diff --git a/telegram-agy-bot/bot.py b/telegram-agy-bot/bot.py index d58d26a..42c7fe4 100644 --- a/telegram-agy-bot/bot.py +++ b/telegram-agy-bot/bot.py @@ -109,6 +109,9 @@ def get_lang_display(lang_code_or_name: str) -> str: norm = LANG_ALIASES.get(norm, norm) return AVAILABLE_LANGUAGES.get(norm, lang_code_or_name) +# Global active user input states for interactive prompts (e.g. FTP configuration wizards) +USER_INPUT_STATES: dict[int, dict] = {} + # Logging configuration logging.basicConfig( format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", @@ -389,9 +392,12 @@ async def build_ftp_menu(chat_id: int) -> tuple[str, InlineKeyboardMarkup]: user=curr_proj.ftp_user, path=curr_proj.ftp_path, tls=curr_proj.ftp_tls, + password=curr_proj.ftp_password, lang=session.language, ) + tls_toggle_label = f"🔒 پروتکل امن: {'روشن ✅' if curr_proj.ftp_tls else 'خاموش ❌'}" if is_fa else f"🔒 FTPS/TLS: {'ON ✅' if curr_proj.ftp_tls else 'OFF ❌'}" + if is_fa: keyboard = [ [ @@ -399,10 +405,19 @@ async def build_ftp_menu(chat_id: int) -> tuple[str, InlineKeyboardMarkup]: InlineKeyboardButton("🔍 تست اتصال FTP", callback_data="btn_ftp_test"), ], [ - InlineKeyboardButton("🐙 منوی گیت و برنچ‌ها", callback_data="btn_git_menu"), - InlineKeyboardButton("📁 مدیریت پروژه‌ها", callback_data="proj_menu"), + InlineKeyboardButton("🌐 ویرایش هاست/پورت", callback_data="ftp_set:host"), + InlineKeyboardButton("👤 ویرایش نام کاربری", callback_data="ftp_set:user"), ], [ + InlineKeyboardButton("🔑 ویرایش رمز عبور", callback_data="ftp_set:pass"), + InlineKeyboardButton("📂 ویرایش مسیر مقصد", callback_data="ftp_set:path"), + ], + [ + InlineKeyboardButton(tls_toggle_label, callback_data="ftp_toggle_tls"), + InlineKeyboardButton("🗑️ پاک‌سازی اطلاعات", callback_data="ftp_clear_conf"), + ], + [ + InlineKeyboardButton("🐙 منوی گیت و برنچ‌ها", callback_data="btn_git_menu"), InlineKeyboardButton("🏠 منوی اصلی", callback_data="btn_dashboard"), ], ] @@ -413,10 +428,19 @@ async def build_ftp_menu(chat_id: int) -> tuple[str, InlineKeyboardMarkup]: InlineKeyboardButton("🔍 Test FTP Connection", callback_data="btn_ftp_test"), ], [ - InlineKeyboardButton("🐙 Git & Branches Menu", callback_data="btn_git_menu"), - InlineKeyboardButton("📁 Projects Menu", callback_data="proj_menu"), + InlineKeyboardButton("🌐 Edit Host/Port", callback_data="ftp_set:host"), + InlineKeyboardButton("👤 Edit Username", callback_data="ftp_set:user"), ], [ + InlineKeyboardButton("🔑 Edit Password", callback_data="ftp_set:pass"), + InlineKeyboardButton("📂 Edit Remote Path", callback_data="ftp_set:path"), + ], + [ + InlineKeyboardButton(tls_toggle_label, callback_data="ftp_toggle_tls"), + InlineKeyboardButton("🗑️ Clear Config", callback_data="ftp_clear_conf"), + ], + [ + InlineKeyboardButton("🐙 Git & Branches Menu", callback_data="btn_git_menu"), InlineKeyboardButton("🏠 Main Dashboard", callback_data="btn_dashboard"), ], ] @@ -4707,6 +4731,96 @@ async def callback_handler(update: Update, context: ContextTypes.DEFAULT_TYPE): except Exception: await query.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True) + elif data.startswith("ftp_set:"): + field_name = data.split(":")[1] + if not curr_proj: + await query.answer("⚠️ پروژه‌ای یافت نشد." if is_fa else "⚠️ No project found.", show_alert=True) + return + + USER_INPUT_STATES[chat_id] = { + "type": "ftp_set", + "field": field_name, + "project": curr_proj.name, + } + + field_prompts = { + "host": ( + "🌐 لطفاً آدرس هاست یا سرور FTP را ارسال کنید:\n\n" + "مثال: ftp.mysite.com یا 185.120.30.40:21" + ) if is_fa else ( + "🌐 Please enter the FTP Host address:\n\n" + "Example: ftp.mysite.com or 185.120.30.40:21" + ), + "user": ( + "👤 لطفاً نام کاربری (Username) اتصال FTP را ارسال کنید:\n\n" + "مثال: deployer@mysite.com یا ftpuser" + ) if is_fa else ( + "👤 Please enter the FTP Username:\n\n" + "Example: deployer@mysite.com or ftpuser" + ), + "pass": ( + "🔑 لطفاً رمز عبور (Password) اتصال FTP را ارسال کنید:\n\n" + "(پیام پس از ثبت، جهت امنیت حذف یا پوشانده می‌شود)" + ) if is_fa else ( + "🔑 Please enter the FTP Password:\n\n" + "(Message will be stored securely)" + ), + "path": ( + "📂 لطفاً مسیر پوشه ریموت مقصد روی هاست را ارسال کنید:\n\n" + "مثال: /public_html یا /domains/site.com/public_html" + ) if is_fa else ( + "📂 Please enter the remote target path:\n\n" + "Example: /public_html" + ), + } + + prompt_text = field_prompts.get(field_name, "لطفاً مقدار جدید را ارسال کنید:") + cancel_kb = InlineKeyboardMarkup([[InlineKeyboardButton("❌ انصراف و بازگشت" if is_fa else "❌ Cancel", callback_data="btn_ftp_menu")]]) + await query.edit_message_text(prompt_text, parse_mode=constants.ParseMode.HTML, reply_markup=cancel_kb) + + elif data == "ftp_toggle_tls": + if curr_proj: + curr_proj.ftp_tls = not curr_proj.ftp_tls + session_manager.save() + status_str = "روشن (FTPS/TLS) 🔒" if curr_proj.ftp_tls else "خاموش (FTP معمولی) 🔓" + await query.answer(f"✅ پروتکل امن: {status_str}") + text, markup = await build_ftp_menu(chat_id) + try: + await query.edit_message_text(text, parse_mode=constants.ParseMode.HTML, reply_markup=markup, disable_web_page_preview=True) + except Exception: + await query.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True) + + elif data == "ftp_clear_conf": + confirm_text = ( + "🗑️ آیا از پاک‌سازی کامل اطلاعات FTP این پروژه اطمینان دارید؟\n\n" + "تمام مشخصات سرور، کاربر و رمز عبور حذف خواهند شد." + ) if is_fa else ( + "🗑️ Are you sure you want to clear FTP settings for this project?" + ) + keyboard = [ + [ + InlineKeyboardButton("💥 بله، پاک شود" if is_fa else "💥 Yes, Clear", callback_data="ftp_clear_do"), + InlineKeyboardButton("❌ انصراف" if is_fa else "❌ Cancel", callback_data="btn_ftp_menu"), + ] + ] + await query.edit_message_text(confirm_text, parse_mode=constants.ParseMode.HTML, reply_markup=InlineKeyboardMarkup(keyboard)) + + elif data == "ftp_clear_do": + if curr_proj: + curr_proj.ftp_host = None + curr_proj.ftp_port = 21 + curr_proj.ftp_user = None + curr_proj.ftp_password = None + curr_proj.ftp_path = "/" + curr_proj.ftp_tls = False + session_manager.save() + await query.answer("🗑️ اطلاعات FTP با موفقیت پاک شد." if is_fa else "🗑️ FTP settings cleared.") + text, markup = await build_ftp_menu(chat_id) + try: + await query.edit_message_text(text, parse_mode=constants.ParseMode.HTML, reply_markup=markup, disable_web_page_preview=True) + except Exception: + await query.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True) + elif data == "btn_ftp_test": await query.answer("🔍 در حال بررسی اتصال FTP..." if is_fa else "🔍 Testing FTP connection...") if curr_proj and curr_proj.ftp_host: @@ -6501,6 +6615,65 @@ async def message_handler(update: Update, context: ContextTypes.DEFAULT_TYPE): session = session_manager.get_or_create(chat_id) is_fa = (session.language or "").lower() in ("fa", "farsi", "persian", "🇮🇷 persian / farsi (فارسی)") + # 1. Check if user is in an interactive input state (e.g. configuring FTP fields) + if chat_id in USER_INPUT_STATES: + state = USER_INPUT_STATES.pop(chat_id) + if state.get("type") == "ftp_set" and curr_proj: + field = state.get("field") + val = update.message.text.strip() + + if field == "host": + # Check for host:port format + if ":" in val: + h, p = val.rsplit(":", 1) + curr_proj.ftp_host = h.strip() + try: + curr_proj.ftp_port = int(p.strip()) + except Exception: + pass + else: + curr_proj.ftp_host = val + elif field == "user": + curr_proj.ftp_user = val + elif field == "pass": + curr_proj.ftp_password = val + # Delete password message from chat if possible for security + try: + await update.message.delete() + except Exception: + pass + elif field == "path": + curr_proj.ftp_path = val if val.startswith("/") else f"/{val}" + + session_manager.save() + + field_labels = { + "host": "هاست و پورت", + "user": "نام کاربری", + "pass": "رمز عبور", + "path": "مسیر مقصد", + } + label_fa = field_labels.get(field, field) + ack_msg = f"✅ {label_fa} با موفقیت ذخیره شد." if is_fa else f"✅ {field} updated successfully." + await update.message.reply_html(ack_msg) + + # Auto-test connection if host, user and password are all present + if curr_proj.ftp_host and curr_proj.ftp_user and curr_proj.ftp_password: + test_ok, test_msg = await ftp_manager.test_connection( + host=curr_proj.ftp_host, + port=curr_proj.ftp_port, + user=curr_proj.ftp_user or "", + password=curr_proj.ftp_password or "", + path=curr_proj.ftp_path or "/", + tls=curr_proj.ftp_tls, + ) + test_status = "✅ اتصال FTP با موفقیت برقرار و تایید شد." if test_ok else f"⚠️ هشدار در تست اتصال: {test_msg}" + await update.message.reply_html(f"{test_status}") + + text, markup = await build_ftp_menu(chat_id) + await update.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True) + return + if not curr_proj: if is_fa: msg = ( diff --git a/telegram-agy-bot/formatters.py b/telegram-agy-bot/formatters.py index 2086adf..c590c34 100644 --- a/telegram-agy-bot/formatters.py +++ b/telegram-agy-bot/formatters.py @@ -622,6 +622,7 @@ def format_ftp_info( user: Optional[str] = None, path: str = "/", tls: bool = False, + password: Optional[str] = None, lang: str = "fa", ) -> str: """Formats FTP connection and deployment status for Telegram HTML.""" @@ -630,18 +631,20 @@ def format_ftp_info( host_str = f"{escape_html(host)}:{port}" if host else ("(تنظیم نشده)" if is_fa else "(Not configured)") user_str = f"{escape_html(user)}" if user else ("(ندارد)" if is_fa else "(None)") path_str = f"{escape_html(path)}" + pass_str = f"{'•' * min(len(password), 8)} (تنظیم شده)" if password else ("(ندارد)" if is_fa else "(None)") tls_str = "بله (FTPS/TLS امن) 🔒" if tls else "خیر (FTP معمولی)" tls_str_en = "Yes (Secure FTPS/TLS) 🔒" if tls else "No (Standard FTP)" if is_fa: return ( - f"🚀 تنظیمات استقرار و دیپلوی FTP پروژه\n\n" + f"🚀 تنظیمات استقرار و مشخصات FTP پروژه\n\n" f"• 📁 پروژه: {clean_p}\n" - f"• 🌐 سرور / هاست FTP: {host_str}\n" + f"• 🌐 سرور / هاست: {host_str}\n" f"• 👤 نام کاربری: {user_str}\n" + f"• 🔑 رمز عبور: {pass_str}\n" f"• 📂 مسیر مقصد روی هاست: {path_str}\n" f"• 🔒 پروتکل امن (FTPS): {tls_str}\n\n" - f"💡 در زمان دیپلوی، هوش مصنوعی فایل‌های زائد، کش، سشن‌ها و مخزن گیت (.git) را به صورت خودکار فیلتر کرده و تنها سورس اصلی و تمیز به سرور منتقل می‌شود." + f"💡 می‌توانید با دکمه‌های زیر هر فیلد را به دلخواه ویرایش، تست یا ذخیره کنید. در زمان دیپلوی، فایل‌های زائد، کش و .git به صورت خودکار فیلتر می‌شوند." ) else: return ( @@ -649,9 +652,10 @@ def format_ftp_info( f"• 📁 Project: {clean_p}\n" f"• 🌐 FTP Host: {host_str}\n" f"• 👤 Username: {user_str}\n" - f"• 📂 Remote Target Path: {path_str}\n" + f"• 🔑 Password: {pass_str}\n" + f"• 📂 Remote Path: {path_str}\n" f"• 🔒 Secure FTPS/TLS: {tls_str_en}\n\n" - f"💡 During deployment, unnecessary cache, temp, sessions, and .git files are automatically excluded for a clean production upload." + f"💡 Use the buttons below to edit fields, test connection, or deploy. Junk and cache files are excluded automatically." ) diff --git a/telegram-agy-bot/sessions.json b/telegram-agy-bot/sessions.json index 0ec7145..c6c32e3 100644 --- a/telegram-agy-bot/sessions.json +++ b/telegram-agy-bot/sessions.json @@ -20,9 +20,9 @@ "model": "gemini-3.7-flash-auto", "effort": "high", "language": "fa", - "last_context_length": 24319, - "last_total_tokens": 229272, - "last_response": "\u0628\u0631\u0627\u06cc \u0627\u06cc\u0646\u06a9\u0647 \u0628\u062a\u0648\u0627\u0646\u06cc\u062f \u062a\u0645\u0627\u0645 \u0641\u06cc\u0644\u062f\u0647\u0627\u06cc FTP \u0631\u0627 \u0628\u0647 \u0635\u0648\u0631\u062a \u06a9\u0627\u0645\u0644\u0627\u064b \u062a\u0639\u0627\u0645\u0644\u06cc \u0628\u0627 \u062f\u06a9\u0645\u0647\u200c\u0647\u0627 \u0648 \u0641\u0631\u0645 \u0627\u062e\u062a\u0635\u0627\u0635\u06cc \u062e\u0648\u062f \u0631\u0628\u0627\u062a \u0648\u0627\u0631\u062f\u060c \u0648\u06cc\u0631\u0627\u06cc\u0634\u060c \u0645\u0634\u0627\u0647\u062f\u0647 \u0648 \u062a\u0633\u062a \u06a9\u0646\u06cc\u062f\u060c \u0628\u0631\u0646\u0627\u0645\u0647 \u0632\u06cc\u0631 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0627\u0631\u062a\u0642\u0627\u06cc \u0631\u0628\u0627\u062a \u062a\u0644\u06af\u0631\u0627\u0645 \u0622\u0645\u0627\u062f\u0647 \u06a9\u0631\u062f\u0647\u200c\u0627\u0645:\n\n---\n\n### \ud83d\udccb \u0628\u0631\u0646\u0627\u0645\u0647 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u062f\u0631 \u0631\u0628\u0627\u062a \u062a\u0644\u06af\u0631\u0627\u0645 (`/root/telegram-agy-bot`):\n\n1. **\u0627\u0636\u0627\u0641\u0647 \u0634\u062f\u0646 \u0645\u0646\u0648\u06cc \u062a\u0639\u0627\u0645\u0644\u06cc \u00ab\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0648 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0645\u0634\u062e\u0635\u0627\u062a FTP\u00bb (`btn_ftp_settings`):**\n - \u062f\u06a9\u0645\u0647 **\ud83c\udf10 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0647\u0627\u0633\u062a / \u0633\u0631\u0648\u0631** (Host & Port)\n - \u062f\u06a9\u0645\u0647 **\ud83d\udc64 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0646\u0627\u0645 \u06a9\u0627\u0631\u0628\u0631\u06cc** (Username)\n - \u062f\u06a9\u0645\u0647 **\ud83d\udd11 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631** (Password)\n - \u062f\u06a9\u0645\u0647 **\ud83d\udcc2 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0645\u0633\u06cc\u0631 \u0645\u0642\u0635\u062f \u0631\u0648\u06cc \u0647\u0627\u0633\u062a** (Remote Path)\n - \u062f\u06a9\u0645\u0647 **\ud83d\udd12 \u062a\u063a\u06cc\u06cc\u0631 \u0648\u0636\u0639\u06cc\u062a FTPS / TLS** (\u0631\u0648\u0634\u0646/\u062e\u0627\u0645\u0648\u0634 \u0628\u0627 \u06cc\u06a9 \u06a9\u0644\u06cc\u06a9)\n - \u062f\u06a9\u0645\u0647 **\ud83d\uddd1\ufe0f \u067e\u0627\u06a9\u200c\u0633\u0627\u0632\u06cc \u0627\u0637\u0644\u0627\u0639\u0627\u062a FTP**\n\n2. **\u0633\u06cc\u0633\u062a\u0645 \u062d\u0627\u0644\u062a \u0648\u0631\u0648\u062f\u06cc \u062a\u0639\u0627\u0645\u0644\u06cc (Interactive Input Prompting):**\n - \u0628\u0627 \u06a9\u0644\u06cc\u06a9 \u0631\u0648\u06cc \u0647\u0631 \u062f\u06a9\u0645\u0647 (\u0645\u062b\u0644\u0627\u064b *\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0647\u0627\u0633\u062a* \u06cc\u0627 *\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631*)\u060c \u0631\u0628\u0627\u062a \u067e\u06cc\u0627\u0645 \u0631\u0627\u0647\u0646\u0645\u0627 \u0627\u0631\u0633\u0627\u0644 \u06a9\u0631\u062f\u0647 \u0648 \u0645\u0646\u062a\u0638\u0631 \u062f\u0631\u06cc\u0627\u0641\u062a \u0645\u0642\u062f\u0627\u0631 \u0627\u0631\u0633\u0627\u0644\u06cc \u0634\u0645\u0627 \u0645\u06cc\u200c\u0645\u0627\u0646\u062f \u0648 \u0628\u0644\u0627\u0641\u0627\u0635\u0644\u0647 \u0641\u06cc\u0644\u062f \u0645\u0631\u0628\u0648\u0637\u0647 \u0631\u0627 \u062f\u0631 \u067e\u0631\u0648\u0698\u0647 \u0630\u062e\u06cc\u0631\u0647 \u0648 \u0645\u0646\u0648 \u0631\u0627 \u0628\u0647\u200c\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc \u0645\u06cc\u200c\u06a9\u0646\u062f.\n\n3. **\u0646\u0645\u0627\u06cc\u0634 \u06a9\u0627\u0645\u0644 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u0648 \u062f\u06a9\u0645\u0647 \u062a\u0633\u062a \u0622\u0646\u0644\u0627\u06cc\u0646:**\n - \u067e\u0633 \u0627\u0632 \u0647\u0631 \u0648\u06cc\u0631\u0627\u06cc\u0634\u060c \u0648\u0636\u0639\u06cc\u062a \u0627\u062a\u0635\u0627\u0644 FTP \u0628\u0644\u0627\u0641\u0627\u0635\u0644\u0647 \u062f\u0631 \u067e\u0646\u0644 \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f \u0648 \u062f\u06a9\u0645\u0647 **\ud83d\udd0d \u062a\u0633\u062a \u0627\u062a\u0635\u0627\u0644 FTP** \u0627\u0645\u06a9\u0627\u0646 \u0633\u0646\u062c\u0634 \u0627\u0631\u062a\u0628\u0627\u0637 \u0622\u0646\u0644\u0627\u06cc\u0646 \u0631\u0627 \u0628\u0647 \u0634\u0645\u0627 \u0645\u06cc\u200c\u062f\u0647\u062f.\n\n---\n\n\u0622\u06cc\u0627 \u0628\u0627 \u0627\u0639\u0645\u0627\u0644 \u0627\u06cc\u0646 \u0642\u0627\u0628\u0644\u06cc\u062a\u200c\u0647\u0627 \u0648 \u0627\u0641\u0632\u0648\u062f\u0646 \u062f\u06a9\u0645\u0647\u200c\u0647\u0627\u06cc \u0648\u06cc\u0631\u0627\u06cc\u0634 \u062a\u0639\u0627\u0645\u0644\u06cc FTP \u0628\u0647 \u0631\u0628\u0627\u062a \u0645\u0648\u0627\u0641\u0642\u06cc\u062f \u062a\u0627 \u0622\u0646 \u0631\u0627 \u067e\u06cc\u0627\u062f\u0647\u200c\u0633\u0627\u0632\u06cc \u0648 \u0641\u0639\u0627\u0644 \u06a9\u0646\u0645\u061f\n\n\u2022 \u0646\u0627\u0645 \u067e\u0631\u0648\u0698\u0647: default \n\u2022 \u0622\u062f\u0631\u0633 \u0645\u062e\u0632\u0646: https://git.msa.artacloud.ir/root/default\n", + "last_context_length": 41556, + "last_total_tokens": 332309, + "last_response": "\u0642\u0627\u0628\u0644\u06cc\u062a \u0645\u062f\u06cc\u0631\u06cc\u062a \u06a9\u0627\u0645\u0644 \u0648 \u062a\u0639\u0627\u0645\u0644\u06cc \u062a\u0646\u0638\u06cc\u0645\u0627\u062a FTP \u0645\u0633\u062a\u0642\u06cc\u0645\u0627\u064b \u0628\u0627 \u062f\u06a9\u0645\u0647\u200c\u0647\u0627\u06cc \u0631\u0628\u0627\u062a \u062a\u0644\u06af\u0631\u0627\u0645 \u067e\u06cc\u0627\u062f\u0647\u200c\u0633\u0627\u0632\u06cc \u0648 \u0641\u0639\u0627\u0644 \u0634\u062f.\n\n---\n\n### \u2728 \u0627\u0645\u06a9\u0627\u0646\u0627\u062a \u0648 \u062f\u06a9\u0645\u0647\u200c\u0647\u0627\u06cc \u062c\u062f\u06cc\u062f \u0627\u0636\u0627\u0641\u0647 \u0634\u062f\u0647:\n\n1. **\ud83c\udf10 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0647\u0627\u0633\u062a / \u067e\u0648\u0631\u062a (`ftp_set:host`):**\n - \u0628\u0627 \u06a9\u0644\u06cc\u06a9 \u0631\u0648\u06cc \u062f\u06a9\u0645\u0647\u060c \u0631\u0628\u0627\u062a \u0645\u0646\u062a\u0638\u0631 \u062f\u0631\u06cc\u0627\u0641\u062a \u0622\u062f\u0631\u0633 \u0647\u0627\u0633\u062a \u0645\u06cc\u200c\u0645\u0627\u0646\u062f (\u0645\u062b\u0627\u0644: `ftp.mysite.com` \u06cc\u0627 `1.2.3.4:2121`).\n2. **\ud83d\udc64 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0646\u0627\u0645 \u06a9\u0627\u0631\u0628\u0631\u06cc (`ftp_set:user`):**\n - \u0628\u0631\u0627\u06cc \u0648\u0627\u0631\u062f \u06a9\u0631\u062f\u0646 \u06cc\u0648\u0632\u0631\u0646\u06cc\u0645 \u0627\u06a9\u0627\u0646\u062a FTP.\n3. **\ud83d\udd11 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631 (`ftp_set:pass`):**\n - \u0628\u0631\u0627\u06cc \u0648\u0627\u0631\u062f \u06a9\u0631\u062f\u0646 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631 (\u067e\u0633 \u0627\u0632 \u062f\u0631\u06cc\u0627\u0641\u062a\u060c \u067e\u06cc\u0627\u0645 \u0628\u0631\u0627\u06cc \u0627\u0645\u0646\u06cc\u062a \u0628\u06cc\u0634\u062a\u0631 \u062d\u0630\u0641 \u0645\u06cc\u200c\u0634\u0648\u062f \u0648 \u062f\u0631 \u0645\u0646\u0648 \u0628\u0647 \u0635\u0648\u0631\u062a \u0645\u0627\u0633\u06a9\u200c\u0634\u062f\u0647 `\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022` \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f).\n4. **\ud83d\udcc2 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0645\u0633\u06cc\u0631 \u0631\u06cc\u0645\u0648\u062a \u0631\u0648\u06cc \u0647\u0627\u0633\u062a (`ftp_set:path`):**\n - \u0628\u0631\u0627\u06cc \u0645\u0634\u062e\u0635 \u06a9\u0631\u062f\u0646 \u0645\u0633\u06cc\u0631 \u067e\u0648\u0634\u0647 \u062f\u0631 \u0647\u0627\u0633\u062a (\u0645\u0627\u0646\u0646\u062f `/public_html` \u06cc\u0627 `/domains/mysite.com/public_html`).\n5. **\ud83d\udd12 \u0633\u0648\u06cc\u06cc\u0686 \u067e\u0631\u0648\u062a\u06a9\u0644 \u0627\u0645\u0646 FTPS / TLS (`ftp_toggle_tls`):**\n - \u0628\u0627 \u06cc\u06a9 \u06a9\u0644\u06cc\u06a9 \u0628\u06cc\u0646 FTP \u0645\u0639\u0645\u0648\u0644\u06cc \u0648 TLS \u0627\u0645\u0646 \u062a\u063a\u06cc\u06cc\u0631 \u0648\u0636\u0639\u06cc\u062a \u0645\u06cc\u200c\u062f\u0647\u062f.\n6. **\ud83d\udd0d \u062a\u0633\u062a \u062e\u0648\u062f\u06a9\u0627\u0631 \u0648 \u0622\u0646\u0644\u0627\u06cc\u0646 \u0627\u062a\u0635\u0627\u0644 FTP (`btn_ftp_test`):**\n - \u0628\u0631\u0631\u0633\u06cc \u0632\u0646\u062f\u0647 \u0635\u062d\u062a \u0645\u0634\u062e\u0635\u0627\u062a \u0627\u062a\u0635\u0627\u0644 \u0628\u0627 \u0647\u0627\u0633\u062a \u0648 \u0646\u0645\u0627\u06cc\u0634 \u0648\u0636\u0639\u06cc\u062a \u0627\u0631\u062a\u0628\u0627\u0637.\n7. **\ud83d\uddd1\ufe0f \u067e\u0627\u06a9\u200c\u0633\u0627\u0632\u06cc \u0645\u0634\u062e\u0635\u0627\u062a FTP (`ftp_clear_conf`):**\n - \u0631\u06cc\u0633\u062a \u0648 \u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u06a9\u0627\u0645\u0644 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u0627\u062a\u0635\u0627\u0644 \u062f\u0631 \u0635\u0648\u0631\u062a \u0646\u06cc\u0627\u0632.\n\n---\n\n[[RESTART_BOT]]\n\n[[BUTTONS: layout=[\n [{\"text\": \"\ud83d\ude80 \u0628\u0627\u0632 \u06a9\u0631\u062f\u0646 \u0645\u0646\u0648\u06cc FTP\", \"cmd\": \"/ftp\"}, {\"text\": \"\ud83c\udfe0 \u0645\u0646\u0648\u06cc \u0627\u0635\u0644\u06cc\", \"cmd\": \"/menu\"}]\n]]]\n\n\u2022 \u0646\u0627\u0645 \u067e\u0631\u0648\u0698\u0647: default \n\u2022 \u0622\u062f\u0631\u0633 \u0645\u062e\u0632\u0646: https://git.msa.artacloud.ir/root/default\n", "created_at": 1787995349.975879, "description": "", "conversation_titles": { @@ -96,20 +96,20 @@ } } }, - "turn_in_progress": true, - "last_prompt": "\u0645\u06cc\u062e\u0648\u0627\u0645 \u062a\u0645\u0627\u0645 \u0645\u0642\u0627\u062f\u06cc\u0631 \u0631\u0648 \u062e\u0648\u062f\u0645 \u0648\u0627\u0631\u062f \u06a9\u0646\u0645 \u0648 \u0628\u062a\u0648\u0646\u0645 \u0648\u06cc\u0631\u0627\u06cc\u0634\u0634 \u06a9\u0646\u0645 \u0648 \u0647\u0631 \u0645\u0648\u0642\u0639 \u062e\u0648\u0627\u0633\u062a\u0645 \u0628\u0628\u06cc\u0646\u0645\u0634\u0648\u0646\n\u0645\u06cc\u062e\u0648\u0627\u0645 \u0627\u06cc\u0646 \u06a9\u0627\u0631\u0647\u0627\u0631\u0648 \u062e\u0648\u062f\u0645 \u0647\u0645 \u0628\u062a\u0648\u0646\u0645 \u0645\u0633\u062a\u0642\u06cc\u0645 \u0628\u0627 \u0631\u0628\u0627\u062a \u0628\u0632\u0646\u0645", - "last_response": "\u0628\u0631\u0627\u06cc \u0627\u06cc\u0646\u06a9\u0647 \u0628\u062a\u0648\u0627\u0646\u06cc\u062f \u062a\u0645\u0627\u0645 \u0641\u06cc\u0644\u062f\u0647\u0627\u06cc FTP \u0631\u0627 \u0628\u0647 \u0635\u0648\u0631\u062a \u06a9\u0627\u0645\u0644\u0627\u064b \u062a\u0639\u0627\u0645\u0644\u06cc \u0628\u0627 \u062f\u06a9\u0645\u0647\u200c\u0647\u0627 \u0648 \u0641\u0631\u0645 \u0627\u062e\u062a\u0635\u0627\u0635\u06cc \u062e\u0648\u062f \u0631\u0628\u0627\u062a \u0648\u0627\u0631\u062f\u060c \u0648\u06cc\u0631\u0627\u06cc\u0634\u060c \u0645\u0634\u0627\u0647\u062f\u0647 \u0648 \u062a\u0633\u062a \u06a9\u0646\u06cc\u062f\u060c \u0628\u0631\u0646\u0627\u0645\u0647 \u0632\u06cc\u0631 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0627\u0631\u062a\u0642\u0627\u06cc \u0631\u0628\u0627\u062a \u062a\u0644\u06af\u0631\u0627\u0645 \u0622\u0645\u0627\u062f\u0647 \u06a9\u0631\u062f\u0647\u200c\u0627\u0645:\n\n---\n\n### \ud83d\udccb \u0628\u0631\u0646\u0627\u0645\u0647 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u062f\u0631 \u0631\u0628\u0627\u062a \u062a\u0644\u06af\u0631\u0627\u0645 (`/root/telegram-agy-bot`):\n\n1. **\u0627\u0636\u0627\u0641\u0647 \u0634\u062f\u0646 \u0645\u0646\u0648\u06cc \u062a\u0639\u0627\u0645\u0644\u06cc \u00ab\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0648 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0645\u0634\u062e\u0635\u0627\u062a FTP\u00bb (`btn_ftp_settings`):**\n - \u062f\u06a9\u0645\u0647 **\ud83c\udf10 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0647\u0627\u0633\u062a / \u0633\u0631\u0648\u0631** (Host & Port)\n - \u062f\u06a9\u0645\u0647 **\ud83d\udc64 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0646\u0627\u0645 \u06a9\u0627\u0631\u0628\u0631\u06cc** (Username)\n - \u062f\u06a9\u0645\u0647 **\ud83d\udd11 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631** (Password)\n - \u062f\u06a9\u0645\u0647 **\ud83d\udcc2 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0645\u0633\u06cc\u0631 \u0645\u0642\u0635\u062f \u0631\u0648\u06cc \u0647\u0627\u0633\u062a** (Remote Path)\n - \u062f\u06a9\u0645\u0647 **\ud83d\udd12 \u062a\u063a\u06cc\u06cc\u0631 \u0648\u0636\u0639\u06cc\u062a FTPS / TLS** (\u0631\u0648\u0634\u0646/\u062e\u0627\u0645\u0648\u0634 \u0628\u0627 \u06cc\u06a9 \u06a9\u0644\u06cc\u06a9)\n - \u062f\u06a9\u0645\u0647 **\ud83d\uddd1\ufe0f \u067e\u0627\u06a9\u200c\u0633\u0627\u0632\u06cc \u0627\u0637\u0644\u0627\u0639\u0627\u062a FTP**\n\n2. **\u0633\u06cc\u0633\u062a\u0645 \u062d\u0627\u0644\u062a \u0648\u0631\u0648\u062f\u06cc \u062a\u0639\u0627\u0645\u0644\u06cc (Interactive Input Prompting):**\n - \u0628\u0627 \u06a9\u0644\u06cc\u06a9 \u0631\u0648\u06cc \u0647\u0631 \u062f\u06a9\u0645\u0647 (\u0645\u062b\u0644\u0627\u064b *\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0647\u0627\u0633\u062a* \u06cc\u0627 *\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631*)\u060c \u0631\u0628\u0627\u062a \u067e\u06cc\u0627\u0645 \u0631\u0627\u0647\u0646\u0645\u0627 \u0627\u0631\u0633\u0627\u0644 \u06a9\u0631\u062f\u0647 \u0648 \u0645\u0646\u062a\u0638\u0631 \u062f\u0631\u06cc\u0627\u0641\u062a \u0645\u0642\u062f\u0627\u0631 \u0627\u0631\u0633\u0627\u0644\u06cc \u0634\u0645\u0627 \u0645\u06cc\u200c\u0645\u0627\u0646\u062f \u0648 \u0628\u0644\u0627\u0641\u0627\u0635\u0644\u0647 \u0641\u06cc\u0644\u062f \u0645\u0631\u0628\u0648\u0637\u0647 \u0631\u0627 \u062f\u0631 \u067e\u0631\u0648\u0698\u0647 \u0630\u062e\u06cc\u0631\u0647 \u0648 \u0645\u0646\u0648 \u0631\u0627 \u0628\u0647\u200c\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc \u0645\u06cc\u200c\u06a9\u0646\u062f.\n\n3. **\u0646\u0645\u0627\u06cc\u0634 \u06a9\u0627\u0645\u0644 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u0648 \u062f\u06a9\u0645\u0647 \u062a\u0633\u062a \u0622\u0646\u0644\u0627\u06cc\u0646:**\n - \u067e\u0633 \u0627\u0632 \u0647\u0631 \u0648\u06cc\u0631\u0627\u06cc\u0634\u060c \u0648\u0636\u0639\u06cc\u062a \u0627\u062a\u0635\u0627\u0644 FTP \u0628\u0644\u0627\u0641\u0627\u0635\u0644\u0647 \u062f\u0631 \u067e\u0646\u0644 \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f \u0648 \u062f\u06a9\u0645\u0647 **\ud83d\udd0d \u062a\u0633\u062a \u0627\u062a\u0635\u0627\u0644 FTP** \u0627\u0645\u06a9\u0627\u0646 \u0633\u0646\u062c\u0634 \u0627\u0631\u062a\u0628\u0627\u0637 \u0622\u0646\u0644\u0627\u06cc\u0646 \u0631\u0627 \u0628\u0647 \u0634\u0645\u0627 \u0645\u06cc\u200c\u062f\u0647\u062f.\n\n---\n\n\u0622\u06cc\u0627 \u0628\u0627 \u0627\u0639\u0645\u0627\u0644 \u0627\u06cc\u0646 \u0642\u0627\u0628\u0644\u06cc\u062a\u200c\u0647\u0627 \u0648 \u0627\u0641\u0632\u0648\u062f\u0646 \u062f\u06a9\u0645\u0647\u200c\u0647\u0627\u06cc \u0648\u06cc\u0631\u0627\u06cc\u0634 \u062a\u0639\u0627\u0645\u0644\u06cc FTP \u0628\u0647 \u0631\u0628\u0627\u062a \u0645\u0648\u0627\u0641\u0642\u06cc\u062f \u062a\u0627 \u0622\u0646 \u0631\u0627 \u067e\u06cc\u0627\u062f\u0647\u200c\u0633\u0627\u0632\u06cc \u0648 \u0641\u0639\u0627\u0644 \u06a9\u0646\u0645\u061f\n\n\u2022 \u0646\u0627\u0645 \u067e\u0631\u0648\u0698\u0647: default \n\u2022 \u0622\u062f\u0631\u0633 \u0645\u062e\u0632\u0646: https://git.msa.artacloud.ir/root/default\n", - "last_status_msg_id": 1820, + "turn_in_progress": false, + "last_prompt": "\u0628\u0644\u0647", + "last_response": "\u0642\u0627\u0628\u0644\u06cc\u062a \u0645\u062f\u06cc\u0631\u06cc\u062a \u06a9\u0627\u0645\u0644 \u0648 \u062a\u0639\u0627\u0645\u0644\u06cc \u062a\u0646\u0638\u06cc\u0645\u0627\u062a FTP \u0645\u0633\u062a\u0642\u06cc\u0645\u0627\u064b \u0628\u0627 \u062f\u06a9\u0645\u0647\u200c\u0647\u0627\u06cc \u0631\u0628\u0627\u062a \u062a\u0644\u06af\u0631\u0627\u0645 \u067e\u06cc\u0627\u062f\u0647\u200c\u0633\u0627\u0632\u06cc \u0648 \u0641\u0639\u0627\u0644 \u0634\u062f.\n\n---\n\n### \u2728 \u0627\u0645\u06a9\u0627\u0646\u0627\u062a \u0648 \u062f\u06a9\u0645\u0647\u200c\u0647\u0627\u06cc \u062c\u062f\u06cc\u062f \u0627\u0636\u0627\u0641\u0647 \u0634\u062f\u0647:\n\n1. **\ud83c\udf10 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0647\u0627\u0633\u062a / \u067e\u0648\u0631\u062a (`ftp_set:host`):**\n - \u0628\u0627 \u06a9\u0644\u06cc\u06a9 \u0631\u0648\u06cc \u062f\u06a9\u0645\u0647\u060c \u0631\u0628\u0627\u062a \u0645\u0646\u062a\u0638\u0631 \u062f\u0631\u06cc\u0627\u0641\u062a \u0622\u062f\u0631\u0633 \u0647\u0627\u0633\u062a \u0645\u06cc\u200c\u0645\u0627\u0646\u062f (\u0645\u062b\u0627\u0644: `ftp.mysite.com` \u06cc\u0627 `1.2.3.4:2121`).\n2. **\ud83d\udc64 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0646\u0627\u0645 \u06a9\u0627\u0631\u0628\u0631\u06cc (`ftp_set:user`):**\n - \u0628\u0631\u0627\u06cc \u0648\u0627\u0631\u062f \u06a9\u0631\u062f\u0646 \u06cc\u0648\u0632\u0631\u0646\u06cc\u0645 \u0627\u06a9\u0627\u0646\u062a FTP.\n3. **\ud83d\udd11 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631 (`ftp_set:pass`):**\n - \u0628\u0631\u0627\u06cc \u0648\u0627\u0631\u062f \u06a9\u0631\u062f\u0646 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631 (\u067e\u0633 \u0627\u0632 \u062f\u0631\u06cc\u0627\u0641\u062a\u060c \u067e\u06cc\u0627\u0645 \u0628\u0631\u0627\u06cc \u0627\u0645\u0646\u06cc\u062a \u0628\u06cc\u0634\u062a\u0631 \u062d\u0630\u0641 \u0645\u06cc\u200c\u0634\u0648\u062f \u0648 \u062f\u0631 \u0645\u0646\u0648 \u0628\u0647 \u0635\u0648\u0631\u062a \u0645\u0627\u0633\u06a9\u200c\u0634\u062f\u0647 `\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022` \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f).\n4. **\ud83d\udcc2 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0645\u0633\u06cc\u0631 \u0631\u06cc\u0645\u0648\u062a \u0631\u0648\u06cc \u0647\u0627\u0633\u062a (`ftp_set:path`):**\n - \u0628\u0631\u0627\u06cc \u0645\u0634\u062e\u0635 \u06a9\u0631\u062f\u0646 \u0645\u0633\u06cc\u0631 \u067e\u0648\u0634\u0647 \u062f\u0631 \u0647\u0627\u0633\u062a (\u0645\u0627\u0646\u0646\u062f `/public_html` \u06cc\u0627 `/domains/mysite.com/public_html`).\n5. **\ud83d\udd12 \u0633\u0648\u06cc\u06cc\u0686 \u067e\u0631\u0648\u062a\u06a9\u0644 \u0627\u0645\u0646 FTPS / TLS (`ftp_toggle_tls`):**\n - \u0628\u0627 \u06cc\u06a9 \u06a9\u0644\u06cc\u06a9 \u0628\u06cc\u0646 FTP \u0645\u0639\u0645\u0648\u0644\u06cc \u0648 TLS \u0627\u0645\u0646 \u062a\u063a\u06cc\u06cc\u0631 \u0648\u0636\u0639\u06cc\u062a \u0645\u06cc\u200c\u062f\u0647\u062f.\n6. **\ud83d\udd0d \u062a\u0633\u062a \u062e\u0648\u062f\u06a9\u0627\u0631 \u0648 \u0622\u0646\u0644\u0627\u06cc\u0646 \u0627\u062a\u0635\u0627\u0644 FTP (`btn_ftp_test`):**\n - \u0628\u0631\u0631\u0633\u06cc \u0632\u0646\u062f\u0647 \u0635\u062d\u062a \u0645\u0634\u062e\u0635\u0627\u062a \u0627\u062a\u0635\u0627\u0644 \u0628\u0627 \u0647\u0627\u0633\u062a \u0648 \u0646\u0645\u0627\u06cc\u0634 \u0648\u0636\u0639\u06cc\u062a \u0627\u0631\u062a\u0628\u0627\u0637.\n7. **\ud83d\uddd1\ufe0f \u067e\u0627\u06a9\u200c\u0633\u0627\u0632\u06cc \u0645\u0634\u062e\u0635\u0627\u062a FTP (`ftp_clear_conf`):**\n - \u0631\u06cc\u0633\u062a \u0648 \u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u06a9\u0627\u0645\u0644 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u0627\u062a\u0635\u0627\u0644 \u062f\u0631 \u0635\u0648\u0631\u062a \u0646\u06cc\u0627\u0632.\n\n---\n\n[[RESTART_BOT]]\n\n[[BUTTONS: layout=[\n [{\"text\": \"\ud83d\ude80 \u0628\u0627\u0632 \u06a9\u0631\u062f\u0646 \u0645\u0646\u0648\u06cc FTP\", \"cmd\": \"/ftp\"}, {\"text\": \"\ud83c\udfe0 \u0645\u0646\u0648\u06cc \u0627\u0635\u0644\u06cc\", \"cmd\": \"/menu\"}]\n]]]\n\n\u2022 \u0646\u0627\u0645 \u067e\u0631\u0648\u0698\u0647: default \n\u2022 \u0622\u062f\u0631\u0633 \u0645\u062e\u0632\u0646: https://git.msa.artacloud.ir/root/default\n", + "last_status_msg_id": null, "restart_pending": false, - "last_delivered": false, - "last_update_time": 1788111971.3573058, + "last_delivered": true, + "last_update_time": 1788112105.8170931, "workspace": "/root", "conversation_id": "ce39875a-dec2-41c5-b2fe-54593a48b00c", "model": "gemini-3.7-flash-auto", "effort": "high", "language": "fa", - "last_context_length": 24319, - "last_total_tokens": 229272 + "last_context_length": 41556, + "last_total_tokens": 332309 }, "232801087": { "chat_id": 232801087,