فرمان‌ها و رابط ربات

اینکه aipager را چطور از تلگرام می‌گردانید. چهار راه ورودی: فرمان‌های اسلش، دکمه‌های کیبورد، داشبورد Mini App، و پیام‌های آزاد (متن، فایل، ویس).

سورس در GitHub ↖این صفحه ترجمهٔ صفحهٔ انگلیسی است؛ اگر جایی با هم فرق داشتند، صفحهٔ انگلیسی درست است. انگلیسی

ربات فقط ورودی چت‌های تنظیم‌شده را قبول می‌کند؛ برای مرز اعتماد مدل امنیتی را ببینید.

فرمان‌های اسلش#

در aipager/bot/lifecycle.py ثبت می‌شوند. منوی فرمان‌های تلگرام این‌ها را نشان می‌دهد و در شروع aipager و با هر تغییر سشن‌ها آپدیت می‌شود.

فرمانآرگومانچه کار می‌کند
‎/start-صفحهٔ اصلی: سشن‌های این چت، اینکه یک پیام معمولی به کجا ارسال می‌شود (✍️ پیام‌ها به x1 ارسال می‌شوند.)، و 🆕 سشن جدید، ⚙️ تنظیمات و، وقتی این چت سشن بسته‌شده‌ای برای برگرداندن دارد، ↩️ ادامه. کیبورد ثابت را هم نشان می‌دهد.
‎/help-یک راهنمای کوتاه بر اساس کار (شروع، گفتگو، کنترل، مدیریت، تنظیمات، و برای ادمین‌ها ‎/update)، با این نکته که زدن روی یک فرمان آن را فوراً می‌فرستد: برای اضافه کردن متن، روی آن نگه دارید (گوشی) یا Tab بزنید (کامپیوتر). برای مالک این نصب (کسی که در چت خصوصی خود این نصب با ربات است) یک دکمهٔ 🐞 گزارش مشکل هم دارد: پیش‌نمایش دقیق گزارش مشکل را در همان چت خصوصی باز می‌کند، با ارسال، افزودن توضیح و لغو. تا «ارسال» را نزنید چیزی فرستاده نمی‌شود (یک گزارش چه چیزهایی دارد).
‎/app-داشبورد Mini App را باز می‌کند (سشن‌ها، نمایشگر diff، تنظیمات).
‎/status-سشن‌های این چت به‌شکل فهرستی که می‌توانید رویش کار کنید. هر کدام وضعیتش را با کلمه می‌گوید (⚙️ در حال کار ۳:۱۲ · Bash: run tests، ⏳ منتظر شما · Bash: make deploy، 💤 آماده)، با ✍️ روی سشنی که پیام معمولی به آن ارسال می‌شود، و یک خط دوم با مدل، کانتکست، هزینه، آنچه در صف است (صف ۳ (۱ در صف، ۲ یادداشت))، و ایجنت‌ها و دستورهای پس‌زمینهٔ در حال اجرا. هر کدام یک ردیف دکمه دارد: ‎✍️ x1 پیام‌های بعدی‌تان را به آن می‌فرستد، ⏹ توقف وقتی کار می‌کند، جواب بده وقتی منتظر شماست، و ⋮ برای بقیه. پایین: 🆕 جدید، و ⚫ بسته‌شده‌ها (n) برای سشن‌هایی که بسته شده‌اند (ادامه، حذف، یا پاک کردن همه از فهرست؛ در ‎/resume باقی می‌مانند).
‎/stop [label]اختیاریکار فعلی یک سشن را قطع می‌کند. خالی، تنها سشن این چت را که در حال کار است متوقف می‌کند (حتی اگر پیام‌هایتان به سشن دیگری ارسال می‌شوند؛ سشنی که ایجنت یا دستور پس‌زمینه‌اش هنوز اجرا می‌شود در حال کار حساب می‌شود)، وقتی چندتا در حال کارند با یک فهرست انتخاب می‌پرسد کدام، و وقتی هیچ‌کدام کار نمی‌کند می‌گوید الان کاری در جریان نیست.. ‎/stop x1 (یا ‎/x1 stop) x1 را متوقف می‌کند (یا وقتی کار نمی‌کند جواب می‌دهد x1 الان کاری انجام نمی‌دهد.). پیام‌های صف را هم دور می‌ریزد و می‌گوید چندتا دور ریخته شد.
‎/now-پیام‌هایی را که Claude در صف سشن فعال نگه داشته همین حالا می‌فرستد، به جای بعد از قدم فعلی (کلیدهای ارسال فوری خود Claude Code، یعنی Ctrl+X Ctrl+S). هر وقتی کار می‌کند، از جمله وقتی چت ساکت است یا در مود حداقلی است؛ وقتی Claude چیزی نگه نداشته جواب می‌دهد چیزی در صف منتظر نیست. فرستادن فوری یک پیام صف را ببینید.
‎/new [name] [first message]همه اختیارییک سشن شروع می‌کند. ‎/new x1 فوراً شروعش می‌کند، و ‎/new x1 fix the tests «fix the tests» را هم به‌عنوان اولین پیامش می‌فرستد. اگر خالی فرستاده شود (مثلاً از منو)، ‎/new اسم را می‌پرسد و پیام بعدی‌ای که می‌فرستید دقیقاً مثل آرگومان استفاده می‌شود، پس ‎/new و بعد x1 fix the tests همان نتیجه را می‌دهد. در گروه، اسم را در جواب کارت بفرستید (یا ربات را منشن کنید: ‎@aipagerbot x1)، چون پیام معمولی آنجا به ربات نمی‌رسد. فقط همان پیام بعدی: اگر اول کار دیگری بکنید (یک عکس، فرمان دیگر، جواب به پیام دیگر، یک قالب کیبورد، دکمهٔ دیگر)، مثل همیشه با آن رفتار می‌شود و کارت بسته می‌شود؛ ‎/status،‏ ‎/settings و منوهای کیبورد آن را باز نگه می‌دارند. کارتی که می‌پرسد مود، مدل و پوشه‌ای را هم که سشن می‌گیرد نشان می‌دهد، با دکمه‌هایی برای اینکه اول عوضشان کنید. هر راهی به همان کارت «آماده» می‌رسد: اینکه سشن چه گرفت، اینکه پیام بعدی‌تان به آن ارسال می‌شود، و دکمه‌هایی برای رفتن به مود دیگر یا عوض کردن مدل با یک زدن. سشن‌های جدید برای همه در مود خودکار شروع می‌شوند؛ اینکه ‎/new با چه چیزی شروع کند را در ‎/settings ← سشن‌های جدید عوض کنید. یک ! قبل از اسم، سشن را در مود دسترسی کامل شروع می‌کند، برای یک ادمین (نقش‌های owner و admin) یا کسی در چت خصوصی خودش با ربات که نقشش اجازهٔ فرستادن پیام و جواب دادن به Claude را می‌دهد (user، نه read_only)؛ برای هر کس دیگر در مود خودکار شروع می‌شود و کارت دلیلش را می‌گوید. اسمی که در حال استفاده است ↩️ برو سراغش (وقتی آن سشن در حال اجراست) یا ♻️ ادامه (وقتی بسته شده)، 🆕 جایگزینی با سشن جدید و ↩️ لغو را پیشنهاد می‌کند، فقط برای کسی که ‎/new را فرستاده. کارتی که اسم می‌پرسد اگر ۱۰ دقیقه استفاده نشود منقضی می‌شود (⏱ وقت این کارت سشن جدید تمام شد. دوباره /new بفرستید.). عضوی که نقشش can_manage ندارد (user،‏ read_only) فقط داخل پوشهٔ root چت شروع می‌کند: پوشهٔ کارت همان پوشهٔ root است، صفحهٔ «پوشه» آن را و پوشه‌های مستقیم داخلش را فهرست می‌کند (بدون ردیف «پوشهٔ پیش‌فرض»)، «پوشهٔ جدید» داخل همانی که انتخاب شده می‌سازد، و «برو سراغش»، «ادامه» و «جایگزینی» روی سشنی که بیرون از پوشهٔ root کار می‌کند رد می‌شوند («این سشن بیرون از پوشهٔ شما ~/... کار می‌کند، پس نقش شما نمی‌تواند آن را ادامه دهد، ری‌استارت کند یا مودش را عوض کند. از یک ادمین بخواهید.»).
‎/resume [label]اختیاریسشنی را که قبلاً بسته شده با اسمش ادامه می‌دهد، یا یک فهرست انتخاب باز می‌کند. سشن در همان مودی که بود برمی‌گردد. سشنی که در مود دسترسی کامل بود فقط برای یک ادمین یا کسی در چت خصوصی خودش در دسترسی کامل برمی‌گردد؛ برای هر کس دیگر در مود خودکار برمی‌گردد و جواب همین را می‌گوید (♻️ x1 در مود خودکار دوباره باز شد: مود دسترسی کامل فقط برای ادمین است.). سشنی که یک aipager قدیمی‌تر در Auto قدیمی‌اش (که بدون هیچ بررسی‌ای اجرا می‌شد) ذخیره کرده در مود دسترسی کامل برمی‌گردد، و سشنی که در Ask ذخیره شده در مود پرسش. سشن بسته‌شده تا GONE_SESSION_MAX_AGE_DAYS (پیش‌فرض ۱۴) روز فهرست می‌ماند و بعد از فهرست سشن‌ها بیرون می‌رود؛ گفتگوی ذخیره‌شدهٔ Claude آن دست نمی‌خورد. عضوی که نقشش can_manage ندارد نمی‌تواند سشنی را که پوشه‌اش بیرون از پوشهٔ root چت است ادامه دهد (مالک‌ها و ادمین‌ها می‌توانند)؛ همین برای ری‌استارت و هر تعویض مودی، از جمله تعویض بدون ری‌استارت بین پرسش و خودکار، برقرار است.
‎/kill [label]اختیارییک سشن را می‌بندد، همیشه بعد از تأیید: ⏹ سشن x1 بسته شود؟ کار Claude متوقف می‌شود و سشن بسته می‌شود. با [⏹ بستن] [لغو]. خالی، وقتی این چت یک سشن در حال اجرا دارد به تأیید می‌رود، وگرنه فهرست انتخابی از سشن‌های در حال اجرای این چت. در ‎/status ← ⋮ ← ⏹ بستن سشن هم هست.
‎/restart [label]اختیارییک سشن را بعد از تأیید ری‌استارت می‌کند: Claude متوقف می‌شود و دوباره شروع می‌شود و گفتگویش را نگه می‌دارد، در مودی که aipager آخرین بار با آن شروعش کرده یا به آن برده. سشنی که در ترمینال با aipager session شروع شده در مود پرسش برمی‌گردد، مگر اینکه از آن موقع از تلگرام عوض شده باشد (aipager نمی‌داند ترمینال آن را با چه مودی شروع کرده، و هیچ‌وقت یک مود بازتر را حدس نمی‌زند)؛ همین برای ادامه دادنش از تلگرام هم برقرار است.
‎/rename [label] [new]اختیاریبه یک سشن اسم جدید می‌دهد (سشن‌های بسته‌شده هم). ‎/rename x1 newname فوراً اسم را عوض می‌کند. با کلمه‌های کمتر می‌پرسد: وقتی فرمان فقط یک سشن می‌تواند باشد، مستقیم اسم جدید را، وگرنه یک فهرست انتخاب (یک کلمهٔ تنها بعد از ‎/rename سشن را انتخاب نمی‌کند، چون می‌تواند اسم قدیمی یا جدید باشد). در گروه، اسم را در جواب سؤال بفرستید.
‎/delete [label]اختیارییک سشن بسته‌شده را بعد از تأیید از فهرست حذف می‌کند.
‎/diff [label]اختیاریdiff گیت پوشهٔ کاری سشن را نشان می‌دهد. خالی، سشنی را نشان می‌دهد که پیام‌هایتان به آن ارسال می‌شود.
‎/clearqueue-همهٔ پیام‌هایی را که هنوز برای سشن فعال برداشته نشده‌اند دور می‌ریزد (هم پیام‌هایی که aipager نگه داشته و هم پیام‌هایی که از قبل داخل Claude در صف‌اند)، بدون قطع کردن کار در جریان. می‌گوید چندتا پاک شد.
‎/mode [label] [ask|auto|full]اختیاریمود اجازهٔ یک سشن را با یک دکمه برای رفتن به هر مود دیگر نشان می‌دهد: ✍️ x1 در 🤖 مود خودکار است. [💬 تغییر به مود پرسش] [🔓 تغییر به مود دسترسی کامل]. سه مود هست. 💬 مود پرسش: Claude قبل از هر کاری می‌پرسد. 🤖 مود خودکار (پیش‌فرض): بررسی ایمنی خود Claude Code کارهای بی‌خطر را اجرا می‌کند و کارهای پرریسک را نگه می‌دارد تا شما تصمیم بگیرید. 🔓 مود دسترسی کامل: همه‌چیز بدون هیچ بررسی‌ای اجرا می‌شود (‎--dangerously-skip-permissions)؛ فقط یک ادمین، یا کسی در چت خصوصی خودش با ربات که نقشش اجازهٔ فرستادن پیام و جواب دادن به Claude را می‌دهد (user، نه read_only)، می‌تواند انتخابش کند. مود خودکار و دسترسی کامل فقط درخواست‌های اجازهٔ خود Claude Code را عوض می‌کنند: هوک aipager همچنان قانون‌های نقش آن عضو را اعمال می‌کند. ‎/mode ask،‏ ‎/mode auto،‏ ‎/mode full یا ‎/mode x1 ask فوراً عوض می‌کنند؛ خود کلمهٔ مود به زبان چت هم کار می‌کند، بدون کلمهٔ «مود» (/mode x1 خودکار برای 🤖 مود خودکار، /mode x1 کامل برای 🔓 مود دسترسی کامل). وقتی یک سشن در حال اجرا در این چت دقیقاً همان اسم را دارد (مثلاً سشنی به اسم demander)، کلمه اسم سشن است: ‎/mode demander مود آن سشن را نشان می‌دهد، و ‎/mode x1 demander باز هم x1 را عوض می‌کند. ask،‏ auto و full همیشه یعنی مود، به هر ترتیبی (‎/mode x1 ask یا ‎/mode ask x1)؛ فقط وقتی هر دو کلمه کلمهٔ مود باشند و فقط یکی از آن‌ها اسم یک سشن در حال اجرا باشد، همان یکی اسم سشن است، پس با سشنی به اسم full،‏ ‎/mode full ask و ‎/mode ask full هر دو آن را به مود پرسش می‌برند، در حالی که ‎/mode full تنها همچنان مود است. رفتن بین مود پرسش و مود خودکار بدون ری‌استارت و هر وقتی (حتی وقتی Claude کار می‌کند) انجام می‌شود: aipager در سشن Shift+Tab می‌زند، همان‌طور که خودتان می‌زدید، و کارت تا وقتی Claude Code مود جدید را در قدم بعدی‌اش گزارش دهد می‌گوید ⚙️ x1 بدون ری‌استارت به 🤖 مود خودکار تغییر می‌کند.، و بعد نتیجه را نشان می‌دهد. اگر مود خودکار برای سشن در دسترس نباشد (مدل یا اشتراکش)، کارت همین را می‌گوید و سشن در مود پرسش می‌ماند. نه وقتی سشن یک سؤال یا درخواست اجازه نشان می‌دهد: اول جوابش را بدهید. رفتن به دسترسی کامل ادمین (یا کسی در چت خصوصی خودش) و یک تأیید لازم دارد و سشن را ری‌استارت می‌کند (گفتگو می‌ماند)؛ بیرون آمدن از دسترسی کامل هم فوراً ری‌استارتش می‌کند. سشنی که در دسترسی کامل شروع شده برای هر تعویضی ری‌استارت می‌شود، حتی بعد از اینکه در ترمینال به پرسش یا خودکار برده شده، و همین‌طور سشنی که از وقتی شروع شده دسترسی کامل گزارش داده (سشن ترمینالی که با ‎--dangerously-skip-permissions شروع شده): Shift+Tab آنجا ممکن بود آن را با چرخه به دسترسی کامل برگرداند. روی سشنی که در حال کار است، ری‌استارت 🛑 توقف و تغییر مود / ⏳ فعلاً نه را پیشنهاد می‌کند. عضوی که نقشش can_manage ندارد نمی‌تواند مود سشنی را که پوشه‌اش بیرون از پوشهٔ root چت است عوض کند، نه بدون ری‌استارت و نه با آن. زدن یک تعویض خود کارت را عوض می‌کند به جای اینکه پیام دومی بفرستد. ‎/perms اسم قدیمی است و هنوز همین کار را می‌کند.
‎/settings-اینکه سشن‌های این چت چطور دیده شوند و جواب بدهند: زبانی که aipager استفاده می‌کند، شکل پیام‌ها، پیش‌نمایش diff، آپدیت کارت در کار طولانی، قالب‌بندی، طول جواب، سطح زبان؛ اینکه ‎/new یک سشن را با چه چیزی شروع کند؛ تنظیمات هر سشن؛ و، در چت خصوصی مالک، پیشنهاد گزارش مشکل. تنظیمات را ببینید. در گروه همه می‌توانند نگاه کنند، و عوض کردن یک تنظیم ادمین لازم دارد.
‎/language-زبانی که aipager برای پیام‌ها و دکمه‌های خودش در این چت استفاده می‌کند (همان فهرست ردیف اول ‎/settings). هر زبان با اسم خودش آمده: English، بعد Español،‏ Русский (روسی)، Português (Brasil)،‏ 简体中文 (چینی ساده‌شده)، Français،‏ Deutsch (آلمانی)، 한국어 (کره‌ای)، العربية (عربی)، Bahasa Indonesia،‏ Українська (اوکراینی)، Italiano،‏ Türkçe (ترکی)، فارسی و Tiếng Việt (ویتنامی). چت خصوصی‌ای که بعد از این نسخه شروع شود دنبال زبان برنامهٔ تلگرامتان می‌رود؛ چتی که از قبل بوده تا شما انتخاب کنید انگلیسی می‌ماند (زبان‌ها را ببینید). در اسپانیایی، پرتغالی، فرانسوی، ایتالیایی و اندونزیایی کلمه‌های کیبورد پایین همان status،‏ stop،‏ new و kill می‌مانند، مثل فرمان‌هایشان. آلمانی و ترکی از Status،‏ Stop،‏ Neu…‎ و Beenden…‎، و Özet،‏ Stop،‏ Oluştur و Sonlandır استفاده می‌کنند؛ کلمه‌های انگلیسی وقتی تایپ شوند همچنان کار می‌کنند. در فارسی و عربی، متن aipager راست به چپ و با رقم‌های فارسی یا عربی است؛ اسم سشن‌ها، فرمان‌ها، اسم مدل‌ها و کد همان‌طور که هستند می‌مانند. فهرست می‌گوید چه چیزی را عوض می‌کند: فقط متن خود aipager، اینجا و در Mini App؛ سشن‌های Claude شما عوض نمی‌شوند و Claude به همان زبانی جواب می‌دهد که برایش می‌نویسید. در گروه همه می‌توانند نگاه کنند، و عوض کردنش ادمین لازم دارد. language یک اسم رزروشده برای سشن است.
‎/whoami-نشان می‌دهد اینجا چه کسی هستید: در استفادهٔ تیمی برچسبتان، نقشتان در این چت و قانون‌هایی که به شما می‌دهد.
‎/update-فقط برای ادمین (نقش‌های owner و admin، یا نقشی با can_manage). aipager و Claude Code را برای نسخهٔ جدیدتر چک می‌کند و بعد هر کدام را که نسخهٔ جدید دارد با یک دکمه آپدیت می‌کند. آپدیت را ببینید.

منوی / اول سشن‌هایتان را نشان می‌دهد (/x1 · گفتگو با x1)، بعد فرمان‌های پرکاربرد: new،‏ status،‏ stop،‏ now،‏ resume،‏ mode،‏ settings،‏ language،‏ help (و وقتی Mini App روشن است، فقط در چت خصوصی، app). kill،‏ restart،‏ rename،‏ delete،‏ diff،‏ clearqueue،‏ perms،‏ whoami و update در منو نیستند ولی وقتی تایپ شوند کار می‌کنند؛ کارهای مربوط به سشن در ‎/status ← ⋮ هم هستند.

فرمان‌هایی که روی یک سشن کار می‌کنند (‎/stop،‏ ‎/mode،‏ ‎/kill،‏ ‎/restart،‏ ‎/rename،‏ ‎/delete،‏ ‎/diff) از یک قانون پیروی می‌کنند:

  • با اسم (‎/restart x1) روی همان سشن این چت کار می‌کنند (‎/rename برای این کار اسم قدیمی و جدید را لازم دارد، بالا را ببینید).
  • خالی، روی تنها سشنی کار می‌کنند که فرمان می‌تواند معنا داشته باشد (تنها سشن در حال کار برای ‎/stop، تنها سشن در حال اجرا برای ‎/kill و ‎/restart، تنها سشن بسته‌شده برای ‎/delete)، و جایی که تأیید هست، از همان تأیید همیشگی می‌گذرند.
  • وگرنه یک فهرست انتخاب فقط از سشن‌های این چت که فرمان برایشان معنا دارد نشان می‌دهند: اول سشنی که پیام‌هایتان به آن ارسال می‌شود، با علامت ✍️، بعد بقیه به ترتیب اسم، و ✖️ لغو. انتخاب یکی به همان کارتی می‌رسد که تایپ اسمش می‌رسید.
  • در گروه، خالی فقط روی سشن فعلی خودتان کار می‌کنند، وقتی فرمان برای آن معنا داشته باشد؛ وگرنه همیشه فهرست انتخاب را نشان می‌دهند، حتی با یک سشن، چون ممکن است آن یکی مال عضو دیگری باشد (استفادهٔ تیمی را ببینید).

‏‎/mode و ‎/diff اول به سشنی نگاه می‌کنند که پیام‌هایتان به آن ارسال می‌شود.

تنظیمات#

‏‎/settings (و تب تنظیمات Mini App، که همان انتخاب‌ها را نشان می‌دهد) تعیین می‌کند سشن‌های این چت چطور دیده شوند و جواب بدهند. هر چت تنظیمات خودش را دارد؛ در گروه همه می‌توانند نگاه کنند، و عوض کردن یک تنظیم ادمین لازم دارد. در چت خصوصی خودتان، با هر نقشی، خودتان عوضشان می‌کنید، در تلگرام و در Mini App. ردیفی که ✅ دارد روی چیزی غیر از پیش‌فرضش است («شکل پیام‌ها» همیشه انتخابش را نشان می‌دهد).

تنظیمگزینه‌ها (اول پیش‌فرض)چه کار می‌کند
🌐 زبانخودکار (زبان Telegram شما)، در چت خصوصی؛ Englishزبان پیام‌ها و دکمه‌های خود aipager در این چت و در Mini App، با اسم خودش (همان فهرست ‎/language). سشن‌های Claude شما را عوض نمی‌کند: Claude به همان زبانی جواب می‌دهد که برایش می‌نویسید. English،‏ Español،‏ Русский (روسی)، Português (Brasil)،‏ 简体中文 (چینی ساده‌شده)، Français،‏ Deutsch (آلمانی)، 한국어 (کره‌ای)، العربية (عربی)، Bahasa Indonesia،‏ Українська (اوکراینی)، Italiano،‏ Türkçe (ترکی)، فارسی و Tiếng Việt (ویتنامی) پیشنهاد می‌شوند؛ «خودکار» دنبال زبان برنامهٔ تلگرامتان می‌رود (زبان‌ها را ببینید).
🖼 شکل پیام‌هاکارت + جواب جدا؛ جواب داخل همان کارت؛ فقط جواب، جای کارتاینکه کار تمام‌شده چطور دیده شود. «کارت + جواب جدا» کارت را بالای جواب، به‌عنوان سابقهٔ اینکه جواب چطور به دست آمد، نگه می‌دارد؛ «جواب داخل همان کارت» جواب را در کارت می‌گذارد؛ «فقط جواب، جای کارت» کارت را برمی‌دارد و جواب را تنها می‌گذارد. پیش‌فرض «کارت + جواب جدا» است (KEEP_FINISHED_CARD=0 آن را برای چت‌هایی که هیچ‌وقت انتخاب نکرده‌اند «فقط جواب، جای کارت» می‌کند). جواب‌ها را ببینید.
📝 پیش‌نمایش diffخاموش؛ روشنروشن، هر Write/Edit را به‌شکل یک پیام diff جداگانه زیر کارت در حال کار می‌فرستد. خاموش یعنی یک کارت و یک جواب؛ کارت همچنان همهٔ ویرایش‌ها را فهرست می‌کند و Mini App یک نمایشگر diff دارد.
⏱ آپدیت کارت در کار طولانیروشن؛ خاموشروشن، کارت در حال کار بعد از ۲ دقیقه هر ۱۰ ثانیه و بعد از ۱۰ دقیقه هر ۳۰ ثانیه آپدیت می‌شود (هر قدر کار طول بکشد، هیچ‌وقت کندتر)، و ساعتش از آن به بعد ۳۰ ثانیه ۳۰ ثانیه جلو می‌رود؛ خاموش، سرعت دقیقه‌های اول را در کل کار نگه می‌دارد (رفع مشکل را ببینید).
✏️ قالب‌بندی سادهخاموش؛ روشنروشن، از Claude فقط متن ساده و فهرست‌های خط‌تیره‌ای می‌خواهد: بدون جدول، بلوک کد، تیتر یا متن پررنگ.
📏 طول جواببدون قاعده؛ خیلی کوتاه؛ کوتاه؛ متوسط؛ بلنداز Claude جواب‌هایی با این طول می‌خواهد.
🎓 سطح زبانبدون قاعده؛ کلمه‌های ساده؛ معمولی؛ پیشرفتهاز Claude این سطح کلمه‌ها را می‌خواهد.
🎨 ظاهردکمهٔ توقف، دکمه‌های اجازه و رد، دکمهٔ App، منوی تنظیماتدکمه‌های aipager در این چت چه شکلی باشند؛ همه‌چیز از «معمولی» شروع می‌شود (ظاهر خود تلگرام). تلگرام به ربات فقط اجازه می‌دهد دکمه را آبی، سبز یا قرمز کند، پس: دکمهٔ توقف (هم روی کارت در حال کار، هم زیر یک سؤال یا درخواست اجازه) معمولی، آبی، سبز یا قرمز؛ اجازه و رد معمولی یا رنگی (اجازه و همیشه اجازه سبز، رد قرمز)؛ دکمهٔ App (روی پیام سنجاق‌شده و زیر ‎/app) معمولی، آبی، سبز یا قرمز (دکمهٔ منوی کنار جای نوشتن پیام را نمی‌شود رنگی کرد)؛ منوی تنظیمات معمولی (✅ گزینهٔ فعلی را نشان می‌دهد) یا گزینهٔ فعلی آبی هم بشود. برای کل چت است، نه برای هر سشن؛ در گروه فقط ادمین می‌تواند عوضش کند. اپ‌های تلگرام که رنگ دکمه را پشتیبانی نمی‌کنند همهٔ دکمه‌ها را معمولی نشان می‌دهند. تب تنظیمات در Mini App همین گزینه‌ها را در بخش جداگانهٔ خودش، ظاهر، بعد از تنظیمات چت دارد، هر کدام با یک نقطهٔ رنگی.
🆕 سشن‌های جدیدمجوزها (مود)، مدل، پوشهاینکه ‎/new وقتی شما انتخاب نمی‌کنید یک سشن را با چه چیزی شروع کند: مود پرسش، مود خودکار (پیش‌فرض) یا مود دسترسی کامل، یک مدل از فهرست مدل‌ها یا پیش‌فرض Claude Code، و یک پوشه. فقط یک ادمین، یا کسی در چت خصوصی خودش با ربات، می‌تواند اینجا دسترسی کامل را انتخاب کند (صفحهٔ یک چت خصوصی آن را به هیچ‌کس دیگری نشان نمی‌دهد)، و هیچ‌وقت روی کسی که نمی‌تواند از آن استفاده کند اعمال نمی‌شود: سشن‌های او در مود خودکار شروع می‌شوند.
👤 تنظیمات هر سشنیک سشن، بعد هر تنظیم بالا جز سشن‌های جدیدتنظیمات مخصوص یک سشن (در ‎/status ← ⋮ ← 👤 تنظیمات سشن هم هست)؛ ⭐ تنظیمی را که آن سشن عوض کرده نشان می‌دهد، و «↩️ همان پیش‌فرض چت» این تغییر را برمی‌دارد. صفحهٔ سشن در Mini App همین تنظیمات را دارد.
🐞 گزارش مشکلاز من بپرس؛ خاموشفقط در چت خصوصی مالک نصب. «از من بپرس» اجازه می‌دهد aipager گاهی پیشنهاد کند گزارشی از یک خطای داخلی که بیش از یک بار به آن خورده بفرستد (حداکثر هر ۳ روز یک بار)؛ «خاموش» هیچ‌وقت پیشنهاد نمی‌دهد (دکمهٔ «گزارش مشکل» در ‎/help همچنان کار می‌کند). دو پیشنهاد ردشده پشت هم پیشنهادها را خاموش می‌کنند، و بعد این ردیف همین را می‌گوید، با یک دکمه برای روشن کردن دوباره. گزارش مشکل را ببینید.

طول جواب، سطح زبان و قالب‌بندی ساده به‌شکل یک دستور کوتاه که به هر پیامی که از تلگرام فرستاده می‌شود اضافه می‌شود به Claude می‌رسند (توسط هوک؛ هوک‌ها را ببینید)، و جایی که سشن تنظیمات خودش را دارد، از همان‌ها استفاده می‌شود.

شکل پیام‌ها هر چه باشد، هر کارت در حال کار با خط وضعیت سشنش تمام می‌شود (⏳/‎✅ name · …‎) و هر جواب با خط نتیجه‌اش شروع می‌شود (‎💬 name، به‌علاوهٔ · تمام شد (…) وقتی کارت تمام‌شده‌ای برای نشان دادن آمار نمانده)؛ شکل «جواب داخل همان کارت» این دو را روی هم می‌گذارد، هر خط در بخش خودش. بالای خط وضعیت کارت در حال کار یک خط جداکننده هست (با نوشتهٔ ریز)، و در شکل «جواب داخل همان کارت» خط دومی کارت تمام‌شده را از جواب جدا می‌کند. در شکل «کارت + جواب جدا»، جواب عمداً یک لحظه بعد از کارت تمام‌شده می‌آید، تا دیده شود کارت «تمام شد» گفته و بعد جواب زیرش برسد؛ این فاصله را با FINISH_CARD_GRACE_SECONDS (به ثانیه، پیش‌فرض ۰٫۸؛ 0 هر دو را با هم می‌فرستد) تنظیم یا خاموش کنید. در شکل «کارت + جواب جدا»، کاری که هیچ ابزاری اجرا نکرد کارتی باقی نمی‌گذارد: کارت قبل از اینکه «تمام شد» بگوید برداشته می‌شود و خط اول جواب آمار را نشان می‌دهد، مثل شکل «فقط جواب، جای کارت».

فرمان‌های مخصوص هر سشن#

برای هر سشن در حال اجرا یک فرمان، که از برچسبش ساخته می‌شود:

شکلچه کار می‌کند
‎/<label>‎‎<label>‎ را سشنی می‌کند که پیام‌هایتان به آن ارسال می‌شود. جواب همین را با وضعیت و مودش می‌گوید (✍️ حالا با x1 حرف می‌زنید · 💤 آماده · 🤖 مود خودکار، بعد «پیامی بفرستید؛ به x1 ارسال می‌شود.»)، وقتی منتظر شماست جواب بده را پیشنهاد می‌کند، و ⋮ بیشتر را برای منویش. آمار کامل در ‎/status است. در گروه به جایش می‌گوید «به پیامی از x1 جواب بدهید (یا ‎@aipagerbot را صدا بزنید) تا با آن حرف بزنید.»، چون پیام معمولی آنجا به ربات نمی‌رسد (استفادهٔ تیمی را ببینید). ‎/x1@aipagerbot، که تلگرام وقتی ‎/x1 را از منوی یک گروه انتخاب می‌کنید می‌فرستد، همین کار را می‌کند.
‎/<label> <prompt>‎‎<prompt>‎ را مستقیم به همان سشن می‌فرستد. همان سشن، سشنی هم می‌شود که پیام‌های معمولی بعدی‌تان به آن ارسال می‌شوند.
‎/<label> stopکار فعلی همان سشن را قطع می‌کند.

نتیجهٔ ‎/status از همان داده‌ای می‌آید که aipager status در خط فرمان نشان می‌دهد؛ برای خود فهرست سشن‌ها رفت‌وبرگشتی با تلگرام لازم نیست.

روی کامپیوتر، aipager status و aipager session ls به هر سشن یک وضعیت می‌دهند: IDLE،‏ BUSY،‏ WAITING (یک اجازه یا سؤال منتظر شماست، و وقتی معلوم باشد چه چیزی، مثلاً permission: Bash: make deploy) یا GONE. با ‎--json، هر سشن waiting_kind (permission یا question) و waiting_summary را هم دارد که هر دو null هستند مگر اینکه منتظر باشد.

زبان‌ها#

‏aipager به English،‏ Español،‏ Русский،‏ Português (Brasil)،‏ 简体中文،‏ Français،‏ Deutsch،‏ 한국어، العربية، Bahasa Indonesia،‏ Українська،‏ Italiano،‏ Türkçe، فارسی و Tiếng Việt حرف می‌زند، هر کدام با اسم خودش در فهرست.

  • فقط متن خود aipager عوض می‌شود. زبان برای پیام‌ها، دکمه‌ها، کارت‌ها و Mini App خود aipager است. سشن‌های Claude شما عوض نمی‌شوند و Claude به همان زبانی جواب می‌دهد که برایش می‌نویسید. اسم سشن‌ها، فرمان‌ها، اسم مدل‌ها و کد همان‌طور که هستند می‌مانند.
  • ‏‎/language (یا ردیف اول ‎/settings) زبان چتی را که در آن هستید انتخاب می‌کند. در چت خصوصی، زبان خود شما هم هست: پیام‌های کوچکی که در یک گروه می‌بینید و Mini App شما از آن استفاده می‌کنند.
  • خودکار (فقط چت‌های خصوصی) دنبال زبان برنامهٔ تلگرامتان می‌رود، و اگر عوضش کنید دوباره دنبالش می‌رود. زبانی که aipager ندارد انگلیسی خوانده می‌شود.
  • چت‌های جدید و قدیمی. چت خصوصی‌ای که بعد از این نسخه شروع شود، تا وقتی زبانی انتخاب کنید دنبال زبان برنامهٔ تلگرامتان می‌رود، و اولین پیامش به زبانی غیر از انگلیسی یک خط کوتاه دارد که همین را و راه عوض کردنش را می‌گوید. چتی که از قبل بوده انگلیسی می‌ماند. اگر برنامهٔ تلگرامتان به زبانی است که aipager بلد است، یک کارت می‌گیرید که آن را پیشنهاد می‌کند، با یک دکمهٔ انگلیسی بماند؛ هر جوابی بدهید، فقط یک بار می‌آید.
  • گروه‌ها یک زبان دارند که یک ادمین در ‎/language تنظیمش می‌کند؛ تا آن موقع انگلیسی‌اند. پیام کوچک بعد از زدن یک دکمه به زبان خود کسی است که آن را زده: انتخابش در چت خصوصی‌اش با ربات، وگرنه برای کسی که بعد از این نسخه اضافه شده زبان برنامهٔ تلگرامش، وگرنه زبان گروه. استفادهٔ تیمی را ببینید.
  • راست به چپ. در فارسی و عربی، متن aipager راست به چپ و با رقم‌های فارسی یا عربی است. کارت در حال کار از زبان چت پیروی می‌کند، Claude به هر زبانی که بنویسد: در چت انگلیسی چپ به راست است، در چت فارسی یا عربی راست به چپ، و جمله‌ای از Claude روی آن که در جهت دیگر نوشته شده باز هم در جهت خودش خوانده می‌شود. جواب از متن Claude پیروی می‌کند: وقتی Claude در چتی که زبانش چپ به راست نوشته می‌شود به فارسی یا عربی جواب می‌دهد، کل جواب یک پیام راست به چپ است و خط‌های خود aipager در آن (ایجنت‌های زیر جواب، و در «جواب داخل همان کارت» کارت تمام‌شدهٔ بالای آن) مثل بقیه سمت راست می‌نشینند و باز هم چپ به راست خوانده می‌شوند.
  • کلمه‌های مود. ‎/mode کلمهٔ مود را به زبان شما می‌گیرد (‎/mode demander)، و ask،‏ auto و full همیشه کار می‌کنند. اگر یک سشن در حال اجرا دقیقاً همان اسم را داشته باشد، کلمه به جایش اسم سشن است (‎/mode را بالا ببینید).
  • توضیح ربات. در شروع، aipager توضیح ربات (متنی که در صفحهٔ خالی چتش دیده می‌شود) و توضیح کوتاهش را به هر کدام از این زبان‌ها، برای کسانی که تلگرامشان به آن زبان است، می‌نویسد. تلگرام چنین متنی را به جای متنی که شما در BotFather نوشته‌اید نشان می‌دهد، پس aipager تا وقتی متن خودتان را دارید هیچ متنی نمی‌گذارد (توضیح و توضیح کوتاه جداگانه چک می‌شوند). هیچ‌وقت متنی از شما را بازنویسی نمی‌کند و هیچ‌وقت متن انگلیسی یا پیش‌فرض را عوض نمی‌کند. وقتی متن فعلی‌اش برای همهٔ زبان‌ها از قبل تنظیم شده، شروع aipager هیچ سؤالی از تلگرام نمی‌کند. وگرنه اول متن BotFather شما را می‌خواند (یک بار برای توضیح و یک بار برای توضیح کوتاه): اگر متنی دارید همان‌جا می‌ایستد، پس با متن خودتان هر شروع فقط همان خواندن‌ها را هزینه دارد. اگر متنی ندارید، هر زبانی را که هنوز متن فعلی‌اش را ندارد می‌خواند، پس زبانی که در آن متن خودتان را نوشته‌اید در هر شروع دوباره خوانده می‌شود. اگر بعد از اینکه aipager متن خودش را گذاشت در BotFather توضیحی بنویسید، خواننده‌های این زبان‌ها همان متن aipager را می‌بینند (رفع مشکل را ببینید).

Mini App#

‏‎/app (و دکمهٔ منوی تلگرام) داشبوردی را باز می‌کند که خود aipager سرو می‌کند. به‌طور پیش‌فرض روشن است؛ با aipager miniapp enable|disable|status مدیریتش کنید. هر درخواست با امضای initData تلگرام چک می‌شود (مدل امنیتی ← تونل Mini App را ببینید). صفحه هیچ چیزی از جای دیگری لود نمی‌کند: نه فونت، نه عکس، نه اسکریپت از سایت‌های دیگر.

  • چت‌ها. اپ هر بار یک چت را نشان می‌دهد. اگر در بیش از یک چت عضو باشید (مثلاً چت خصوصی‌تان و یک گروه)، ردیفی از اسم چت‌ها در بالا بینشان جابه‌جا می‌شود؛ اپ روی چت خصوصی خودتان باز می‌شود و آخرین انتخابتان را روی همان گوشی به خاطر می‌سپارد. هر چه زیر آن است برای چت انتخاب‌شده است، با نقش شما در آن. با یک چت، آن ردیف نشان داده نمی‌شود. استفادهٔ تیمی را ببینید.
  • سشن‌ها. یک جمله کل چت را خلاصه می‌کند، مثلاً «۱ منتظر شما، ۲ در حال کار، ۳ آماده»، و زیرش آنچه خرج شده. هر سشن در حال اجرا یک کاشی است با یک حلقهٔ کانتکست، پوشه، مدل و هزینه‌اش؛ آن‌هایی که کار می‌کنند با رنگ اصلی می‌درخشند. سشن‌های تمام‌شده در یک قفسهٔ جمع‌شوندهٔ بسته‌شده می‌مانند. دکمهٔ + یک سشن جدید شروع می‌کند.
  • منتظر شما. سشنی که منتظر یک درخواست اجازه یا یک سؤال است در یک سینی کهربایی بالای صفحه می‌نشیند و نشان می‌دهد چه می‌پرسد. جواب در چت همان درخواست را با دکمه‌هایش دوباره ته چت می‌فرستد، مثل دکمهٔ جواب دادن نوار سنجاق‌شده، و شما همان‌جا جوابش را می‌دهید. اگر تنها سشن منتظر بود، اپ بسته می‌شود تا درخواست درست جلوی چشمتان باشد؛ وگرنه باز می‌ماند و می‌گوید «به چت فرستاده شد. همان‌جا جواب بدهید.». اجازهٔ پیام دادن به آن سشن را لازم دارد، و کپی‌ای که بعد از جواب داده شدن یا عوض شدن درخواست زده شود می‌گوید «قبلاً جواب داده شده».
  • صفحهٔ یک سشن. بالای صفحه حلقهٔ کانتکست، وضعیت («در حال کار، ۳:۱۲»، «منتظر شما (اجازه)»، «آماده، آخرین فعالیت ۵ دقیقه پیش»، «بسته‌شده») و یک توقف (وقتی در حال کار یا منتظر است) یا ادامه (وقتی بسته شده) با یک زدن را نشان می‌دهد. زیر آن: درخواست منتظر با جواب در چت، چند اجرای ابزار آخر به‌شکل یک نوار (برای خط زمانی کامل رویش بزنید)، آخرین جواب، اطلاعات، کنترل مدل، تنظیمات خود سشن، و فایل‌های تغییرکرده و خط زمانی. منوی ⋮ همهٔ کارها را دارد، با همان تأییدهای قبلی.
  • سشن جدید. یک کارت قدم‌به‌قدم: اسم، بعد کجا (با تکه‌های اخیر برای پوشه‌هایی که سشن‌هایتان استفاده می‌کنند، جدیدترین اول)، بعد مدل (با تکه‌های پیشنهادی)، بعد گزینه‌های بیشتر برای مود اجازه و سبک جواب. دکمهٔ خود تلگرام پایین صفحه شروع سشن است. برای عضوی که نقشش can_manage ندارد، «کجا» فقط پوشهٔ root چت و پوشه‌های مستقیم داخلش را پیشنهاد می‌کند (پوشهٔ root پیش‌فرض است، و «پوشهٔ جدید» داخل همانی که انتخاب شده می‌سازد)؛ پوشه‌ای بیرون از آن با دلیلش رد می‌شود، و ادامه، ری‌استارت و تعویض مود سشنی که بیرون از آن کار می‌کند جواب می‌دهند «این سشن بیرون از پوشهٔ شما ~/... کار می‌کند، پس نقش شما نمی‌تواند آن را ادامه دهد، ری‌استارت کند یا مودش را عوض کند. از یک ادمین بخواهید.»
  • تنظیمات. اول زبان برنامه: زبان خود شما برای متن aipager در اپ و در چت خصوصی‌تان (انگلیسی، اسپانیایی، روسی، پرتغالی (برزیل)، چینی (ساده‌شده)، فرانسوی، آلمانی، کره‌ای، عربی، اندونزیایی، اوکراینی، ایتالیایی، ترکی، فارسی یا ویتنامی؛ «خودکار» دنبال زبان برنامهٔ تلگرامتان می‌رود، زبان‌ها را ببینید). هر کسی می‌تواند مال خودش را عوض کند، هیچ‌وقت در یک چت نوشته نمی‌شود، و سشن‌های Claude شما را عوض نمی‌کند. بعد تنظیمات چت (در گروه فقط ادمین می‌تواند عوضشان کند؛ در چت خصوصی خودتان، با هر نقشی، خودتان می‌توانید، مثل ‎/settings در همان‌جا) و، برای ادمین، آپدیت، که همان ‎/update است. برای مالک در چت خصوصی‌اش، گزارش مشکل صفحهٔ خودش را باز می‌کند: یک توضیح بنویسید، گزارش را نگاه کنید، بفرستیدش و کد پیگیری‌اش را ببینید، بدون اینکه از اپ بیرون بروید (گزارش مشکل را ببینید).

اپ وقتی تم روشن یا تیرهٔ تلگرام را عوض می‌کنید همراهش عوض می‌شود، و وقتی گوشی‌تان حرکت کمتر می‌خواهد انیمیشن‌های آرامش را متوقف می‌کند. هر چیزی در Mini App از چت هم در دسترس است: منوی ⋮ در داشبورد یک سشن همان کارها را دارد.

عوض کردن مدل یک سشن در حال اجرا#

صفحهٔ یک سشن در حال اجرا یک کنترل مدل دارد که مدلی را که سشن گزارش می‌دهد (از خط وضعیت Claude Code) نشان می‌دهد، و همان فهرستی را که انتخاب‌گر شروع سشن و کیبورد مدل‌های چت پیشنهاد می‌کنند. انتخاب یکی دقیقاً ‎/model <name>‎ را در آن سشن تایپ می‌کند، همان تایپی که کیبورد مدل‌های چت انجام می‌دهد، با همان قانون دربارهٔ اینکه چه کسی می‌تواند (هر کسی که می‌تواند به آن سشن پیام بدهد). کنترل تا وقتی خط وضعیت مدل دیگری گزارش دهد در حال تغییر… را نشان می‌دهد و بعد آن را؛ اگر تا ۱۵ ثانیه چیزی عوض نشود، تأیید نشد (سشن را چک کنید) را نشان می‌دهد.

  • فقط وقتی سشن آماده است، نه وقتی Claude کار می‌کند یا یک درخواست باز است. Claude Code /model را همان لحظه اجرا می‌کند، حتی وسط کار، نه بعد از آن، پس تعویض تا تمام شدن کار رد می‌شود. کیبورد چت هم در همین وضعیت‌ها، با همین کلمه‌ها، رد می‌کند.
  • سؤال «Switch model?» در Claude Code.‏ Claude Code معمولاً قبل از تعویض این را می‌پرسد، چون جواب بعدی باید کل گفتگو را دوباره بخواند. با Claude Code نسخهٔ 2.1.251 یا بعدتر، هوک PreModelSwitch aipager تعویضی را که خود aipager همین الان تایپ کرده تأیید می‌کند، پس این سؤال پرسیده نمی‌شود (هوک‌ها را ببینید). هر تعویض دیگری همچنان می‌پرسد. با یک Claude Code قدیمی‌تر، یا در تعویض به opusplan یا از آن، سؤال باز هم ممکن است بیاید. آن‌وقت تعویض به‌شکل تأیید نشد نشان داده می‌شود و سؤال در ترمینال منتظر می‌ماند. قبل از اینکه هر چیز دیگری به آن سشن بفرستید همان‌جا جوابش را بدهید، وگرنه پیام بعدی‌تان در آن تایپ می‌شد. به همین دلیل، aipager بعد از یک تعویض تأییدنشده تا یک دقیقه، یا تا وقتی سشن مدل جدیدی گزارش دهد، تعویض دیگری از آن سشن را رد می‌کند.

نوار وضعیت سنجاق‌شده#

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

خط اولکی
⏳ jim منتظر شماست - Bash: make deployیک سشن منتظر یک درخواست اجازه، یک سؤال یا یک درخواست تعاملی است؛ وقتی بقیه هم منتظرند (+۲ مورد دیگر)
⚙️ jim (در حال کار) / 💤 jim (آماده)چت یک سشن در حال اجرا دارد و آن سشن در حال کار / آماده است (🔄 jim (در حال شروع) وقتی دارد شروع می‌شود): این خط، جز یک خط محدودیت تلگرام، کل نوار است
⚙️ ۲ در حال کار · ۱ آمادهچند سشن، هیچ‌کدام منتظر نیست: چندتا در هر وضعیت‌اند (در حال کار، آماده، در حال شروع)؛ 🔄 وقتی هیچ‌کدام کار نمی‌کند و یکی در حال شروع است، 💤 وقتی همه آماده‌اند
💤 همه آمادههیچ سشنی در حال اجرا نیست

زیرش، فقط وقتی برقرار است، یک خط محدودیت (🐢 بعد از هشدار Telegram، کندتر ارسال می‌کند (شش ساعت بعد از یک 429) یا ⏸ کارت‌ها فعلاً آپدیت نمی‌شوند (سقف ساعتی Telegram) / (محدودیت Telegram) (مود حداقلی، رفع مشکل را ببینید))، و بعد، وقتی چت بیش از یک سشن در حال اجرا دارد، ✍️ پیام‌ها به jim ارسال می‌شوند (سشنی که یک پیام معمولی در این چت به آن ارسال می‌شود، پایین را ببینید؛ نه در گروه، جایی که هر کس مال خودش را دارد) و یک خط برای هر سشن با وضعیتش: در حال کار، منتظر شما، آماده یا در حال شروع. نوار اسم هر سشن را یک بار می‌آورد: سشن منتظری که خط اول نامش را آورده خط جداگانه‌ای نمی‌گیرد، و خط اول هیچ‌وقت اسم‌هایی را که خط‌های پایین تکرار می‌کنند فهرست نمی‌کند. سشنی که ایجنت‌هایش هنوز در پس‌زمینه کار می‌کنند، روی خط خودش (یا با یک سشن، روی همان یک خط) می‌گوید چندتا: 💤 jim (آماده، ۱ ایجنت در حال کار). دستورهایی که Claude در پس‌زمینه اجرا می‌کند هم همین‌طور شمرده می‌شوند: (آماده، ۱ دستور پس‌زمینه در حال اجرا)، یا با هر دو (آماده، ۲ ایجنت و ۱ دستور پس‌زمینه در حال اجرا). این فقط یک شمارش است، هیچ‌وقت اسمشان، پس نوار فقط وقتی شمارش عوض شود تکان می‌خورد. روی نوار بزنید تا به خود پیام بروید.

یک پیام معمولی به کجا ارسال می‌شود. پیامی که جواب نیست به سشنی ارسال می‌شود که این چت آخرین بار با آن حرف زده: همانی که آخرین بار با ‎/<label>‎ به آن رفتید، به آن پیام دادید، شروعش کردید، یا آخرین بار اینجا جوابتان را داد. یک ‎/mode،‏ ‎/clearqueue،‏ ‎/diff یا ‎/now خالی روی همان سشن کار می‌کند (‎/stop هر سشنی را که در حال کار است متوقف می‌کند). هر چت مال خودش را دارد: پیامی در یک چت هیچ‌وقت به سشنی که مال چت دیگری است ارسال نمی‌شود. در گروه فقط یک جواب به ربات، پیامی که ربات را منشن می‌کند، یک فرمان یا زدن کیبورد گروه حساب می‌شود (استفادهٔ تیمی را ببینید)، و هر کس مقصد خودش را دارد که جواب یک سشن آن را جابه‌جا نمی‌کند (استفادهٔ تیمی را ببینید).

دکمه‌های پیام سنجاق‌شده:

  • جواب دادن به ‎<label>‎ (یکی برای هر سشن منتظر، حداکثر سه تا) درخواست آن سشن را با دکمه‌های جوابش دوباره ته چت می‌فرستد، تا بدون بالا رفتن جوابش را بدهید. اگر در این فاصله جواب داده شده باشد، به جایش یک پیام کوچک «قبلاً جواب داده شده» می‌گیرید، و کپی‌ای (یا درخواست اصلی) که بعد از جواب داده شدن درخواستش در جای دیگر زده شود همین‌طور رد می‌شود؛ هیچ‌وقت به یک درخواست بعدی جواب نمی‌دهد. بعد از ری‌استارت aipager، درخواستی که منتظر بود از کارت در حال کار یا از پیام خودش همچنان کار می‌کند، ولی aipager دیگر نمی‌داند یک کپی قدیمی‌تر کدام درخواست را نشان می‌داد، پس زدن کپی‌ای که نوار قبل از ری‌استارت فرستاده با «این درخواست دیگر باز نیست» رد می‌شود. هر کسی که می‌تواند به آن درخواست جواب بدهد می‌تواند از آن استفاده کند؛ هیچ‌کس دیگر.
  • ‏📱 App در چت خصوصی شما، تا وقتی Mini App روشن است، Mini App را باز می‌کند.

نوار هیچ ساعت، هزینه، درصد کانتکست یا مدلی ندارد، پس فقط وقتی وضعیت یک سشن عوض شود تغییر می‌کند. aipager آن را (بی‌صدا، بدون اعلان) فقط وقتی چیزی که نشان می‌دهد عوض شده ویرایش می‌کند، حداکثر هر ۳۰ ثانیه یک بار برای هر چت (PINNED_MIN_EDIT_GAP)؛ تغییری که داخل این فاصله بیفتد وقتی فاصله تمام شد نشان داده می‌شود، هیچ‌وقت گم نمی‌شود. وقتی چت به خاطر بن تلگرام ساکت است هیچ‌وقت ویرایش نمی‌شود، و وقتی سکوت تمام شد عقب‌ماندگی را جبران می‌کند.

در گروه، ربات برای سنجاق کردن به دسترسی ادمین نیاز دارد. اگر سنجاق کردن رد شود، aipager پیام وضعیتی را که همین الان فرستاده پاک می‌کند (تا هیچ‌وقت سنجاق‌نشده در تاریخچهٔ گروه نماند) و تا ری‌استارت aipager در آن گروه هیچ نواری نشان نمی‌دهد؛ همین برای چتی که کلاً ربات را رد کرده (بیرون کرده، بلاک کرده) برقرار است. اگر پیام سنجاق‌شده را پاک کنید، aipager یک پیام جدید می‌فرستد و سنجاقش می‌کند، حداکثر ساعتی یک بار برای هر چت.

کیبورد ثابت#

یک کیبورد ثابت زیر جای نوشتن چت می‌نشیند. ردیف‌ها، از بالا به پایین:

ردیفدکمه‌هانکته
سشن‌هایک دکمه برای هر برچسب سشن در حال اجراخودکار از فهرست سشن‌ها ساخته می‌شود
کارهاوضعیت، توقف، جدیدمیان‌برهای متنی ساده (بستن وقتی تایپ شود هنوز کار می‌کند؛ بستن یک سشن در ‎/status ← ⋮ است)
رفتنقالب‌ها، فرمان‌هاMini App از دکمهٔ منو کنار جای تایپ یا با ‎/app باز می‌شود، نه از این کیبورد

مدل › داخل زیرمنوی «فرمان‌ها» است. زدن یک گزینهٔ زیرمنو یک پیام آماده یا فرمان اسلش می‌فرستد:

  • قالب‌ها: پیام‌هایی که مدام خودتان تایپشان می‌کنید، مثلاً «نوشتن تست»، «توضیح نقشهٔ کار»، «آپدیت حافظه».
  • فرمان‌ها: فرمان‌های اسلشی که خود Claude Code می‌فهمد (‎/compact،‏ ‎/clear و غیره)، که فوراً تایپ می‌شوند. یک فرمان یا قالب اسم سشنی را که به آن رفته می‌آورد (🧹 /clear برای x1 ارسال شد). پاک کردن گفتگو وقتی سشن کار می‌کند رد می‌شود (⚠️ وقتی سشن در حال کار است نمی‌شود گفتگو را پاک کرد).
  • مدل‌ها: تعویض سریع مدل برای سشن فعال. اسم‌های کوتاه خانواده‌ها (sonnet،‏ opus،‏ haiku،‏ fable،‏ opusplan) که همیشه یعنی جدیدترین مدل آن خانواده، و مدل‌های ثابت (claude-opus-5-5،‏ claude-opus-5-5[1m] با پنجرهٔ کانتکست ۱ میلیونی، claude-sonnet-5-5،‏ claude-fable-5-1،‏ claude-haiku-5-5) هستند. انتخاب‌گرهای شروع و سشن در Mini App همین فهرست را دارند. تعویض وقتی سشن کار می‌کند یا یک درخواست باز است رد می‌شود. بعد جواب 🔄 عوض می‌شود تا مدلی را که سشن گزارش می‌دهد نشان دهد، یا می‌گوید تعویض تأیید نشد (عوض کردن مدل یک سشن در حال اجرا را ببینید).

برای عوض کردن چیدمان پیش‌فرض، ‎~/.config/aipager/keyboard.json را بنویسید:

json
{
  "templates": [{"label": "Deploy",  "prompt": "Deploy to staging"}],
  "commands":  [{"label": "Compact", "send": "/compact"}],
  "models":    [{"label": "Sonnet",  "send": "/model sonnet"}]
}

هر بخش مستقل است؛ بخش‌هایی که نیستند از پیش‌فرض‌های داخلی می‌آیند، پس می‌توانید یکی را بدون تعیین بقیه عوض کنید. JSON خراب نادیده گرفته می‌شود و یک هشدار در لاگ می‌آید. تغییرات به ری‌استارت aipager نیاز دارند.

دکمه‌های زیر هر پیام#

بیشتر جواب‌های ربات دکمه‌های مخصوص همان موقعیت را دارند:

درخواست‌های اجازه#

وقتی Claude می‌خواهد ابزاری را اجرا کند که تأیید لازم دارد، کارت در حال کار به یک درخواست اجازه تبدیل می‌شود:

text
🔐 Bash: List the temp directory
ls -la /tmp

  [✅ اجازه بده]  [❌ رد کن]
  [🟢 همیشه اجازه بده]  [⏹ توقف]

کارت دستور (یا مسیر فایل) واقعی‌ای را که Claude می‌خواهد اجرا کند، زیر توضیح خود Claude دربارهٔ آن، نشان می‌دهد: چیزی را تأیید کنید که می‌توانید بخوانید. نویسه‌ای که ترتیب کشیده شدن متن را عوض می‌کند (یک کنترل جهت یونیکد مثل U+202E، که می‌تواند یک دستور را شبیه دستور دیگری نشان دهد) به‌شکل علامتی مثل ‎⟨U+202E⟩‎ نشان داده می‌شود، و کارت بعد اضافه می‌کند: ⚠️ این متن حرف‌های پنهانی دارد که جهت نوشتن را عوض می‌کنند (به شکل ⟨U+...⟩ نشان داده شده‌اند). ممکن است چیزی غیر از آنچه می‌بینید اجرا شود.

  • اجازه بده: همین یک اجرا را تأیید می‌کند.
  • رد کن: ردش می‌کند؛ Claude آن اجرای ابزار را انجام نمی‌دهد.
  • همیشه اجازه بده: تأیید می‌کند و قانون همیشگی‌ای را که Claude پیشنهاد می‌کند اضافه می‌کند («دیگر برای … نپرس»). این دکمه فقط وقتی Claude چنین قانونی پیشنهاد کند دیده می‌شود؛ برای دستوری که نمی‌تواند برایش قانونی بسازد (بیشتر دستورهای ترکیبی) کارت به جایش اجازه بده / رد کن / توقف را دارد، همان‌طور که برای خواندن فقط‌خواندنی یک فایل (Read،‏ Grep،‏ Glob) بیرون از پوشهٔ کاری سشن. Claude Code از 2.1.259 به بعد، در پنجرهٔ Bash خودش یک ردیف «رفتن به مود خودکار» را در همین جا می‌گذارد، در پنجرهٔ خواندن بیرون از پوشه یک ردیف «از این به بعد خواندن بیرون از پوشه‌های کاری را ببند»، و برای یک Write/Edit که نمی‌تواند برایش قانونی مخصوص فایل بسازد یک تعویض مود اجازه، مثل قبول خودکار همهٔ ویرایش‌های فایل (acceptEdits)؛ aipager هیچ‌وقت هیچ‌کدام از این‌ها را انتخاب نمی‌کند؛ مودها را آگاهانه با ‎/mode عوض کنید.
  • توقف: به جای جواب دادن، کار را قطع می‌کند.

جواب از طریق هوک اجازهٔ aipager به Claude Code می‌رسد که تا ۲۰ ثانیه منتظرش می‌ماند. درخواستی که قبل از کارت در حال کار آمده (آن‌وقت به‌شکل پیام جداگانه، فقط با اجازه بده و رد کن فرستاده می‌شود) هم همین‌طور جواب داده می‌شود. وقتی آن انتظار تمام شد، دکمه‌ها به جایش جواب را در پنجرهٔ سؤال خود Claude Code تایپ می‌کنند؛ آن‌وقت «رد کن» آخرین ردیف پنجره را انتخاب می‌کند («No, and tell Claude what to do differently») که مثل توقف کار Claude را تمام می‌کند، و کارت می‌گوید 🚫 jim · رد شد.

هر زدن دکمه در ‎~/.claude/aipager-audit.jsonl ثبت می‌شود و به‌شکل یک جواب یک‌خطی زیر کارت در حال کار هم نوشته می‌شود: ✅ jim · اجازه داده شد · @alice · Bash: List the temp directory (توضیح آن اجرا، یا وقتی توضیحی ندارد دستورش؛ در چتی که با aipager config راه افتاده؛ در استفادهٔ شخصی فقط اجازه داده شد).

تا وقتی یک درخواست اجازه (یا یک AskUserQuestion) منتظر شماست، سشن منتظر نشان داده می‌شود، هیچ‌وقت آماده. اگر Claude Code در این مدت دربارهٔ بیکار ماندن ورودی تذکر بدهد، چت ⬆️ jim · هنوز بالاتر منتظر جواب شماست را به‌شکل جواب به آن درخواست می‌گیرد، یک بار در هر انتظار.

پنجره‌های AskUserQuestion هم همین‌طور نشان داده می‌شوند، با یک دکمه برای هر گزینه (چهار تای اول)، و برای سؤالی که چند جواب را قبول می‌کند، کلیدهای ⬜/☑ و یک دکمهٔ ✅ ارسال. خود سؤال و توضیح هر گزینه کامل نشان داده می‌شوند، مثل ترمینال. فقط فرمی کوتاه می‌شود که برای یک پیام تلگرام زیادی بلند باشد: کارت در حال کار اول ردیف‌های ابزار کمتری نشان می‌دهد، بعد بلندترین متن‌ها از میان سؤال و توضیح‌ها سر یک کلمه با … تمام می‌شوند.

بیشتر از یک درخواست. Claude Code می‌تواند هم‌زمان منتظر دو درخواست باشد: یک ایجنت پس‌زمینه اجازه می‌خواهد و در همان حال Claude از شما سؤالی می‌پرسد، یا برعکس. aipager هر دو را نشان می‌دهد: اولی روی کارت در حال کار (یا به‌شکل پیام جداگانه)، و هر کدام که بعد بیاید به‌شکل پیام جداگانه زیر کارت، با دکمه‌های خودش. سشن تا وقتی جواب آخری داده نشده منتظر شما نشان داده می‌شود، و پیامی که در این فاصله بفرستید تا آن موقع نگه داشته می‌شود. به هر ترتیبی که خواستید جواب بدهید. اجازه بده و رد کن تا وقتی هوک اجازه منتظر است از طریق آن ارسال می‌شوند، و هوک به همان درخواست می‌رسد، هر جا که باشد. دکمه‌ای که باید کلید تایپ کند (گزینهٔ یک سؤال، یا اجازه بده و رد کن وقتی انتظار هوک تمام شده) کلیدها را فقط در درخواستی تایپ می‌کند که Claude Code اول نشان می‌دهد: Claude Code هر بار فقط یک پنجرهٔ سؤال نشان می‌دهد و کلیدها به پنجرهٔ رویی می‌رسند. وگرنه آن دکمه چیزی تایپ نمی‌کند، دکمه‌هایش سر جایشان می‌مانند و می‌گوید فعلاً Claude Code یک درخواست دیگر را جلوتر نشان می‌دهد؛ اول به آن جواب بدهید، بعد به این یکی.، یا وقتی aipager ترتیب را نمی‌داند (مثلاً برای ایجنتی که شروعش را ندیده) برای aipager معلوم نیست Claude Code کدام درخواست را اول نشان می‌دهد؛ این یکی را در ترمینال جواب بدهید. اگر اول به درخواست روی کارت جواب داده شود، کارت نشان می‌دهد که منتظر است و فقط دکمهٔ توقف را دارد، و بقیهٔ درخواست‌ها دکمه‌هایشان را نگه می‌دارند. اگر Claude کارش را تمام کند و درخواست یک ایجنت هنوز باز باشد، جواب مثل همیشه می‌آید و سشن همچنان منتظر آن درخواست می‌ماند، که دوباره به‌شکل پیام جداگانه فرستاده می‌شود. ری‌استارت وقتی دو درخواست یا بیشتر باز است هیچ‌کدام را برنمی‌گرداند: دکمه‌هایشان قبلاً جواب داده شده جواب می‌دهند و چیزی تایپ نمی‌کنند، و هنوز می‌شود در ترمینال به درخواست‌ها جواب داد. یک درخواستِ تنهای باز مثل قبل برمی‌گردد.

در ۸۰٪ کانتکست، چت ⚠️ name · کانتکست ۸۲٪ پر شده - به‌زودی خودکار کامپکت می‌شود را با 📦 الان کامپکت کن می‌گیرد که ‎/compact را به آن سشن می‌فرستد. این هشدار در هر گفتگو یک بار می‌آید: کامپکت کردن آن را برنمی‌گرداند و یک گفتگوی جدید (مثلاً بعد از ‎/clear) دوباره آن را می‌گیرد.

دکمه‌های قدیمی#

دکمه‌هایی که روی یک کار در جریان اثر می‌گذارند (توقف، بستن، ری‌استارت، تعویض ‎/mode و «توقف و تغییر مود» آن، «جایگزینی» در ‎/new) به کاری بسته‌اند که برایش نشان داده شده‌اند. دکمه‌ای که از یک کار قبلی جا مانده، به جای اینکه روی هر چه الان در جریان است اثر بگذارد، چیزی را عوض نمی‌کند، و دکمه‌ای هم که قبل از بسته شدن سشن و ادامه یا ری‌استارت دوباره‌اش نشان داده شده همین‌طور. بستن، ری‌استارت، تعویض ‎/mode، و توقف در ‎/status یا فهرست انتخاب ‎/stop جواب می‌دهند x1 سراغ کار جدیدی رفته - … با اینکه دوباره چه چیزی را بزنید یا بفرستید (یا این سشن بسته شده.)؛ توقف کارت در حال کار جواب می‌دهد آن کار قبلاً تمام شده - …، و «توقف و تغییر مود» در ‎/mode کارتش را به کارت ‎/mode زیر ⚠️ x1 کار جدیدی را شروع کرد، پس چیزی تغییر نکرد. برمی‌گرداند. «جایگزینی» در ‎/new وقتی سشن بعد از نشان داده شدن کارتش کاری را شروع کرده باشد می‌گوید x1 در این فاصله کارش را شروع کرده. برای جایگزین کردنش دوباره /new بفرستید..

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

دکمهٔ ⚡ همین حالا بفرست فقط روی پیامی کار می‌کند که زیرش است: اگر Claude آن پیام را قبلاً برداشته باشد، زدنش جواب می‌دهد Claude قبلاً آن را برداشته، چیزی نمی‌فرستد و خط‌های صف را برمی‌دارد.

جواب‌ها#

وقتی یک کار تمام می‌شود، جواب همان‌طور که شکل پیام‌هایتان می‌گوید می‌آید (پایین و تنظیمات را ببینید). اگر جواب Claude بلندتر از چیزی باشد که یک پیام جا دارد (حدود ۳۲ کیلوبایت)، پیام هر قدر جا شود را زیر یک یادداشت 📎 جواب کامل در فایل زیر ↓ نشان می‌دهد، و کل کار (قدم‌هایش و جواب کامل) به‌شکل ‎<name>_full_log.md می‌آید که تلگرام بدون برنامهٔ دیگری نشانش می‌دهد. وقتی کارت در حال کار مجبور شده ردیف‌هایی را جا بیندازد هم همین فایل پیوست می‌شود.

کاری که با یک خطای API از Anthropic تمام شود (اعتبار، شلوغی سرور، محدودیت سرعت، شبکه) به جای جواب ‎⚠️ name · <what went wrong>‎ را نشان می‌دهد، با 🔄 دوباره امتحان کن که آخرین پیام را دوباره به همان سشن می‌فرستد. وقتی چت به خاطر بن تلگرام ساکت است، زدنش هیچ کاری نمی‌کند (پیام دوباره فرستاده نمی‌شود و دکمه سر جایش می‌ماند)، پس بعد از تمام شدن بن دوباره بزنیدش.

در شکل «کارت + جواب جدا»، کارت تمام‌شده بالای جواب می‌ماند، به‌عنوان سابقهٔ اینکه جواب چطور به دست آمد: ردیف‌های ابزار، ردیف‌های ایجنت و حرف‌هایی که Claude بینشان زد. جواب به‌شکل پیام جداگانهٔ خودش (با اعلان) می‌آید. از کاری که هیچ ابزاری اجرا نکرد (نه ابزاری، نه ایجنتی، نه دستور پس‌زمینه‌ای، نه سؤال یا درخواست اجازه‌ای) فقط ✅ name · تمام شد · Ns می‌ماند، برای همین کارتش وقتی هنوز «در حال کار» است برداشته می‌شود و هیچ‌وقت «تمام شد» نمی‌شود، و به‌جایش خط اول جواب زمان را نشان می‌دهد (💬 name · تمام شد (…)). فرستادن فایل برای شما اینجا اجرای ابزار حساب نمی‌شود: فایل‌ها بعد از جواب می‌آیند. کاری که جوابی برای نشان دادن ندارد، یا با یک خطای API تمام شده، کارتش را نگه می‌دارد. برای اینکه هر کار یک پیام داشته باشد، «جواب داخل همان کارت» (جواب در کارت می‌رود) یا «فقط جواب، جای کارت» (کارت برداشته می‌شود و جواب تنها می‌ماند) را انتخاب کنید.

هر کار دقیقاً یک کارت در حال کار دارد. پیامی که وقتی یک کار در جریان است می‌فرستید هیچ‌وقت کارت دومی برای آن کار اضافه نمی‌کند، و کارتی که کارش تمام شده دیگر دکمهٔ توقف ندارد: اگر چیزی آن را نبسته باشد (یک Stop گم‌شده، یک ری‌استارت)، aipager بعد از ۳۰ ثانیه، همان‌طور که شکل پیام‌هایتان می‌گوید، می‌بنددش. بعد از ری‌استارت aipager، کارتی که کارش هنوز در جریان است نگه داشته می‌شود و فوراً دوباره جلو می‌رود و زمانش از شروع کار ادامه پیدا می‌کند، و سشن تا تمام شدن کار در حال کار نشان داده می‌شود؛ هر کارت دیگری که از قبل از ری‌استارت مانده بسته می‌شود («aipager ری‌استارت شد»، و دکمهٔ توقف برداشته می‌شود). سشنی که منتظر یک درخواست اجازه یا یک سؤال تکی از Claude بود، منتظر برمی‌گردد، نه در حال کار: کارتش و نوار سنجاق‌شده می‌گویند منتظر شماست و دکمه‌های درخواست همچنان جوابش را می‌دهند، مگر اینکه گفتگوی ذخیره‌شده نشان دهد در این فاصله در ترمینال جواب داده شده. سؤال‌های چندبخشی یا چندانتخابی، و درخواست‌هایی که یک ساب‌ایجنت پرسیده، به ترمینال سپرده می‌شوند. وقتی معلوم شود یک درخواست تمام شده (با زدن دکمه یا در ترمینال جواب داده شده، کارش تمام شده، یا ری‌استارت برش نگردانده چون در این فاصله جواب داده شده یا نشده ذخیره و دوباره خوانده شود)، دکمه‌های جواب قدیمی‌اش جواب می‌دهند «قبلاً جواب داده شده» و چیزی تایپ نمی‌کنند، بعد از ری‌استارت هم. درخواستی که هیچ‌کس جوابش را نمی‌دهد تا وقتی Claude منتظرش است باز می‌ماند. aipager فقط وقتی دیگر منتظرش نمی‌ماند که Claude ۵ دقیقه هیچ خبری ندهد و گفتگوی ذخیره‌شده نشان بدهد آن درخواست گذشته است (خبر جواب گم شده)؛ چنین درخواستی معلوم نیست تمام شده، پس دکمه‌هایش همچنان به آن پنجره جواب می‌دهند. این خبر فقط خبر خود Claude و ایجنتی است که پرسیده: ایجنت پس‌زمینه‌ای که برای خودش کار می‌کند حساب نمی‌شود، و گفتگوی ذخیره‌شده دربارهٔ درخواست یک ایجنت چیزی نمی‌گوید؛ آن درخواست منتظر خبر خود همان ایجنت می‌ماند.

کاری که Claude خودش شروع می‌کند (یک ایجنت پس‌زمینه که با یک ‎<task-notification>‎ گزارش می‌دهد، وقتی هیچ کاری باز نیست) فقط وقتی کاری بکند کارت در حال کارش را می‌گیرد: با اولین اجرای ابزار، یا بعد از ۱۵ ثانیه، هر کدام زودتر باشد. بیشتر این بیدار شدن‌ها چند ثانیه «خبر جدیدی نیست» هستند؛ آن‌ها حالا فقط جواب را نشان می‌دهند. نشانگر «در حال تایپ…» همچنان تا وقتی اجرا می‌شود دیده می‌شود، و خود جواب همیشه فرستاده می‌شود؛ هیچ چیزی به این دلیل که کم‌اهمیت است فیلتر نمی‌شود. کارهایی که خودتان شروع می‌کنید، از تلگرام یا ترمینال، همچنان فوراً کارتشان را می‌گیرند.

تا وقتی یک سشن در حال کار است، هر ایجنت پس‌زمینه‌ای که Claude شروع می‌کند (با ابزار Agent در Claude Code، که در نسخه‌های قدیمی‌تر Task بود) ردیف خودش را روی کارت در حال کار می‌گیرد: ‎🤖 <type> · <activity> · <elapsed>‎، که نوع ایجنت و کاری را که الان انجام می‌دهد نشان می‌دهد و با رسیدن اجرای ابزارهای خودش آپدیت می‌شود. وقتی آن ایجنت سه اجرای ابزار یا بیشتر داشته باشد، این‌ها در یک دکمهٔ ▸ N ابزار اجرا شد درست زیر ردیفش جمع می‌شوند؛ هیچ‌وقت در خط زمانی کار اصلی یا شمارش Bash ×N آن نمی‌آیند. وقتی ایجنت تمام شود، ردیفش به ✅ 🤖 <type> · N ابزار اجرا کرد · <elapsed> ثابت می‌شود و همان دکمه را نگه می‌دارد. ایجنتی که یک ایجنت دیگر شروعش کرده (یک کمک‌کار)، اگر aipager همان لحظهٔ شروع بداند چه کسی شروعش کرده، پیش از نوع خودش اسم ایجنت بالای زنجیره‌اش را می‌آورد: ‎🤖 pipeline-runner › ship-tester؛ ردیف‌ها به همان ترتیبی می‌مانند که ایجنت‌ها شروع شدند. فایل پیوست ‎.md بالا یک بخش «ایجنت‌ها» می‌گیرد که هر ایجنتی را که در آن کار اجرا شد، با زمانش، تعداد ابزارهایش و ابزارهایی که اجرا کرد، فهرست می‌کند.

وقتی ایجنت‌های پس‌زمینه بعد از تمام شدن کارشان هنوز اجرا می‌شوند، کارت به‌عنوان وضعیت آن کار می‌ماند. وقتی Claude در این فاصله پیام جدیدی برمی‌دارد، کارت زنده همانی است که زیر آن پیام است و همچنان ایجنت‌های در حال کار را نشان می‌دهد. پیامی که به سشن آماده می‌فرستید یک کار جدید شروع می‌کند: کارت کار قبلی همان‌جا که هست ثابت می‌شود و قدم‌هایش می‌ماند، و کار جدید کارت خودش را می‌گیرد. پیامی که در صف بوده و برداشته شود ادامهٔ کار همان کار است: کارتش زیر آن پیام دوباره فرستاده می‌شود و کپی قبلی پاک می‌شود. اجرای ابزارهایی که داخل یک ایجنت انجام می‌شود هیچ‌وقت به‌شکل ردیف‌های خود کار اصلی دیده نمی‌شود، و هیچ‌وقت باعث نمی‌شود aipager فکر کند کار جدیدی شروع شده.

دستوری که Claude در پس‌زمینه اجرا می‌کند (run_in_background،‏ Ctrl+B، یا دستوری که Claude Code وقتی طول می‌کشد به آنجا می‌برد) تا وقتی اجرا می‌شود ردیف خودش را دارد: ⏳ دستور پس‌زمینه: <description> (۳:۱۲)، که با توضیح آن اجرا یا وگرنه خط اول دستور نام‌گذاری می‌شود. وقتی تمام شود ردیف به ✅ دستور پس‌زمینه: <description> - تمام شد (۶:۱۲)، ❌ ... - با خطا تمام شد (کد خروج ۱)، یا ⏹ ... - متوقف شد (۶:۱۲) ثابت می‌شود (Claude با TaskStop متوقفش کرده، یا Claude Code زیر فشار حافظه)؛ ردیف‌های با خطا و متوقف‌شده همین علامت را روی کارت تمام‌شده نگه می‌دارند. کاری که وقتی چنین دستوری هنوز اجرا می‌شود تمام شود تمام‌شده نیست: کارت به‌عنوان وضعیت آن کار منتظر می‌ماند (🔄 name · ۱ دستور پس‌زمینه هنوز در حال کار · ۴:۱۰، یا با یک ایجنت هم ۱ ایجنت (ship-reviewer) و ۱ دستور پس‌زمینه هنوز در حال کار)، و وقتی دستور تمام شود، ادامهٔ کار Claude روی همان کارت می‌آید. دستورهایی که داخل یک ایجنت شروع شده‌اند مال همان ایجنت‌اند و نشان داده نمی‌شوند. دستوری که aipager پایانش را هیچ‌وقت نمی‌بیند (یک ری‌استارت، یک رویداد گم‌شده) بعد از دو ساعت دیگر شمرده نمی‌شود (AIPAGER_BG_SHELL_MAX_TRACK، به ثانیه): ردیفش ⏹ ... - پایانش دیده نشد می‌شود، و کاری که فقط منتظر آن بود با ⚠️ name · تمام شد (۲:۰۰:۰۴، از دستور پس‌زمینه خبری نشد) بسته می‌شود.

وقتی خط زمانی یک کار طولانی می‌شود، هر رشتهٔ قدیمی‌تر از اجرای ابزارها (سه تا یا بیشتر پشت هم، و نه رشته‌ای که الان در جریان است) همان جایی که اتفاق افتاده در یک دکمهٔ ▸ N ابزار اجرا شد جمع می‌شود، به جای اینکه کامل روی هم انباشته شود یا با سقف طول پیام خود تلگرام بریده شود؛ روی هر کدام بزنید تا همان‌جا بخوانیدش. حرف‌های Claude هیچ‌وقت جمع نمی‌شوند؛ جدیدترین فعالیت و خط وضعیت همیشه بدون زدن چیزی دیده می‌شوند. ردیف خود یک ایجنت پس‌زمینه که هنوز در حال کار است (یا همین الان ثابت شده) هیچ‌وقت خودش در یک دکمه جمع نمی‌شود، فقط اجرای ابزارهایش، و هیچ‌وقت وقتی تنها چیزی است که بین خط زمانی و سقف ایستاده. فقط اگر خط زمانی آن‌قدر بزرگ باشد که حتی با جمع شدن همه باز هم جا نشود، محتوایی واقعاً از کارت حذف می‌شود؛ در آن حالت فایل پیوست ‎.md بالا سابقهٔ کامل را دارد.

ایجنت‌هایی که وقتی جواب فرستاده می‌شود هنوز کار می‌کنند#

‏Claude Code می‌تواند ایجنت‌ها را در پس‌زمینه اجرا کند، و کاری که شروعشان کرده ممکن است وقتی هنوز کار می‌کنند تمام شود. آن‌وقت جواب با یک خط جداکننده و یک وضعیت کوتاه از آن کار پس‌زمینه تمام می‌شود، به سبک پنل ایجنت‌های خود Claude Code، که تا وقتی کار ادامه دارد آپدیت می‌شود. هر چه زیر آن خط است با نوشتهٔ ریز است (پانویس تلگرام)، تا خود جواب بیشتر به چشم بیاید:

text
⏳ ۵ ایجنت در حال کار · 🖥 ۱ دستور پس‌زمینه (shell) در حال اجرا

○ 🤖 pipeline-runner · Writing final.md for the pipeline

- 🤖 ship-tester · Write and run criteria tests
- 🤖 ship-developer · Editing state.py
- 🤖 ship-developer › ship-reviewer · Collect line numbers

‖ 🤖 r2-runner · منتظر ایجنت‌های خودش

وقتی کار ایجنت‌ها تمام شود، نتیجه همین‌جا ارسال می‌شود.
  • خط اول می‌شمارد. ایجنت‌های در حال کار (یا تمام‌شده)، و دستورهای پس‌زمینهٔ این کار که در حال اجرا، تمام‌شده یا متوقف‌شده‌اند. یک دستور پس‌زمینه همیشه فقط یک عدد است، هیچ‌وقت خود دستورش.
  • یک ردیف برای هر ایجنت، یک 🤖 و نوعش با حروف پررنگ، بعد کاری که الان انجام می‌دهد: آخرین خط متن خودش (حرف‌های Claude، همان‌طور که نوشته شده، هیچ‌وقت ترجمه نمی‌شود)، وگرنه آخرین ابزارش به‌شکل یک عبارت کوتاه که می‌گوید روی چه چیزی کار می‌کند (Reading state.py،‏ Writing final.md،‏ Searching for …‎، یا توضیح خود یک دستور)، وگرنه کاری که Claude موقع شروع ایجنت به آن سپرده، وگرنه فقط آخرین ابزارش (Running a command،‏ Using TodoWrite)، وگرنه فقط نوعش. برای همین دو ایجنت هم‌نوع که دستورهای بدون توضیح اجرا می‌کنند باز هر کدام کار خودشان را نشان می‌دهند. ایجنتی که ایستاده تا منتظر ایجنت‌هایی بماند که خودش شروع کرده، به‌جای این‌ها می‌گوید ‖ … منتظر ایجنت‌های خودش.
  • ایجنت‌ها به‌شکل درخت. ایجنت‌هایی که سشن شروع کرده سطح اول‌اند. هر ایجنتی که یکی از آن‌ها شروع کرده، در هر عمقی، درست زیر آن می‌آید، هر کدام درست بعد از ایجنتی که شروعش کرده؛ ایجنتی که یک ایجنتِ سطح دوم شروعش کرده، اول اسم همان ایجنت را می‌آورد (ship-developer › ship-reviewer). کارت در حال کار به‌جایش همان ایجنت را بعد از ایجنت بالای زنجیره می‌آورد (pipeline-runner › ship-reviewer). هیچ‌وقت بیشتر از دو سطح نیست. ایجنتی که در سطح دوم کار می‌کند ○ خودش را ندارد: آنجا تلگرام یک نقطهٔ فهرست می‌کشد. ایجنتی که aipager هنوز نمی‌داند چه کسی شروعش کرده در سطح اول نشان داده می‌شود، هیچ‌وقت زیر یک حدس، و همین که شروع‌کننده‌اش معلوم شد زیر آن می‌رود.
  • حداکثر شش ردیف، اول ایجنت‌هایی که هنوز کار می‌کنند، بعد +N ایجنت دیگر برای ایجنت‌هایی که ردیف ندارند. هیچ ایجنتی بدون ایجنت‌های بالای سرش نشان داده نمی‌شود.
  • قول «وقتی کار ایجنت‌ها تمام شود، نتیجه همین‌جا ارسال می‌شود.» فقط تا وقتی یک ایجنت هنوز کار می‌کند می‌ماند. دستورهای پس‌زمینه هیچ‌وقت آن را ندارند: یک سرور توسعه ممکن است هیچ‌وقت تمام نشود.

ردیف هر ایجنت وقتی خود آن ایجنت متوقف شود جداگانه ثابت می‌شود، به ✓ 🤖 Explore · تمام شد (۰:۴۲) (مدتی که آن ایجنت کار کرد)، و خط اول کم می‌شمارد. ایجنتی که یکی از ایجنت‌های فهرست بعد از ارسال جواب شروع کند، در آپدیت بعدی زیر همان ایجنت به وضعیت اضافه می‌شود؛ ایجنتی که خود سشن بعداً شروع کند، به‌جایش زیر یک جواب بعدی می‌آید. وقتی همهٔ ایجنت‌ها تمام شوند، ردیف‌ها جایشان را به یک خط می‌دهند، با زمان از جواب تا تمام شدن آخرین ایجنت:

text
✅ کار ۲ ایجنت تمام شد (۶:۱۲) · 🖥 ۱ دستور پس‌زمینه (shell) در حال اجرا

و وقتی آن دستور پس‌زمینه تمام شود، ✅ کار ۲ ایجنت تمام شد (۶:۱۲) · ۱ دستور پس‌زمینه (shell) تمام شد (۲:۱۳:۰۵) (مدتی که دستور اجرا شد؛ متوقف شد وقتی بسته شده یا Claude متوقفش کرده، تمام شد وقتی خودش تمام شده، با خطا یا بدون خطا؛ ردیف کارتش می‌گوید چطور). جوابی که فقط یک دستور پس‌زمینه از کار خودش دارد 🖥 ۱ دستور پس‌زمینه (shell) در حال اجرا را نشان می‌دهد که به ۱ دستور پس‌زمینه (shell) تمام شد (…) یا ۱ دستور پس‌زمینه (shell) متوقف شد (…) ثابت می‌شود.

فقط دستورهای پس‌زمینهٔ کار خود همان جواب شمرده می‌شوند: سرور توسعه‌ای که یک کار قبلی روشن گذاشته زیر هر جوابی تکرار نمی‌شود (نوار سنجاق‌شده همچنان همهٔ دستورهای پس‌زمینه را می‌شمارد). ‎/stop کار را تمام می‌کند، ولی Escape یک دستور پس‌زمینه را تمام نمی‌کند: دستوری که هنوز اجرا می‌شود تا وقتی تمام شود در نوار سنجاق‌شده می‌ماند و دیگر زیر جواب‌های بعدی شمرده نمی‌شود؛ ادامهٔ بعدی‌اش آن‌وقت کار خودش را شروع می‌کند.

آن جواب همان لحظه که کار تمام می‌شود، به‌شکل یک پیام عادی (با اعلان) در جواب پیام شما فرستاده می‌شود؛ همان متنی که ترمینال نشان می‌دهد. کارت در حال کار بالای آن به‌عنوان وضعیت زندهٔ کار می‌ماند، در هر شکل پیامی: 🔄 name · ۱ ایجنت (general-purpose) هنوز در حال کار · ۱:۱۸، با دکمهٔ توقف. وقتی ایجنت‌ها گزارش بدهند، جواب Claude به آن به‌شکل پیام جداگانهٔ خودش می‌آید؛ جواب قبلی هیچ‌وقت دوباره فرستاده نمی‌شود، حتی با ری‌استارت aipager. کاری که ایجنت‌هایش بیش از یک بار گزارش می‌دهند برای هر گزارش یک جواب می‌دهد، که هر کدام همان‌طور که نوشته می‌شود فرستاده می‌شود.

ایجنتی که وقتی کار پس‌زمینهٔ خودش هنوز اجرا می‌شود متوقف شده در حال کار حساب می‌شود، چون بعداً ادامه می‌دهد. ایجنتی که یک ایجنت مال خودش را شروع کرده و بعد برای منتظر ماندنِ آن متوقف شده، از همان شروع شناخته می‌شود (از اجرای خودش که ایجنت دیگر را شروع کرد): در وضعیت به‌عنوان در حال کار می‌ماند، و کار را باز نگه می‌دارد، تا وقتی که متوقف شود و هیچ‌کدام از ایجنت‌های خودش دیگر اجرا نشود. اگر دو دقیقه بعد از تمام شدن آخرینِ آن‌ها ادامه نداده باشد، دیگر در حال اجرا حساب نمی‌شود و وضعیت همان‌طور که آخرین بار نشان داده شده می‌ماند. ‎<task-notification>‎ خود Claude برای یک ایجنت همین را در یک یادداشت می‌گوید؛ aipager آن را وقتی آن اعلان یک کار را شروع کند می‌خواند، و همین‌طور وقتی Claude آن را وسط یک کار در جریان بردارد، تا وقتی کارت در حال کار سر جایش است. ردیف چند ثانیه صبر می‌کند و بعد «تمام شد» را نشان می‌دهد، تا آن یادداشت بتواند اول برش گرداند. این وضعیت در هر شکل پیامی، به زبان چت، اضافه می‌شود.

چطور آپدیت می‌شود. aipager جواب را بی‌صدا، فقط وقتی چیزی که وضعیت نشان می‌دهد عوض شده، و حداکثر هر ۳۰ ثانیه یک بار برای هر جواب ویرایش می‌کند (خود جواب اولی حساب می‌شود). هر جوابی که وضعیت دارد این‌طور آپدیت می‌شود (تا پنج جواب منتظر برای هر سشن). این ویرایش‌ها کم‌اهمیت‌اند: ویرایشی که سهمیهٔ ارسال ردش کند، یا وقتی چت به خاطر بن ساکت است بیفتد، انجام نمی‌شود و وضعیت منتظر تغییر بعدی‌اش می‌ماند. ویرایش آخر، وقتی همه‌چیز تمام شده، اگر سکوت یا سهمیه ردش کند یک بار دیگر بعد از تمام شدن سکوت امتحان می‌شود و بعد کنار گذاشته می‌شود. هیچ ویرایشی روی جوابی که پاک شده، برای سشنی که بسته یا kill شده، یا وقتی جواب را برای تلگرام زیادی بلند می‌کند انجام نمی‌شود (وقتی یک جواب بلند بریده می‌شود، جا برای وضعیت نگه داشته می‌شود).

وقتی aipager نمی‌تواند بداند کار تمام شده، وضعیت همان‌طور که آخرین بار نشان داده شد می‌ماند، هیچ‌وقت به «تمام شد» تبدیل نمی‌شود:

  • ایجنتی که aipager ۳۰ دقیقه هیچ خبری از آن نمی‌شنود (AIPAGER_SUBAGENT_SILENCE) دیگر در حال کار شمرده نمی‌شود، ولی بی‌خبری یعنی تمام شدن نیست؛
  • دستور پس‌زمینه‌ای که بیشتر از دو ساعت (AIPAGER_BG_SHELL_MAX_TRACK) بدون دیده شدن پایانش اجرا شود دیگر شمرده نمی‌شود؛
  • ری‌استارت aipager فراموش می‌کند کدام جواب‌ها منتظرند.

ری‌استارت aipager ایجنت‌هایی را که هنوز اجرا می‌شوند نگه می‌دارد، از جمله آن‌هایی که منتظر ایجنت‌های خودشان هستند: جوابی که بعد از ری‌استارت فرستاده شود آن‌ها را فهرست می‌کند، کارت در حال کاری که ری‌استارت آن را تحویل می‌گیرد دوباره نشانشان می‌دهد، و تمام شدنشان بعداً مثل همیشه تشخیص داده می‌شود. ایجنت‌هایی که بیش از ۳۰ دقیقه پیش از ری‌استارت ذخیره شده‌اند برگردانده نمی‌شوند.

جوابی که سکوت بن نگهش داشته، یا بعد از شکست ارسال قالب‌بندی‌شده به‌شکل متن ساده فرستاده شده، بدون وضعیت ارسال می‌شود، و همین‌طور کاری که بدون متن جواب (فقط یک تیتر) تمام شود.

تأیید بستن#

‏‎/kill، فهرست انتخابش و ⋮ ← ⏹ بستن سشن همیشه تأیید می‌خواهند:

text
⏹ سشن jim بسته شود؟ کار Claude متوقف می‌شود و سشن بسته می‌شود.

  [⏹ بستن]  [لغو]

بعد از ⏹ بستن، پیام بالای سشن‌های باقی‌ماندهٔ این چت می‌گوید ⏹ jim بسته شد. تأییدی که بعد از اینکه سشن کار جدیدی را شروع کرده زده شود رد می‌شود (jim سراغ کار جدیدی رفته - …)، و همین‌طور تأییدی برای سشنی هم‌اسم که از آن موقع شروع شده.

نصب ویس (وقتی قابلیتش نصب نیست)#

وقتی یک ویس می‌فرستید و aipager[voice] نصب نیست:

text
⚠️ برای ویس یک پکیج اختیاری لازم است
   (حدود ۲۰۰ مگابایت نصب، و حدود ۷۴ مگابایت مدل در اولین استفاده).

  [📦 نصب قابلیت ویس]  [لغو]

زدن نصب، دستور نصب درست را برای نصب‌کنندهٔ شما اجرا می‌کند (uv tool install --reinstall aipager[voice]،‏ pipx install --force، یا در آخر pip install faster-whisper) و هر ۵ ثانیه پیامش را ویرایش می‌کند، و در صورت موفقیت یک دکمهٔ [🔄 ری‌استارت aipager] پیشنهاد می‌دهد.

ری‌استارت#

🔄 ری‌استارت aipager:

  • ‏aipagerی که به‌شکل سرویس systemd کاربری اجرا می‌شود، یک systemctl --user restart aipager.service جداشده را برای ۵ ثانیه بعد زمان‌بندی می‌کند (با تایمری با دقت ۱ ثانیه)، در یک سرویس موقت بیرون از گروه پروسهٔ خود aipager، تا بعد از بسته شدن aipager هم بماند. وقتی سرویس سشن‌هایتان را می‌بندد (KillMode غیر از process یا none) رد می‌کند و می‌گوید اول aipager service install را اجرا کنید.
  • ‏macOS، وقتی ایجنت launchd نصب است (‎~/Library/LaunchAgents/com.aipager.daemon.plist): launchctl kickstart -k gui/<uid>/com.aipager.daemon، حتی برای aipagerی که خودتان اجرا کرده‌اید.
  • وگرنه aipagerی که خودتان اجرا کرده‌اید (aipager start)، روی Linux حتی وقتی سرویس هم نصب است: یک جانشین جداشده شروع می‌کند که منتظر می‌ماند پروسهٔ قبلی بسته شود و بعد همان دستوری را اجرا می‌کند که aipager با آن شروع شده بود (خروجی‌اش در لاگ ری‌استارت خودکار نوشته می‌شود). aipager فعلی همین که آن جانشین زنده شد تمیز می‌ایستد.

‏SSH لازم نیست. برای تمام کردن یک آپدیت aipager، دکمهٔ 🔄 همین حالا ری‌استارت کن روی کارت آپدیت به‌جایش aipager را درجا، در همان ترمینال، ری‌استارت می‌کند (ببینید آپدیت).

آپدیت#

‏‎/update (فقط ادمین؛ در استفادهٔ شخصی، فقط صاحب aipager) با یک دکمه جواب می‌دهد: 🔄 چک کردن آپدیت. تا آن را نزنید هیچ چیزی جست‌وجو نمی‌شود. زدنش همان پیام را به یک خط برای هر محصول تبدیل می‌کند:

  • ‏aipager 1.0.1 ← 1.1.0 وقتی نسخهٔ جدیدتری هست (جدیدترین در PyPI)؛
  • ‏aipager 1.0.1 (آپدیت است) وقتی نیست؛
  • ‏Claude Code 2.1.282 (چک نشد) وقتی جست‌وجو شکست خورد (شبکه قطع، مهلت ۵ ثانیه، یا claude پیدا نشد).

‏Claude Code با جدیدترین نسخهٔ کانال آپدیت خودش مقایسه می‌شود (autoUpdatesChannel:‏ latest،‏ stable یا rc). زیر این خط‌ها، با متن کوچک، می‌آید aipager چطور نصب شده (مثلاً pipx, from PyPI یا pipx, from local path …‎؛ چت‌های گروهی هیچ‌وقت مسیرها را نشان نمی‌دهند).

اگر چیزی جدیدتر باشد، فقط یک دکمه هست که فقط محصولاتی را که آپدیت دارند آپدیت می‌کند: آپدیت aipager، آپدیت Claude Code یا آپدیت هر دو، به‌علاوهٔ لغو. وقتی aipager پیشنهاد شود، پیام می‌گوید ری‌استارت چطور انجام می‌شود: ری‌استارت: خودکار، وقتی هیچ کاری در جریان نباشد.، ری‌استارت: بعد از نصب، «همین حالا ری‌استارت کن» را بزنید. (aipagerی بدون سرویس، پایین‌تر را ببینید) یا ری‌استارت: دستی (reason).

اگر یک aipager جدیدتر از قبل نصب شده باشد اما aipager در حال اجرا هنوز همان قدیمی باشد (آپدیتی که بدون ری‌استارت تمام شده، یا یک pip install -U دستی)، خط می‌گوید aipager 1.1.0 نصب شده و منتظر ری‌استارت است (نسخهٔ در حال اجرا: 1.0.1). و پیام به‌جای آپدیت، 🔄 همین حالا ری‌استارت کن را پیشنهاد می‌دهد: «آپدیت aipager» هیچ‌وقت برای نسخه‌ای که فقط ری‌استارت لازم دارد پیشنهاد نمی‌شود. نسخهٔ نصب‌شده با اجرای همان مفسری چک می‌شود که aipager با آن ری‌استارت می‌شود، پس نسخه‌ای که نصب شده اما لود نمی‌شود همین را می‌گوید (aipager 1.1.0 نصب شده اما لود نمی‌شود. با … دوباره نصبش کنید.) و چیزی پیشنهاد نمی‌دهد. نسخهٔ منتشرشده‌ای که از نسخهٔ نصب‌شده جدیدتر باشد باز هم به‌عنوان آپدیت پیشنهاد می‌شود. aipager جدیدتر روی نصبی که از اینجا آپدیت نمی‌شود (editable،‏ Nix،‏ Snap، پکیج سیستم، کانتینر، یا نصب کاربر دیگر) با دلیلش نشان داده می‌شود و پیشنهاد نمی‌شود. همین برای Claude Code جدیدتری برقرار است که با npm در پوشه‌ای نصب شده که کاربر شما نمی‌تواند رویش بنویسد (مثلاً sudo npm install -g زیر ‎/usr/lib/node_modules)، جایی که claude update فقط می‌توانست شکست بخورد: خط می‌گوید از اینجا نمی‌شود آپدیت کرد: installed with npm into a folder your user can't write to; run "claude install" once to switch to Claude Code's own installer, then restart aipager. اگر هیچ چیزی آپدیت‌شدنی نباشد، پیام می‌گوید «همه چیز آپدیت است.»، می‌گوید یک بررسی شکست خورد، یا وقتی چیزی جدیدتر هست ولی از اینجا نصب نمی‌شود، «نسخهٔ جدیدی آمده، اما از اینجا نصب نمی‌شود.»، با یک دکمهٔ دوباره چک کن و بدون دکمهٔ آپدیت.

دکمهٔ آپدیت فقط چیزی را شروع می‌کند که آن بررسی پیشنهاد کرده. اگر بررسی بیشتر از ۱۰ دقیقه پیش بوده، آپدیت دیگری از آن موقع اجرا شده، یا نسخه‌ها دیگر با دکمه جور نیستند، به جایش از شما می‌خواهد دوباره چک کنید. دکمه‌های یک منوی قدیمی‌تر ‎/update (آپدیت Claude Code / آپدیت aipager / هر دو جداگانه) جواب می‌دهند «این منو قدیمی است، دوباره ‎/update بفرستید» و کاری نمی‌کنند. هر زدنی قانون ادمین را دوباره چک می‌کند.

آپدیت Claude Code،‏ claude update را اجرا می‌کند (با مسیر کامل، مهلت ۵ دقیقه) و Claude Code A ← B، «آپدیت است»، یا شکست را با انتهای خروجی‌اش گزارش می‌دهد. سشن‌های در حال اجرا تا وقتی ری‌استارتشان کنید (‎/restart) نسخهٔ قدیمی را نگه می‌دارند؛ جواب آن‌ها را فهرست می‌کند. هیچ سشنی برایتان ری‌استارت نمی‌شود. سشن‌های جدید از نسخهٔ جدید استفاده می‌کنند.

آپدیت aipager (آپدیت aipager، یا نیمهٔ دوم آپدیت هر دو که اول Claude Code را آپدیت می‌کند):

  1. روی نصب PyPIی که از قبل آپدیت است، همین را می‌گوید و می‌ایستد.
  2. اگر aipager می‌تواند خودش را ری‌استارت کند، اول صبر می‌کند تا هیچ چیزی در جریان نباشد: هیچ سشنی که کاری انجام می‌دهد، منتظر یک سؤال است، یک ایجنت پس‌زمینه اجرا می‌کند، یک کارت در حال کار زنده نشان می‌دهد، ابزاری اجرا می‌کند، یا یک درخواست اجازهٔ باز دارد، و هیچ جواب نگه‌داشته‌شده‌ای که منتظر برداشته شدن یک محدودیت سرعت است. پیام فهرست می‌کند منتظر چه چیزی است، با همین حالا ری‌استارت کن (بدون انتظار) و لغو. بعد از ۱۰ دقیقه دوباره می‌پرسد: ۱۰ دقیقهٔ دیگر صبر کن، همین حالا ری‌استارت کن، لغو. اگر یک ساعت جوابی نگیرد، خودش لغو می‌شود.
  3. از طریق نصب‌کننده‌ای که صاحب aipager در حال اجراست آپدیت می‌کند (pipx upgrade aipager،‏ uv tool upgrade aipager،‏ brew upgrade aipager، یا ‎<venv>/bin/python -m pip install --upgrade aipager)، با مسیر کامل و مهلت ۱۰ دقیقه. وقتی نصب‌کننده اجرا می‌شود دکمهٔ لغوی نیست.
  4. چک می‌کند نسخهٔ جدید در یک مفسر جدید import می‌شود. آپدیتی که شکست بخورد، تمام نشود یا import نشود هیچ چیزی را ری‌استارت نمی‌کند. آپدیتی که تمام نشده وسط کار متوقف شده، پس پیام هشدار می‌دهد که ممکن است نصب نیمه‌کاره باشد و دستور نصب دوباره را می‌دهد تا قبل از ری‌استارت بعدی اجرایش کنید. خروجی نصب‌کننده فقط در چت خصوصی نشان داده می‌شود؛ گروه «(خروجی در log خود aipager است)» را می‌گیرد.
  5. اگر وسط آپدیت کاری شروع شده باشد، دوباره صبر می‌کند.
  6. یک systemctl --user restart aipager.service جداشده را برای ۵ ثانیه بعد زمان‌بندی می‌کند (با تایمری با دقت ۱ ثانیه)، و پیام وضعیت می‌گوید ⏳ aipager A ← B نصب شد، در حال ری‌استارت…. وقتی قدم ۵ منتظر است، می‌گوید ⏳ aipager A ← B نصب شد؛ وقتی کار فعلی تمام شود، ری‌استارت می‌شود. بعد از ری‌استارت، aipager جدید همان پیام را به ✅ aipager A ← B آپدیت شد و N سشن دوباره وصل شد تبدیل می‌کند (و ⚠️ برنگشتند: … برای هر سشنی که برنگشت). اگر پیام پاک شده یا دیگر ویرایش‌شدنی نیست، نتیجه را به‌شکل یک پیام جدید به چتی که خواسته بود می‌فرستد.

در Mini App، تنظیمات ← آپدیت «در حال ری‌استارت aipager…‎» را با یک فانوس چرخان نشان می‌دهد تا aipager جدید جواب بدهد، و بعد «به B آپدیت شد.» را با تعداد سشن‌هایی که دوباره وصل شدند. هیچ‌وقت شمارش معکوس نشان نمی‌دهد. بعد از حدود ۲ دقیقه بدون جواب (هیچ‌وقت قبل از اینکه aipager قدیمی می‌توانست گزارش کند ری‌استارتی انجام نشد) می‌گوید «هنوز در حال ری‌استارت است؛ چند لحظه بعد برنامه را دوباره باز کنید.». با تونل مدیریت‌شدهٔ aipager، ری‌استارتِ بعد از آپدیت آدرس اپ را نگه می‌دارد (aipager جدید تونل را تحویل می‌گیرد)، پس صفحهٔ باز سر پا می‌ماند و «به B آپدیت شد» را نشان می‌دهد. اگر آخرش نشود تونل را نگه داشت، صفحه بعد از حدود ۲ دقیقه می‌گوید «هنوز در حال ری‌استارت است؛ چند لحظه بعد برنامه را دوباره باز کنید.». آپدیتی که از یک aipager بدون این قابلیت (یا با MINIAPP_KEEP_TUNNEL=0) شروع شده باشد هنوز آدرس را عوض می‌کند: وقتی aipager قدیمی دیگر جواب نمی‌دهد صفحهٔ باز می‌گوید «aipager ری‌استارت شد. وقتی چت گفت آپدیت شده، برنامه را دوباره باز کنید»؛ ببندیدش و دوباره از دکمهٔ منوی چت یا ‎/app بازش کنید. ورود اپ ۵ دقیقه اعتبار دارد، پس صفحه‌ای که بیشتر از این باز شده به جایش می‌گوید «برای دیدن نتیجهٔ آپدیت، برنامه را دوباره باز کنید.».

‏aipager بعد از آپدیت فقط وقتی خودش را ری‌استارت می‌کند که به‌شکل سرویس systemd کاربری اجرا شود و آن سرویس KillMode=process (یا none) داشته باشد. با یک KillMode ناامن، aipager باز هم آپدیت می‌شود، و پیام می‌گوید ری‌استارت لازم است: …: اول aipager service install را اجرا کنید (سشن‌هایی را که یک ری‌استارت می‌بست فهرست می‌کند).

همین حالا ری‌استارت کن، بدون سرویس. aipagerی که هیچ مدیر سرویسی ری‌استارتش نمی‌کند (aipager start در یک ترمینال یا tmux،‏ Docker، یا ایجنت launchd روی macOS) آپدیت را نصب می‌کند و بعد «همین حالا ری‌استارت کن» را بزنید تا اجرا شود (aipager صبر می‌کند تا هیچ کاری در جریان نباشد). را با یک دکمهٔ 🔄 همین حالا ری‌استارت کن نشان می‌دهد. زدنش (فقط برای ادمین، مثل همهٔ دکمه‌های آپدیت):

  1. چک می‌کند aipager نصب‌شده لود می‌شود (⏳ در حال چک کردن aipager نصب‌شده…)؛ نصب خراب هیچ چیزی را ری‌استارت نمی‌کند، و با همان نسخه می‌گوید چیزی برای ری‌استارت نیست؛
  2. مثل ری‌استارت systemd، صبر می‌کند تا هیچ کاری در جریان نباشد، با همین حالا ری‌استارت کن (رد شدن از انتظار) و لغو؛
  3. نصب را دوباره چک می‌کند، بعد می‌گوید ⏳ aipager A ← B نصب شد، در حال ری‌استارت… و aipager را تمیز متوقف می‌کند (همان کاری که Ctrl+C می‌کند)؛
  4. ‏aipager جدید را درجا شروع می‌کند: همان پروسه، همان دستور، همان محیط و پوشه، در همان ترمینال یا پنجرهٔ tmux (و در Docker، همان پروسهٔ کانتینر). سشن‌ها به کارشان ادامه می‌دهند. aipager جدید پیام را به ✅ aipager A ← B آپدیت شد و N سشن دوباره وصل شد تغییر می‌دهد.

زدن دکمه‌ها در همان چند ثانیهٔ ری‌استارت گم می‌شود، مثل هر ری‌استارت دیگری. یک Ctrl+C یا docker stop وسط ری‌استارت برنده است: aipager می‌ایستد و دوباره شروع نمی‌شود. اگر aipager جدید درجا شروع نشود، یک نسخهٔ جدا بعد از رفتن نسخهٔ قدیمی شروعش می‌کند (خروجی‌اش در لاگ ری‌استارت خودکار نوشته می‌شود، یعنی aipager.log در پوشهٔ همان نصب یا ‎/tmp/aipager.log، و اگر آن نسخه برنگردد، لاگ aipager دستوری را که باید اجرا کنید می‌گوید)؛ اگر این هم نشود، یا خود مفسر از بین رفته باشد، aipager با کد 1 خارج می‌شود و لاگ aipager با دستوری که باید اجرا کنید restart.failed:‎ را می‌گوید.

وقتی aipager اصلاً نمی‌تواند خودش را ری‌استارت کند، پیام به‌جای دکمه قدم‌های دقیق مخصوص راه‌اندازی شما را می‌دهد:

  • ترمینال یا tmux: در ترمینال یا پنجرهٔ tmux که aipager در آن اجرا می‌شود، Ctrl+C را بزنید و بعد aipager start را اجرا کنید.
  • ‏macOS: روی مک، launchctl kickstart -k gui/<uid>/com.aipager.daemon را اجرا کنید.
  • ‏Docker: روی کامپیوتری که Docker روی آن اجرا می‌شود، docker restart <container> را اجرا کنید. (اگر اسم میزبان کانتینر شناسهٔ کوتاه آن باشد، همان شناسه)، با یادآوری اینکه ساختن دوبارهٔ کانتینر از روی ایمیجش نسخهٔ aipager همان ایمیج را برمی‌گرداند.

دکمهٔ همین حالا ری‌استارت کن وقتی یک aipager جدیدتر نصب شده و منتظر است، در نتیجهٔ چک کردن آپدیت هم می‌آید، و در یک اعلان یک‌باره هم: وقتی هوک‌های Claude Code (که در هر رویداد از نو از روی aipager نصب‌شده شروع می‌شوند) همین حالا یک aipager جدیدتر از aipager در حال اجرا را اجرا می‌کنند، مالک برای هر نسخهٔ جدیدتر و هر بار اجرای aipager یک پیام بی‌صدا با همان دکمه می‌گیرد: ⚠️ آپدیت aipager نیمه‌کاره مانده: …. این پیام از لحظه‌ای که هوک‌ها اولین بار نسخهٔ جدیدتر را اجرا کردند دو دقیقه صبر می‌کند (ری‌استارتی که درست بعد از نصب بیاید هیچ‌وقت آن را نشان نمی‌دهد)، بعد صبر می‌کند تا هیچ کاری در چت خصوصی مالک در جریان نباشد. بعد از ری‌استارت به آن نسخه، اعلان بدون دکمه به ✅ آپدیت aipager تمام شد: حالا aipager نسخهٔ B است. تبدیل می‌شود. در Mini App، تنظیمات ← آپدیت همین وضعیت را به‌شکل یک خط بالای کارت نشان می‌دهد، با همین حالا ری‌استارت کن (اول می‌پرسد).

در Mini App، آپدیت اولین کارت تب تنظیمات است: اسمش، نسخهٔ در حال اجرا، و یک چک کردن آپدیت کوچک آخر همان ردیف. باز کردن تب تنظیمات خودش چک می‌کند (حداکثر هر ده دقیقه یک بار، هیچ‌وقت وقتی آپدیتی در جریان است یا aipager در حال ری‌استارت است؛ اگر چک کردن آنجا شکست بخورد چیزی نمی‌گوید)، و زدن دکمه همیشه چک می‌کند. کارت تا وقتی کاری برای انجام نباشد یک ردیف آرام می‌ماند: نسخهٔ جدیدتر خط‌های خودش و همان یک دکمهٔ آپدیت را می‌آورد، «همه چیز آپدیت است.» یک خط تنها بدون دکمه است، و آپدیتِ در جریان، یک ری‌استارت یا همین حالا ری‌استارت کن دکمه‌های خودشان را نگه می‌دارند.

هر بار فقط یک آپدیت اجرا می‌شود، در کل ‎/update، کارت تنظیمات ← آپدیت در Mini App (همان چک کردن، همان یک دکمهٔ آپدیت، همان کار) و aipager update در خط فرمان. این شامل ثانیه‌های بین «نصب شد، در حال ری‌استارت…» و خود ری‌استارت هم می‌شود: ‎/update جواب می‌دهد که aipager دارد ری‌استارت می‌شود، Mini App هیچ دکمه‌ای پیشنهاد نمی‌دهد، و ری‌استارت aipager در قابلیت ویس وقتی یک آپدیت اجرا می‌شود یا منتظر ری‌استارت است رد می‌کند. اگر aipager دو دقیقه بعد از زمان‌بندی ری‌استارتش هنوز زنده باشد، تایمر ری‌استارت منتظر را متوقف می‌کند، قفل آپدیت را آزاد می‌کند، و می‌گوید خودتان ری‌استارتش کنید.

اگر aipager وقتی یک نصب‌کننده اجرا می‌شود خاموش شود، نصب‌کننده ۳ ثانیه فرصت دارد تمام شود و بعد متوقف می‌شود (وگرنه وقتی aipager بعدی شروع می‌شود همچنان روی نصب می‌نوشت). پیام وضعیت و، بعد از ری‌استارت، یک پیام جدید می‌گویند ممکن است نصب نیمه‌کاره باشد و چطور تعمیرش کنید.

وقتی خاموش شدن شروع شد، هیچ چیزی ری‌استارت نمی‌شود و هیچ چیز جدیدی شروع نمی‌شود: دکمه‌های ‎/update جواب می‌دهند که aipager دارد خاموش می‌شود، Mini App با 503 جواب می‌دهد، و هیچ نصب‌کننده یا بررسی نسخه‌ای شروع نمی‌شود. نصب‌کننده‌ای که در همان ۳ ثانیه‌اش تمام شود همچنان حساب می‌شود. پیام وضعیت می‌گوید نسخهٔ جدید نصب شده و هیچ چیزی ری‌استارت نشده، و شروع بعدی اعلام می‌کند aipager A ← B آپدیت شد.‏ aipagerی که با aipager service stop متوقفش کرده‌اید متوقف می‌ماند. سهم آپدیت از خاموش شدن روی هم حداکثر ۸ ثانیه طول می‌کشد.

پیام‌های آزاد#

متن#

به‌عنوان پیام بعدی برای سشن فعال حساب می‌شود: مقصد این چت، یعنی سشنی که آخرین بار به آن رفتید، به آن پیام دادید، شروعش کردید، یا آخرین بار اینجا جوابتان را داد (نوار وضعیت سنجاق‌شده را ببینید). در گروه، هر کس مقصد خودش را دارد که جواب یک سشن آن را جابه‌جا نمی‌کند (استفادهٔ تیمی را ببینید). پیام‌ها فوراً به Claude می‌رسند، حتی وقتی کار خودتان در جریان است، درست مثل تایپ کردن در ترمینال (در گروه، پیام کس دیگری منتظر تمام شدن آن کار می‌ماند؛ پایین را ببینید). چند پیام بفرستید و داخل خود Claude در صف قرار می‌گیرند، که هر کدام را در یک نقطهٔ مناسب برمی‌دارد:

ری‌اکشن روی پیامتان همراهش جلو می‌رود، همان‌طور که پیام صف‌شده در خود Claude Code از خاکستری به سفید می‌رود:

  • 👀: به سشن ارسال شد (یا نگه داشته شد، پایین را ببینید)، ولی Claude هنوز برش نداشته. پیامی که وقتی یک کار در جریان است فرستاده شود، تا وقتی در صف Claude منتظر است 👀 می‌ماند.
  • ‏👍: Claude برش داشت: یک کار را با آن شروع کرد، یا آن را وارد کار در جریان کرد، یا به یک ایجنت پس‌زمینهٔ در حال کار داد.
  • 🤷: هیچ‌وقت برداشته نمی‌شود: پیام نگه‌داشته‌شده‌ای که ‎/stop،‏ ‎/clearqueue یا ‎/kill دور ریخته، یا موقع آزاد شدن فرستاده نشد؛ پیام یا فرمانی که هنوز منتظر بود وقتی ‎/stop،‏ ‎/clearqueue،‏ ‎/kill یا بسته شدن سشن (نه ‎/clear یا ‎/resume) دور ریختش؛ یا پیامی که Claude Code ردش کرد (پایین را ببینید). پیام‌هایی که Claude قبلاً در صف گذاشته فقط تا وقتی علامت می‌خورند که aipager آن صف را می‌بیند (یعنی گشتن زندهٔ گفتگوی ذخیره‌شده اجرا می‌شود و هیچ کار پس‌زمینه‌ای منتظر نیست)؛ وگرنه 👀 می‌مانند. Escape در ترمینال صف Claude را به جای نوشتنش برمی‌گرداند، جایی که ممکن است دوباره فرستاده شود، پس پیامی که این‌طور کنار رفته هم 👀 می‌ماند.
  • 👌: یک فرمان Claude Code که اجرا شده (پایین را ببینید)، یا تأیید ‎/stop توسط aipager.

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

دکمه‌های فرمان (کامپکت گفتگو، ‎/model …‎): اگر وقتی سشن آماده است زده شوند، فرمان فوراً 👌 می‌گیرد؛ Claude Code آن را با Enter اجرا می‌کند، و یک فرمان محلی مثل ‎/model هیچ هوکی نمی‌فرستد که بعداً این را بگوید. اگر وقتی یک کار در جریان است زده شوند (نه ‎/model: تا تمام شدن کار رد می‌شود، عوض کردن مدل یک سشن در حال اجرا را ببینید)، تا تمام شدن آن کار 👀 می‌ماند (به‌شکل عادی، به‌شکل توقف موقت یک کار پس‌زمینه، یا با یک خطای API) و بعد 👌؛ اگر قبل از آن ‎/stop،‏ ‎/clearqueue،‏ ‎/kill یا بسته شدن سشن دور بریزدش، هیچ‌وقت اجرا نشد: 🤷. وقتی Claude Code آن را به‌عنوان یک پیام در صف می‌گذارد، همان مسیر 👀 ← 👍 را می‌رود. یک ویس بعد از اینکه متنش فرستاده شد همان ری‌اکشن‌های متن را می‌گیرد.

کارت در حال کار و جواب نهایی دنبال پیامی می‌روند که Claude واقعاً برای یک کار برداشته (پیامی که اگر سشن آماده بود با آن شروع کرد، یا پیامی که وارد کار در جریان کرد)، هیچ‌وقت صرفاً آخرین پیامی که فرستادید. فرستادن یک پیام دیگر وسط کار «جواب را به خودش نمی‌کشد»: اگر Claude آن را وارد جوابی که دارد شکل می‌گیرد کند، کارت همان لحظه به آن می‌پرد؛ اگر Claude اول تمامش کند و بعد برش دارد، جواب اول زیر پیام اول می‌ماند و پیام بعدی کار خودش را می‌گیرد، با کارت و جواب خودش زیرش.

اگر Claude Code یک پیام را کلاً رد کند (یک فرمان اسلش ناشناخته، یا یک فرمان داخلی که فقط یک پنجره در ترمینال باز می‌کند)، هیچ هوکی نمی‌آید، پس هیچ چیزی کاری را که aipager همین الان اعلام کرده تمام نمی‌کرد. بعد از ۸ ثانیه بدون هیچ هوکی (PROMPT_HOOK_GRACE_SECONDS)، کارت در حال کار به ⚠️ name · Claude Code پیام را تحویل نگرفت با یک توضیح یک‌خطی تبدیل می‌شود و سشن دوباره آماده می‌شود؛ دلیلش در ترمینال است، و پیام 🤷 می‌گیرد (یک فرمان اسلش به جایش 👌 می‌گیرد: فرمان داخلی‌ای که یک پنجره باز می‌کند هم هیچ هوکی نمی‌فرستد). فقط پیامی که یک کار را شروع کرده این‌طور قضاوت می‌شود؛ پیامی که پشت یک کار در جریان در صف است تا وقتی Claude برش دارد یا دور ریخته شود 👀 را نگه می‌دارد.

سه حالت به جای فرستاده شدن نگه داشته می‌شوند و وقتی برطرف شدند خودکار فرستاده می‌شوند:

  • یک درخواست اجازه یا سؤال باز است، تا هر وقت که باز بماند (محدودیت زمانی ندارد): متن شما وگرنه جواب آن پنجره حساب می‌شد. اولین پیامی که آن موقع می‌فرستید یک جواب زیر همان درخواست می‌گیرد که می‌گوید Claude هنوز منتظر جواب شماست (پیام‌های بعدی فقط 👀 می‌گیرند). همین که جواب بدهید، در تلگرام یا در ترمینال، پیام‌های نگه‌داشته‌شده به همان ترتیبی که فرستادید برای Claude ارسال می‌شوند و آن جواب حذف می‌شود. اگر سشن تمام شود و درخواست هنوز باز باشد، آن پیام‌ها با یک 🤷 کنار گذاشته می‌شوند.
  • (استفادهٔ تیمی) پیام نفر دیگری هنوز منتظر برداشته شدن است.
  • (استفادهٔ تیمی) کار نفر دیگری در جریان است، از جمله یک ایجنت پس‌زمینه که شروع کرده. کاری که در ترمینال تایپ شده مال مالک حساب می‌شود، پس فقط پیام یک مالک (یا، در چت خصوصی، پیام عضو همان چت) به آن اضافه می‌شود.

دو تای آخر پیام‌های آدم‌های مختلف را از یک کار بیرون نگه می‌دارند تا هر کدام با اختیارات فرستندهٔ خودش اجرا شود. اگر باز هم یکی اضافه شود (مثلاً فرستنده‌ای که aipager نمی‌شناسد و هیچ‌وقت نگه داشته نمی‌شود)، کار با سخت‌ترین قانون‌های همهٔ کسانی که در آن هستند اجرا می‌شود (استفادهٔ تیمی را ببینید). اگر کاری که پیام منتظرش است متوقف شود، یا با یک ابزار مسدود متوقف شود، پیام‌های نگه‌داشته‌شده با یک 🤷 دور ریخته می‌شوند.

پیام‌های نگه‌داشته‌شده برای هر سشن حداکثر ۵۰ تا هستند و بعد از ۲۴ ساعت منقضی می‌شوند؛ ‎/clearqueue آن‌ها را همراه هر چه Claude نگه داشته دور می‌ریزد.

فرستادن فوری یک پیام صف#

پیامی که وقتی Claude روی کار خودتان کار می‌کند می‌فرستید، فوراً به Claude می‌رسد (aipager نگهش نمی‌دارد) و تا تمام شدن قدم فعلی در صف Claude منتظر می‌ماند. همین که صف Claude آن را نشان دهد، aipager زیرش جواب می‌دهد:

text
⏳ در صف - Claude بعد از قدم فعلی آن را می‌خواند
[⚡ همین حالا بفرست]

هر پیام صف‌شده خط خودش را می‌گیرد، و هر خط، با 👍 آن، همان لحظه که Claude آن پیام را برمی‌دارد ناپدید می‌شود. پیامی که Claude قبل از دیده شدن رکورد صفش برمی‌دارد هیچ خطی نمی‌گیرد، فقط 👀 و بعد 👍.

زدن ⚡ همین حالا بفرست (یا فرستادن ‎/now) کلیدهای ارسال فوری خود Claude Code (Ctrl+X، بعد Ctrl+S) را در آن سشن می‌زند. آن‌وقت Claude هر چه در صف دارد را با هم می‌خواند، نه فقط پیامی که زدید. اینکه با کار در جریان چه می‌شود انتخاب خود Claude Code است: یک دستور یا ایجنت در حال اجرا در پس‌زمینه ادامه می‌دهد؛ اگر Claude وسط نوشتن یک جواب باشد، آن جواب نیمه‌کاره می‌ماند و با پیام شما از نو شروع می‌شود. هر نوع قدم دیگری (مثلاً ابزاری دیگر) ممکن است بعد از کمی فرصت قطع شود. در بعضی حالت‌ها (مثلاً وقتی کارهای پس‌زمینهٔ Claude Code خاموش است) ارسال فوری به یک قطع سادهٔ قدم در جریان برمی‌گردد. همهٔ این‌ها رفتار ارسال فوری خود Claude Code است، نه چیزی که aipager تصمیم می‌گیرد.

زدن دکمه جواب می‌دهد همین حالا برای Claude ارسال شد و همهٔ خط‌ها همان لحظه ناپدید می‌شوند، چون ارسال فوری هر چه Claude نگه داشته را به آن می‌دهد؛ ‎/now هم همین‌طور برشان می‌دارد، و برای پیام‌هایی که «همین حالا بفرست» فرستاد خطی نمی‌آید (پیامی که بعد از آن بفرستید خط خودش را می‌گیرد). اگر Claude به جای بردن قدم در جریان به پس‌زمینه لغوش کند، فقط قدیمی‌ترین پیام صف را فوراً برمی‌دارد و بقیه را در قدم بعدی می‌خواند؛ جواب زیر همان پیامی ارسال می‌شود که برداشته، و آن پیام دو بار اجرا نمی‌شود. اگر رسیدن کلیدها به Claude بیشتر از یک لحظه طول بکشد (کامپیوتر شلوغ)، زدن دکمه به جایش جواب می‌دهد در حال ارسال به Claude؛ آن‌وقت خط وقتی کلیدها رسیدند ناپدید می‌شود، یا اگر نرسیدند، می‌ماند و می‌گوید ⏳ در صف - به Claude نرسید؛ «همین حالا بفرست» را دوباره بزنید، با دکمه‌اش، تا دوباره بزنید. کلیدها فقط وقتی زده می‌شوند که گفتگوی ذخیره‌شدهٔ Claude نشان دهد هنوز آن پیام را نگه داشته؛ وگرنه زدن دکمه جواب می‌دهد Claude قبلاً آن را برداشته و خط را برمی‌دارد. بدون زدن هیچ کلیدی رد می‌شود وقتی یک درخواست اجازه یا سؤال باز است (اول جواب سؤال باز را بدهید)، وقتی Claude ممکن است همین الان یکی باز کرده باشد که aipager هنوز نشانش نداده (رویدادهای یک کار جدید وقتی جواب کار قبلی هنوز در حال فرستاده شدن است نگه داشته می‌شوند: فعلاً مشغول است، چند لحظه بعد دوباره امتحان کنید)، و وقتی aipager وسط تایپ کردن پیام دیگری در سشن است (aipager دارد پیامی را تایپ می‌کند، چند لحظه بعد دوباره امتحان کنید). هر کسی که می‌تواند به آن سشن پیام بفرستد می‌تواند از دکمه و ‎/now استفاده کند؛ یک عضو read_only نمی‌تواند.

خط وقتی پیامش از صف Claude بیرون برود خودش ناپدید می‌شود: Claude برش می‌دارد (وارد کار در جریان می‌شود، به یک ایجنت پس‌زمینه داده می‌شود، یا به‌عنوان کار بعدی شروع می‌شود)، Escape در ترمینال صف را به جای نوشتن برمی‌گرداند، یا ‎/stop،‏ ‎/clearqueue،‏ ‎/kill،‏ ‎/restart، یک توقف ایمنی یا بسته شدن سشن دورش می‌ریزد. ری‌استارت aipager هر خطی را که هنوز دیده می‌شود برمی‌دارد.

این خط‌ها هیچ‌وقت منتظر مدیر سهمیهٔ ارسال نمی‌مانند: حتی در یک چت شلوغ یا کند، و در مود حداقلی، فوراً فرستاده و برداشته می‌شوند. فقط وقتی خود تلگرام چت را ساکت کرده هیچ خطی فرستاده نمی‌شود (‎/now آن موقع هم کار می‌کند)، و اگر تلگرام همین الان از aipager خواسته کندتر بفرستد، یک خط همان چند ثانیه‌ای که خواسته صبر می‌کند. هر پیام منتظر یک درخواست به چت برای خطش هزینه دارد؛ خط‌هایی که به هم مربوط‌اند با یک درخواست برداشته می‌شوند.

فایل‌ها#

فایل‌های آپلودشده در یک پوشهٔ خصوصیِ مخصوص چتی که از آن آمده‌اند دانلود می‌شوند، ‎/tmp/aipager-files/<chat>/‎ (با اسم ‎<time>_<file name>‎؛‏ ‎<chat>‎ اسمی است که از آیدی چت و توکن ربات ساخته می‌شود و آیدی چت را لو نمی‌دهد). این پوشه‌ها فقط برای کاربری که aipager با آن اجرا می‌شود خواندنی‌اند (0700، فایل‌ها 0600)، و کار یک عضو در یک چت نمی‌تواند آپلودهای چت دیگری را بخواند، در آن‌ها جست‌وجو کند یا در آن‌ها بنویسد (مدل امنیتی را ببینید). فایل‌های قبل از این تغییر همان‌جا که بودند می‌مانند، یعنی مستقیم در ‎/tmp/aipager-files/‎؛ هیچ چیزی جابه‌جا یا پاک نمی‌شود، و aipager موقع شروع دسترسی این پوشه را به 0700 محدود می‌کند تا فقط همان کاربر به آن فایل‌ها برسد. یک توکن ربات جدید به هر چت یک پوشهٔ جدید می‌دهد؛ آپلودهای قبل از آن در پوشه‌های قبلی می‌مانند و کار یک عضو دیگر نمی‌تواند آن‌ها را بخواند. پوشهٔ دانلودی که symlink باشد یا مال کاربر دیگری باشد رد می‌شود و آپلود انجام نمی‌شود. مسیر فایل به Claude داده می‌شود: با کپشن، پیام همان کپشن و بعد مسیر(ها)ست؛ بدون کپشن فقط check this: <path>‎ است (یا برای یک آلبوم check these: <paths>‎)، تا Claude به فایل اشاره داده شود بدون اینکه گفته شود با آن چه کند. کپشنی که با ‎/<label>‎ شروع شود سشن را انتخاب می‌کند، دقیقاً مثل ‎/<label> <prompt>‎ برای متن، و برچسب از پیام حذف می‌شود: ‎/api تنها check this: <path>‎ را به api می‌فرستد، و ‎/api compare these همان‌جا compare these <paths>‎ را. فقط یک ‎/<label>‎ در اول مسیر را تعیین می‌کند؛ اسلشی که جای دیگری از کپشن بیاید فقط متن است. برچسبی که هیچ سشنی به آن جواب نمی‌دهد با ⚠️ سشنی به این اسم نیست رد می‌شود و چیزی فرستاده نمی‌شود. سقف ۲۰ مگابایتی دانلود فایل ربات‌ها در تلگرام از اول اعمال می‌شود؛ فایل‌های بزرگ‌تر قبل از هر تلاشی برای دانلود یک رد روشن می‌گیرند. دانلودی که به یک خطای گذرای شبکه بخورد روی هم تا سه بار امتحان می‌شود (۱ ثانیه و بعد ۲ ثانیه صبر) و بعد خطا را می‌بینید، که اسم فایل را می‌آورد. یک آلبوم (چند عکس یا سند که به‌شکل یک پیام فرستاده شده‌اند) وقتی آخرین آیتمش رسید، به‌شکل یک پیام به Claude داده می‌شود (کپشن، و بعد همهٔ مسیرهای فایل به ترتیب)؛ اگر یک آیتم دانلود نشود، بقیه باز هم فرستاده می‌شوند، با یک یادداشت که اسم آیتمِ جاافتاده را می‌آورد.

فایل‌هایی که Claude می‌فرستد#

‏Claude می‌تواند از سشنش برایتان فایل بفرستد: با حرف خودتان بخواهید («اسکرین‌شات را برام بفرست»، «عکسی که در ‎~/proj/chart.png هست را برام بفرست»)، یا هر وقت فکر کند لازمش دارید خودش می‌فرستد. برای این کار از ابزار SendUserFile در Claude Code استفاده می‌کند (Claude Code نسخهٔ 2.1.301 یا بالاتر)، که هر سشنی که aipager باز می‌کند آن را دارد: aipager سشن را با CLAUDE_CODE_ATTACHMENTS_BY_PATH=1 باز می‌کند و به Claude می‌گوید این ابزار را دارد. سشنی که قبل از اینکه aipager شما این قابلیت را داشته باشد باز شده، فقط بعد از ری‌استارت این ابزار را می‌گیرد: ‎/restart، عوض کردن مودی که سشن را ری‌استارت کند، یا ادامه دادن سشن.

  • فایل‌ها بعد از جواب کار می‌رسند، به‌شکل جواب به همان پیام (اگر کار جوابی نداشته باشد، به پیام خود شما)، بی‌صدا، و فقط در چت خود همان سشن. تا کار در حال اجراست، کارت کار 📎 در حال ارسال ۲ فایل را نشان می‌دهد.
  • هر فایل بر اساس محتوایش فرستاده می‌شود، نه اسمش: عکس اگر در محدودیت‌های عکس تلگرام جا شود به‌شکل عکس (حداکثر ۱۰ مگابایت، جمع عرض و ارتفاع حداکثر ۱۰٬۰۰۰، ضلع بلند حداکثر ۲۰ برابر ضلع کوتاه)، وگرنه به‌شکل فایل؛ GIF به‌شکل انیمیشن؛ MP4 به‌شکل ویدیو؛ MP3 یا M4A به‌شکل صوت؛ و بقیه به‌شکل فایل. اگر Claude یک پیوست ساده بخواهد، همه‌چیز به‌شکل فایل فرستاده می‌شود.
  • ۲ تا ۱۰ عکس و ویدیو با هم یک آلبوم می‌شوند؛ فایل‌ها با فایل‌ها و صوت‌ها با صوت‌ها فرستاده می‌شوند؛ انیمیشن جدا فرستاده می‌شود. اگر بیشتر باشند به‌طور مساوی تقسیم می‌شوند (۱۱ تا به‌شکل ۶ و ۵ فرستاده می‌شوند)، و هیچ آلبومی از ۵۰ مگابایت بیشتر نیست.
  • کپشن ‎💬 <session>‎ است، و کپشن خود Claude در خط بعدی پیام اول می‌آید، حداکثر ۱٬۰۲۴ کاراکتر.
  • هر فایل اول چک می‌شود، برای همه، owner هم (امنیت): تنظیمات aipager، اطلاعات ورود Claude، کلیدها و فایل‌هایی که شبیه رمز و اطلاعات محرمانه‌اند هیچ‌وقت فرستاده نمی‌شوند؛ فایل باید یک فایل معمولی باشد، خالی نباشد و حداکثر ۵۰ مگابایت باشد؛ یک عضو فقط فایل‌های داخل پوشهٔ root چت را می‌فرستد. اگر یک فایلِ یک درخواست رد شود، هیچ چیزی از آن درخواست فرستاده نمی‌شود: Claude دلیلش را می‌فهمد و به شما می‌گوید، و کار ادامه پیدا می‌کند.
  • ‏aipager یک کپی خصوصی را می‌فرستد که همان لحظه‌ای که Claude Code فایل را خواند گرفته است؛ این کپی در ‎~/.local/state/aipager/outbox/‎ نگه داشته می‌شود و بعد از ارسال، یا بعد از یک روز، پاک می‌شود.
  • ‏aipager هیچ سقف تعدادی از خودش ندارد: ارسال‌ها با سرعت مجاز تلگرام فرستاده می‌شوند، و هر آلبوم به ازای هر فایل یکی حساب می‌شود. تا وقتی چت محدود شده، فایل‌ها صبر می‌کنند و بعد از جواب می‌رسند.
  • فایلی که فرستاده نشود یک خط در چت می‌گیرد، مثلاً ⚠️ report.pdf ارسال نشد: Telegram آن را قبول نکرد. فایلی که aipager درخواستش را در گفتگوی ذخیره‌شدهٔ خود Claude پیدا نکند هیچ خطی نمی‌گیرد (امنیت). فایلی که درخواستش آن‌جا هست ولی aipager نمی‌تواند آن را به کارِ در جریان ربط بدهد، این خط را می‌گیرد: ⚠️ report.pdf ارسال نشد: aipager نتوانست مطمئن شود که Claude آن را در همین کار فرستاده است. فایل‌ها از پیامی هم می‌آیند که وقتی Claude در حال کار است می‌فرستید و آن را کار بعدی‌اش می‌کند، و از کاری که یک hook از نوع Stop ادامه‌اش می‌دهد (‎/goal). هر فایلی که فرستاده، رد یا ناموفق شده، رکورد خودش را در لاگ ممیزی دارد.

ویس#

ویس‌ها از faster-whisper (افزونهٔ aipager[voice]) می‌گذرند. صدا روی همین کامپیوتر به متن تبدیل می‌شود، به‌شکل 🎙️ شنیدم: … برگردانده می‌شود، و طوری فرستاده می‌شود که انگار خودتان تایپش کرده بودید، از جمله به‌عنوان اسم برای ‎/new یا یک تغییر اسم منتظر. ویسی بزرگ‌تر از سقف ۲۰ مگابایتی دانلود ربات‌ها در تلگرام رد می‌شود. برای اینکه بعد چه اتفاقی می‌افتد، هوک‌ها ← UserPromptSubmit را ببینید.


خط فرمان: همهٔ دستورها#

برای همین فهرست روی کامپیوتر خودتان، aipager <command> --help را اجرا کنید.

دستورچه کار می‌کند
aipager configویزارد تنظیمات با سؤال و جواب: توکن ربات، چت‌ها، اعضا و نقش‌ها، هوک‌های Claude Code. برای عوض کردن هر چیزی دوباره اجرایش کنید (استفادهٔ تیمی را ببینید).
aipager setupهمان راه‌اندازی اول بدون هیچ سؤالی، برای اسکریپت‌ها و ایجنت‌های برنامه‌نویسی (پایین را ببینید).
aipager startaipager را در همان ترمینال اجرا می‌کند. وقتی aipager دیگری اجرا می‌شود شروع نمی‌شود.
aipager service install [--yes]aipager را به‌شکل سرویس پس‌زمینه نصب و اجرا می‌کند (سرویس systemd کاربری روی Linux، ایجنت launchd روی macOS). ‎--yes از سؤال وقتی سرویس نصب‌شده فرق دارد رد می‌شود.
aipager service start|stop|status|logs|uninstallسرویس را شروع، متوقف یا نشان می‌دهد، لاگش را دنبال می‌کند، یا برش می‌دارد.
aipager status [--json]aipager و همهٔ سشن‌ها در یک نگاه: وضعیت، مدل، کانتکست، هزینه، و وضعیت محدودیت سرعت تلگرام.
aipager logs [-f] [-n LINES]لاگ aipager (journald روی Linux، لاگ launchd روی macOS): ۱۰۰ خط آخر، یا ‎-n خط؛ ‎-f دنبالش می‌کند.
aipager doctor [--fix] [--safety-check] [--json]بررسی‌های سلامت (رفع مشکل را ببینید). ‎--fix پیشنهاد می‌کند اطلاعات ورود Claude و یک نصب مبهم claude را درست کند، اول با پرسیدن؛ ‎--safety-check قانون‌های ایمنی در حال اجرا را چاپ می‌کند؛ ‎--json برای اسکریپت‌هاست (پایین را ببینید).
aipager session <name> [claude args]یک سشن Claude Code به اسم ‎<name>‎ زیر dtach در پوشهٔ فعلی شروع می‌کند، یا اگر در حال اجراست به آن وصل می‌شود. آرگومان‌های بعد از اسم (یا بعد از --) همان‌طور که هستند به claude داده می‌شوند، مثلاً ‎--resume.‏ aipager در حال اجرا لازم دارد.
aipager session ls [-a] [--json]سشن‌ها را فهرست می‌کند؛ ‎-a بسته‌شده‌ها را هم می‌آورد. aipager session list هم هست.
aipager session kill <name> [-y]یک سشن را می‌بندد، بعد از یک سؤال مگر با ‎-y.
aipager resume [name]یک سشن بسته‌شده را با گفتگویش برمی‌گرداند؛ بدون اسم، یک فهرست انتخاب.
aipager miniapp enable [--port PORT] [--url URL]Mini App را روشن می‌کند، روی ‎127.0.0.1:PORT (پیش‌فرض 8765)، پشت تونل مدیریت‌شده یا آدرس https://‎ خودتان. از ری‌استارت بعدی aipager اعمال می‌شود.
aipager miniapp disable|statusخاموشش می‌کند (از ری‌استارت بعدی)، یا تنظیمات و آدرسش را نشان می‌دهد.
aipager policy validatepolicy.yaml (و policy.d) را چک می‌کند؛ با یک مشکل با کد غیرصفر خارج می‌شود.
aipager updateaipager را از طریق نصب‌کننده‌ای که صاحبش است آپدیت می‌کند (uv،‏ pipx،‏ Homebrew،‏ pip). هیچ‌وقت aipager را ری‌استارت نمی‌کند؛ خودتان ری‌استارتش کنید، یا از ‎/update در تلگرام استفاده کنید که می‌تواند (آپدیت را ببینید).
aipager report [--note TEXT]یک گزارش مشکل را نشان می‌دهد و اگر بله بگویید می‌فرستدش (پایین را ببینید).
aipager uninstall [-y]aipager و تنظیماتش را متوقف و حذف می‌کند و داده‌هایش را نگه می‌دارد (پایین را ببینید).
aipager version،‏ aipager --versionنسخه را چاپ می‌کند.
aipager help [command]راهنمای aipager یا یک دستور.

خط فرمان: aipager setup (برای ایجنت‌های برنامه‌نویسی)#

بخش‌های بالا ربات تلگرام را توضیح می‌دهند. این بخش دستوری را توضیح می‌دهد که در ترمینال اجرا می‌کنید، یا یک اسکریپت یا ایجنت برنامه‌نویسی برایتان اجرا می‌کند: aipager setup aipager را بدون هیچ سؤالی راه می‌اندازد و همان نتیجهٔ اولین اجرای aipager config را می‌دهد.

sh
# 1. آیدی تلگرام آن شخص را پیدا کنید (ربات را باز می‌کند و Start را می‌زند)
aipager setup detect-chat --token-file ~/bot-token.txt --json
# 2. وقتی تأیید کرد خودش است، aipager را راه بیندازید
aipager setup --token-file ~/bot-token.txt --chat-id 123456789 --service --json
# 3. نصب را چک کنید
aipager doctor --json

چه کار می‌کند، به این ترتیب: توکن ربات را می‌خواند، آن را با تلگرام چک می‌کند (getMe)، همه‌چیز را روی این کامپیوتر بدون نوشتن چک می‌کند (تنظیمات موجود، وابستگی‌ها، ‎~/.claude/settings.json، اینکه aipagerی اجرا می‌شود یا نه)، یک پیام آزمایشی برای آن شخص می‌فرستد ("aipager is set up for you. ...")، و فقط بعد می‌نویسد. فایل‌هایی که می‌نویسد، همان‌طور که ویزارد می‌نویسد:

  • ‏‎~/.config/aipager/aipager.yaml (حالت دسترسی 0600): bot_token و یک چت خصوصی که تنها عضوش همان شخص است (label: owner، نقش owner یا admin).
  • ‏‎~/.claude/settings.json: هوک‌های aipager و statusLine (وقتی فایل موجود عوض شود، یک نسخهٔ پشتیبان settings.json.bak.<time>‎ از آن گرفته می‌شود).
  • وقتی کسی مالک می‌شود، لاگ ممیزی یک رکورد grant-owner می‌گیرد.
  • با ‎--service، سرویس پس‌زمینه (همان aipager service install --yes).
  • فقط روی یک نصب قدیمی config.env (هنوز بدون aipager.yaml)، همان انتقالی که ویزارد انجام می‌دهد: یک کپی config.env.bak.<time>‎ (و team.yaml.bak.<time>‎ وقتی team.yaml هست)، و یک ‎~/.config/aipager/policy.yaml شروع وقتی هیچ‌کدام نیست. خود config.env همان‌طور که هست می‌ماند.

اگر هر بررسی‌ای شکست بخورد، هیچ چیزی فرستاده و نوشته نمی‌شود. وقتی aipager از قبل اجرا می‌شود، تغییر چت یا نقش بدون ری‌استارت خوانده می‌شود؛ یک توکن ربات جدید ری‌استارت لازم دارد (aipager service stop، بعد aipager service start)، که setup هیچ‌وقت خودش انجام نمی‌دهد، و ‎--service رد می‌شود. اگر setup نتواند بفهمد aipagerی اجرا می‌شود یا نه، طوری رفتار می‌کند که انگار اجرا می‌شود (هشدار daemon_unknown): آن‌وقت هیچ‌وقت سرویس را نصب نمی‌کند، تا هیچ‌وقت نتواند یک aipager زنده را ری‌استارت کند، و بعد از هر تغییری هیچ سیگنال خواندن دوباره‌ای نمی‌فرستد و به جایش restart_needed: true را گزارش می‌دهد.

فلگ‌های aipager setup#

فلگمعنی
‎--token-file PATHتوکن ربات را از این فایل می‌خواند (حداکثر ۴۰۹۶ بایت؛ متن اطراف یک توکن مشکلی ندارد). فایلی که کاربرهای دیگر می‌توانند بخوانند کار می‌کند ولی هشدار token_file_shared می‌دهد: chmod 600 کنید، یا وقتی setup موفق شد پاکش کنید.
‎--token-stdinتوکن ربات را از stdin می‌خواند (یک pipe یا فایل redirect‌شده، هیچ‌وقت ترمینال). pipe باید بسته شود: setup حداکثر ۳۰ ثانیه منتظر پایان stdin می‌ماند و بعد با token_stdin_timeout و کد ۲ خارج می‌شود. printf '%s\n' "$TOKEN" | aipager setup --token-stdin ...‎ و ‎< token.txt هر دو آن را می‌بندند.
‎--chat-id Nالزامی. آیدی عددی کاربر تلگرام آن شخص، که همان آیدی چت خصوصی‌اش هم هست. گروه‌ها با aipager config اضافه می‌شوند.
‎--role owner|adminنقش آن شخص (پیش‌فرض owner).
‎--serviceسرویس پس‌زمینه را هم نصب و اجرا می‌کند (وقتی aipagerی اجرا می‌شود رد می‌شود).
‎--forceاجازه می‌دهد توکن ربات، چت خصوصی مالک، یا نقش یک نصب موجود عوض شود. چت‌های گروهی و بقیهٔ چت‌های خصوصی می‌مانند.
‎--dry-runهمهٔ بررسی‌ها را اجرا می‌کند، هیچ چیزی نمی‌فرستد، هیچ چیزی نمی‌نویسد، و گزارش می‌دهد چه چیزی عوض می‌شد.
‎--jsonدقیقاً یک شیء JSON روی stdout چاپ می‌کند؛ بقیه به stderr می‌رود.

دقیقاً یکی از ‎--token-file و ‎--token-stdin را بدهید. توکن هیچ‌وقت به‌عنوان مقدار یک فلگ پذیرفته نمی‌شود: ‎--token و ‎--bot-token رد می‌شوند (token_on_command_line) و مقدار نشان داده نمی‌شود. فلگ‌های کوتاه‌شده (‎--token-f،‏ ‎--dry) پذیرفته نمی‌شوند. setup هیچ‌وقت سؤالی نمی‌پرسد، هیچ‌وقت ترمینال لازم ندارد، و هیچ‌وقت توکن را از یک متغیر محیطی نمی‌خواند.

اجرای دوباره با همان توکن، چت و نقش هیچ چیزی را عوض نمی‌کند و همین را می‌گوید (unchanged، بدون پیام آزمایشی). یک توکن، چت یا نقش متفاوت روی یک نصب موجود با کد ۶ خارج می‌شود تا وقتی ‎--force اضافه کنید. یک نصب قدیمی config.env اول منتقل می‌شود، همان‌طور که ویزارد انجام می‌دهد (نقش admin را می‌دهد، پس ‎--role owner روی آن ‎--force لازم دارد).

aipager setup detect-chat#

sh
aipager setup detect-chat (--token-file PATH | --token-stdin) [--timeout SECONDS] [--json]

منتظر جدیدترین پیام خصوصی به ربات می‌ماند (زدن Start یکی می‌فرستد) و فرستنده‌اش را چاپ می‌کند: آیدی، اسم و یوزرنیم. چیزی ذخیره نمی‌کند، پس آن شخص را به کاربر نشان بدهید و aipager setup --chat-id را فقط وقتی اجرا کنید که تأیید کرد. فقط پیام‌هایی حساب می‌شوند که حداکثر ۱۰ دقیقه قبل از شروع دستور فرستاده شده‌اند. ‎--timeout بین ۰ تا ۳۶۰۰ ثانیه است (پیش‌فرض ۳۰۰؛ ۰ یعنی یک بار نگاه). پیام‌های تلگرام را بدون تأیید هیچ پیامی می‌خواند، پس ‎/start برای ویزارد و aipager در دسترس می‌ماند.

وقتی یک aipager برای همان ربات اجرا می‌شود، aipager پیام‌های ربات را می‌گیرد، و پیام‌های خصوصی کسانی را که هنوز تنظیم نشده‌اند یادداشت نمی‌کند. آن‌وقت detect-chat با کد ۹ (source: "daemon"‎) خارج می‌شود: aipager را متوقف کنید (aipager service stop) و دوباره اجرایش کنید، یا آیدی عددی آن شخص را از خودش بپرسید. با aipagerی برای ربات دیگر، مستقیم از تلگرام می‌خواند (source: "telegram"‎).

محدودیت: چون detect-chat هیچ‌وقت پیامی را تأیید نمی‌کند، تلگرام فقط ۱۰۰ آپدیت خوانده‌نشدهٔ قدیمی‌تر ۲۴ ساعت گذشته را نشانش می‌دهد. وقتی ربات این‌قدر پیام منتظر دارد، یک ‎/start جدید دیده نمی‌شود: detect-chat آن‌وقت با مهلت تمام‌شده (کد ۸) و هشدار updates_backlog خارج می‌شود، و زدن دوبارهٔ Start کمکی نمی‌کند. به جایش آیدی عددی تلگرام آن شخص را از خودش بپرسید (یا یک بار aipager را اجرا کنید که آن پیام‌ها را می‌خواند و پاک می‌کند).

کدهای خروج#

کدerrorمعنی
0موفق (installed،‏ updated،‏ unchanged،‏ dry_run، یا detect-chat با found).
1config_malformed،‏ ambiguous_install،‏ settings_invalid،‏ test_send_failed،‏ write_failed،‏ service_failed،‏ internal_errorشکست. ambiguous_install: بیش از یک چت خصوصی می‌تواند مال مالک باشد؛ در aipager config درستش کنید.
2usage،‏ missing_token_source،‏ token_source_conflict،‏ token_file_unreadable،‏ token_stdin_is_tty،‏ token_stdin_timeout،‏ token_malformed،‏ token_on_command_line،‏ bad_chat_id،‏ bad_role،‏ bad_timeoutورودی بد یا ناقص؛ fix فلگ را نام می‌برد. یک فلگ ناشناخته یا کلمهٔ اشتباه بعد از setup را پردازشگر آرگومان‌ها گزارش می‌دهد (متن ساده، بدون JSON)، باز هم با کد ۲.
3deps_missingdtach،‏ claude،‏ aipager-hook یا aipager-statusline نیست؛ fix دستورها را دارد. چیزی نوشته نشد.
4token_rejectedتلگرام توکن را رد کرد.
5chat_not_started،‏ bot_blockedآن شخص در ربات Start را نزده ("Open t.me/<bot> and press Start, then run this again.")، یا ربات را بلاک کرده. چیزی نوشته نشد.
6existing_installیک توکن، چت یا نقش متفاوت از قبل تنظیم شده؛ ‎--force اضافه کنید.
7telegram_unreachableخطای شبکه، یا تلگرام با 429 یا ‎5xx جواب داد.
8detect_timeoutdetect-chat قبل از ‎--timeout هیچ پیام خصوصی‌ای ندید (با هشدار updates_backlog وقتی ۱۰۰ آپدیت خوانده‌نشدهٔ قدیمی جدیدترها را پنهان کرده‌اند).
9daemon_runningdetect-chat: یک aipager در حال اجرا پیام‌های ربات را می‌گیرد.
10updates_conflictdetect-chat: برنامهٔ دیگری پیام‌های این ربات را می‌خواند.
130interruptedCtrl-C.

وقتی چند بررسی با هم شکست بخورند، کد از این ترتیب پیروی می‌کند: config_malformed،‏ ambiguous_install،‏ existing_install،‏ settings_invalid،‏ deps_missing.‏ ‎--dry-run با همان کدی خارج می‌شود که اجرای واقعی از این بررسی‌ها می‌گرفت.

JSON: aipager setup --json#

همهٔ کلیدها همیشه هستند؛ مقداری که هنوز معلوم نیست null است.

json
{
  "command": "setup",
  "status": "installed",
  "ok": true,
  "exit_code": 0,
  "error": null,
  "message": "aipager is set up for @example_bot (chat 123456789, role owner). ...",
  "fix": null,
  "dry_run": false,
  "bot_username": "example_bot",
  "chat_id": 123456789,
  "role": "owner",
  "changed": ["bot_token", "owner_dm", "settings_json"],
  "test_message": "sent",
  "deps": {"ok": true, "items": [{"name": "dtach", "found": true, "path": "/usr/bin/dtach", "fix": null}]},
  "settings_json": {"path": "/home/you/.claude/settings.json", "status": "created", "backup": null, "repointed": 0},
  "daemon": {"running": false, "reload": "not_needed", "restart_needed": false},
  "service": {"requested": false, "result": "not_requested"},
  "warnings": [],
  "next_step": "Start aipager with `aipager service install` ..."
}
  • ‏status:‏ installed،‏ updated،‏ unchanged،‏ dry_run یا error.
  • ‏changed: چه چیزی عوض شد (یا در یک اجرای آزمایشی عوض می‌شد)، به این ترتیب: migrated_v1،‏ bot_token،‏ owner_dm،‏ role،‏ settings_json،‏ service.
  • ‏test_message:‏ sent،‏ not_needed،‏ skipped_dry_run،‏ failed یا not_attempted.
  • ‏settings_json.status:‏ created،‏ patched،‏ unchanged،‏ would_change یا not_checked.
  • ‏daemon.reload:‏ reloaded،‏ refused،‏ not_reloaded یا not_needed.‏ restart_needed بعد از یک توکن جدید وقتی aipager اجرا می‌شود، و بعد از هر تغییری وقتی aipager نتوانست تنظیمات را دوباره بخواند یا setup نتوانست بفهمد aipagerی اجرا می‌شود یا نه، true است.
  • ‏service.result:‏ not_requested،‏ installed،‏ already_installed،‏ skipped_daemon_running،‏ would_install،‏ failed، یا null وقتی setup قبل از آن ایستاده.
  • ‏warnings: شیءهایی با code (token_file_shared،‏ reload_refused،‏ daemon_unknown،‏ audit_write_failed) و message.‏ audit_write_failed: دادن مالکیت نوشته شده، ولی رکورد grant-owner آن به لاگ ممیزی اضافه نشد؛ این رکورد در حد تلاش است، پس کد خروج ۰ می‌ماند.
  • ‏next_step بعد از تغییری که وقتی aipager اجرا می‌شود نتوانست دوباره خوانده شود، می‌گوید ری‌استارتش کنید (aipager service stop، بعد aipager service start)؛ فقط وقتی توکن عوض شده اسم توکن ربات را می‌آورد.
  • با هشدار daemon_unknown،‏ next_step هیچ‌وقت نمی‌گوید aipager در حال اجراست. می‌گوید setup نتوانست بفهمد، به aipager doctor --json اشاره می‌کند، و می‌گوید اگر aipager اجرا نمی‌شود با aipager service install یا aipager start شروعش کنید. وقتی ری‌استارت لازم باشد، فقط اگر aipagerی اجرا می‌شود ری‌استارت می‌خواهد، و وگرنه می‌گوید همان‌طور شروعش کنید.
  • در صورت خطا، status برابر error است و error،‏ message و fix می‌گویند چه چیزی خراب شد و چه کار کنید؛ next_step همان fix را تکرار می‌کند. وقتی خطا بعد از یک نوشتن آمده، changed آنچه را نوشته شده فهرست می‌کند، و خروجی ساده یک خط stderr به‌شکل Already written: aipager.yaml, ... (changed: ...) اضافه می‌کند.

JSON: aipager setup detect-chat --json#

json
{
  "command": "detect-chat",
  "status": "found",
  "ok": true,
  "exit_code": 0,
  "error": null,
  "message": "Found Ada L (@ada), Telegram id 123456789.",
  "fix": null,
  "bot_username": "example_bot",
  "source": "telegram",
  "candidate": {"id": 123456789, "first_name": "Ada", "last_name": "L", "username": "ada", "date": 1700000000},
  "other_candidates": 0,
  "warnings": [],
  "next_step": "Show this person to the user; once they confirm, run: aipager setup --token-file <path> --chat-id 123456789"
}

‏candidate فقط وقتی status برابر found است null نیست. warnings شیءهایی با code (token_file_shared،‏ updates_backlog) و message دارد. other_candidates آدم‌های دیگری را می‌شمارد که در همان ۱۰ دقیقه به ربات پیام داده‌اند: وقتی ۰ نیست، مطمئن شوید شخص درستی را دارید. next_step فلگ توکنی را که استفاده کردید تکرار می‌کند، هیچ‌وقت خود توکن را.

aipager doctor --json#

بررسی‌های aipager doctor به‌شکل یک شیء JSON روی stdout. مثل aipager doctor ساده فقط می‌خواند و هیچ پیام تلگرامی نمی‌فرستد. وقتی هر بررسی‌ای شکست بخورد کد ۱، وگرنه ۰. با ‎--fix یا ‎--safety-check ترکیب نمی‌شود (کد ۲ با یک شیء خطا).

json
{
  "command": "doctor",
  "version": "1.0.1",
  "ok": true,
  "summary": {"ok": 14, "warn": 1, "fail": 0},
  "checks": [{"key": "token_valid", "status": "ok", "title": "Telegram bot token", "detail": ["@example_bot"], "fix": null}]
}

‏checks به این ترتیب و با این کلیدهاست: config_parses،‏ config،‏ token_valid،‏ chat_reachable،‏ team،‏ role_shell_access،‏ peer_messages،‏ claude،‏ claude_auth،‏ dtach،‏ hook_scripts،‏ settings_json،‏ daemon،‏ service_installed،‏ service_unit_path،‏ miniapp. بررسی‌ای که کرش کند کلیدش را با وضعیت warn نگه می‌دارد. متن‌ها ساده‌اند (بدون markup)، و هر چیزی که شکل توکن ربات دارد با ‎<redacted>‎ عوض می‌شود.

خط فرمان: aipager uninstall#

‏aipager uninstall aipager را متوقف می‌کند و سرویسش را برمی‌دارد، پوشهٔ تنظیمات (‎~/.config/aipager: توکن ربات، چت‌ها و تنظیمات) و فهرست سشن‌ها (‎~/.claude/aipager-sessions.json) را پاک می‌کند، فایل‌های aipager را در ‎/tmp جمع می‌کند، و خود aipager را حذف می‌کند. اول می‌پرسد (‎-y از سؤال رد می‌شود).

داده‌های aipager را نگه می‌دارد تا نصب دوباره از همان‌جا ادامه دهد: ‎~/.local/share/aipager (پوشه‌های سشن‌ها، ابزارهای دانلودشده، فایل‌های قفل و علامت)، ‎~/.local/state/aipager (رکوردهای گزارش مشکل و وضعیت زبان)، ‎~/.claude/aipager-audit.jsonl (لاگ جواب‌های اجازه)، ‎~/.claude/aipager-flood-state.json (تاریخچهٔ محدودیت سرعت تلگرام)، ‎~/.claude/aipager-pending-users.json (کسانی که بدون دسترسی ربات را امتحان کرده‌اند) و ‎~/aipager-users (پوشه‌های root اعضا، با کارشان). قبل از پرسیدن، آن‌هایی را که روی کامپیوترتان هستند فهرست می‌کند، و در آخر دستور rm -rf را که آن‌ها را هم پاک می‌کند چاپ می‌کند.

ورودی‌های خود aipager را هم از ‎~/.claude/settings.json در Claude Code برمی‌دارد: هوک‌هایی که aipager-hook را اجرا می‌کنند و خط وضعیتی که aipager-statusline را اجرا می‌کند (خط وضعیت خودتان می‌ماند). بقیهٔ آن فایل همان‌طور که بود می‌ماند، و فایل همان‌طور که بود کنارش به‌شکل settings.json.bak.<time>‎ نگه داشته می‌شود. اگر فایل یک لینک به فایل دیگر باشد، خوانده نشود، JSON معتبر نباشد، یا شکلی نباشد که Claude Code می‌خواند، دقیقاً همان‌طور که هست می‌ماند و uninstall می‌گوید کدام ورودی‌ها را دستی بردارید. هوکی از خودتان که هنوز aipager-hook یا aipager-statusline را نام می‌برد (مثلاً یک wrapper به اسم aipager-hook-capped.sh) هم می‌ماند، و uninstall اسمش را می‌آورد. سشن‌های Claude Code که از قبل باز هستند تا وقتی ری‌استارتشان کنید همان هوک‌هایی را که لود کرده‌اند اجرا می‌کنند. aipager config بعد از نصب دوباره این ورودی‌ها را دوباره اضافه می‌کند. ربات تلگرام شما و نسخه‌های پشتیبان قدیمی‌تر settings.json.bak.*‎ دست نمی‌خورند، و skipDangerousModePermissionPrompt هم نه (تنظیمی که هشدار Claude Code را قبل از اجرا با بررسی‌های اجازهٔ خاموش رد می‌کند)، که aipager تنظیمش می‌کند ولی ممکن است خودتان هم تنظیمش کرده باشید.

خط فرمان: aipager report#

‏aipager report گزارش مشکلی از همان نوع دکمهٔ «گزارش مشکل» ربات می‌سازد، از چیزهایی که aipager روی این کامپیوتر ثبت کرده (با اطلاعات کمتری از aipager در حال اجرا: مود، چت‌ها، قابلیت‌ها، مدت روشن بودن، سشن‌ها و جزئیات Claude Code نامعلوم یا خالی می‌مانند)، همه‌اش را چاپ می‌کند و می‌پرسد Send this report? [y/N]. فقط y یا yes آن را می‌فرستد؛ هر چیز دیگر، یا بدون ترمینال (یک اسکریپت، یک pipe،‏ shell یک سشن Claude Code)، هیچ چیزی نمی‌فرستد. ‎--note "text"‎ یک توضیح تا ۵۰۰ حرف اضافه می‌کند که در گزارش چاپ‌شده دیده می‌شود. وقتی گزارش فرستاده شد، به انتخاب شما فرستاده نشد، یا فقط چاپ شد با کد ۰، و وقتی ارسالی که تأیید کردید انجام نشد با کد ۱ خارج می‌شود. برای اینکه یک گزارش چه دارد و کجا ارسال می‌شود، گزارش مشکل را ببینید.

تنظیمات محیطی#

چند تنظیم به جای aipager.yaml از محیط aipager خوانده می‌شوند. برای سرویس systemd، آن‌ها را با systemctl --user edit aipager زیر ‎[Service]‎ اضافه کنید (Environment=STALE_BUSY_TIMEOUT=900)، بعد aipager service stop و aipager service start؛ برای سرویس launchd روی macOS، آن‌ها را به EnvironmentVariables فایل plist اضافه کنید (‎~/Library/LaunchAgents/com.aipager.daemon.plist؛‏ aipager service install آن فایل را دوباره می‌نویسد، پس بعدش دوباره اضافه‌شان کنید)؛ برای aipagerی که خودتان اجرا می‌کنید، قبل از aipager start تنظیمشان کنید. هیچ‌کدام برای استفادهٔ معمولی لازم نیست.

تنظیمپیش‌فرضچه چیزی را عوض می‌کند
AIPAGER_WHISPER_MODELbaseمدل تبدیل صدا به متن برای ویس (tiny،‏ base،‏ small،‏ medium، ...): بزرگ‌تر یعنی دقیق‌تر و کندتر.
MINIAPP_PORT8765پورت Mini App روی 127.0.0.1 (aipager miniapp enable --port به جایش آن را ذخیره می‌کند).
MINIAPP_ENABLEDاز aipager.yaml0 Mini App را خاموش و 1 روشن می‌کند، هر چه aipager.yaml بگوید (aipager miniapp enable|disable به جایش انتخاب را ذخیره می‌کند).
MINIAPP_PUBLIC_URLهیچMini App را به جای تونل مدیریت‌شده روی آدرس https://‎ خودتان سرو می‌کند (مدل امنیتی).
KEEP_FINISHED_CARD10 «فقط جواب، جای کارت» را شکل پیام‌های چت‌هایی می‌کند که هیچ‌وقت در ‎/settings انتخابی نکرده‌اند.
STALE_BUSY_TIMEOUT7200 (۲ ساعت)چند ثانیه یک سشن در حال کار می‌تواند بی‌خبر بماند قبل از اینکه چت یادداشت «هنوز کار می‌کند (۱۲۰ دقیقه بی‌خبر)» را بگیرد.
PROMPT_HOOK_GRACE_SECONDS8چند ثانیه قبل از اینکه پیامی که Claude Code هیچ‌وقت تحویل نگرفت «Claude Code پیام را تحویل نگرفت» علامت بخورد (پیام‌های آزاد).
FINISH_CARD_GRACE_SECONDS0.8کارت تمام‌شده در شکل «کارت + جواب جدا» چقدر جلوتر از جواب می‌آید؛ 0 هر دو را با هم می‌فرستد.
GONE_SESSION_MAX_AGE_DAYS14چند روز یک سشن بسته‌شده در ‎/resume می‌ماند؛ 0 نگهشان می‌دارد.
STREAM_EDIT_INTERVAL،‏ BUSY_EDIT_INTERVAL1.2، 3.0سرعت آپدیت کارت در حال کار وقتی متن نشان می‌دهد و وقتی آرام است، به ثانیه؛ سقف هر چت در تلگرام همچنان برنده است (رفع مشکل).
TYPING_INDICATOR_INTERVAL4.5چند ثانیه بین حباب‌های «در حال تایپ…»؛ 0 خاموششان می‌کند.
TELEGRAM_MAX_RETRY_AFTER90انتظار تلگرام، به ثانیه، که بیشتر از آن aipager یک محدودیت سرعت را بن حساب می‌کند (پایین نیاوریدش؛ رفع مشکل را ببینید).
CLAUDE_RICH_SUMMARIES10 قالب‌بندی غنی جواب‌هایی را که بلوک کد دارند خاموش می‌کند (یک حالت جایگزین که از نسخه‌های قدیمی‌تر مانده).
AIPAGER_INTERACTIVE_TIMEOUT300چند ثانیه یک درخواست اجازه یا سؤال می‌تواند بدون خبر از Claude Code منتظر بماند قبل از اینکه aipager گفتگوی ذخیره‌شده را نگاه کند؛ سشن فقط وقتی دوباره در حال کار حساب می‌شود که گفتگو نشان بدهد درخواست تمام شده (رفع مشکل).
AIPAGER_SUBAGENT_SILENCE1800چند ثانیه بی‌خبری که بعد از آن یک ساب‌ایجنت بدون دیده شدن پایانش کنار گذاشته می‌شود (هوک‌ها).
AIPAGER_BG_SHELL_MAX_TRACK7200چند ثانیه که بعد از آن یک دستور پس‌زمینه بدون دیده شدن پایانش دیگر شمرده نمی‌شود.
AIPAGER_REPORT_PROMPTSروشن0 پیشنهادهای خودکار گزارش مشکل را خاموش می‌کند (گزارش مشکل).
AIPAGER_CLAUDE_BINهیچclaudeی که باید اجرا شود، وقتی چندتا نصب است (claude_path در aipager.yaml برنده است).
AIPAGER_SOCKET_PATH‎$XDG_RUNTIME_DIR/aipager.sockسوکت کنترل aipager. سشن‌هایی که aipager شروع می‌کند آن را به هوک‌هایشان می‌دهند.
AIPAGER_DEBUGخاموش1 در محیط یک سشن باعث می‌شود aipager-hook و aipager-statusline اطلاعات عیب‌یابی‌شان را روی stderr چاپ کنند.
AIPAGER_INSTANCE_DIR،‏ AIPAGER_TELEGRAM_API_BASEهیچیک aipager دوم و جدا برای تست (معماری).

این‌ها را هم ببینید#