Add working directory per user with cd command support

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
mirivlad 2026-02-23 16:02:08 +08:00
parent c852b09148
commit 8070762310
1 changed files with 52 additions and 4 deletions

56
bot.py
View File

@ -49,6 +49,7 @@ class UserState:
input_type: Optional[str] = None # "name", "description", "icon", "command" input_type: Optional[str] = None # "name", "description", "icon", "command"
parent_menu: Optional[str] = None parent_menu: Optional[str] = None
context: Dict[str, Any] = field(default_factory=dict) context: Dict[str, Any] = field(default_factory=dict)
working_directory: Optional[str] = None # Текущая директория пользователя
class StateManager: class StateManager:
@ -270,11 +271,16 @@ async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
state_manager.reset(user.id) state_manager.reset(user.id)
# Показать текущую директорию
working_dir = config.get("working_directory", str(Path.home()))
await update.message.reply_text( await update.message.reply_text(
f"👋 Привет, {user.first_name}!\n\n" f"👋 Привет, {user.first_name}!\n\n"
f"{config.icon} *{config.name}*\n" f"{config.icon} *{config.name}*\n"
f"_{config.description}_\n\n" f"_{config.description}_\n\n"
f"*Просто отправьте CLI команду в чат* — я её выполню!\n\n" f"*Просто отправьте CLI команду в чат* — я её выполню!\n\n"
f"📁 Рабочая директория: `{working_dir}`\n\n"
f"Используйте `cd путь` для смены директории.\n"
f"Или используйте кнопки меню для быстрых команд.\n" f"Или используйте кнопки меню для быстрых команд.\n"
f"Команда /help покажет справку.", f"Команда /help покажет справку.",
parse_mode="Markdown", parse_mode="Markdown",
@ -296,6 +302,12 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
`df -h` свободное место на диске `df -h` свободное место на диске
`git status` статус git `git status` статус git
*Навигация по директориям:*
`cd путь` сменить директорию (например, `cd git/project`)
`cd ..` на уровень вверх
`cd ~` в домашнюю директорию
`pwd` показать текущую директорию
*Кнопки меню:* *Кнопки меню:*
📋 Предустановленные команды быстрые команды по категориям 📋 Предустановленные команды быстрые команды по категориям
Настройки бота изменение имени, описания, иконки Настройки бота изменение имени, описания, иконки
@ -490,10 +502,14 @@ async def menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
async def execute_cli_command(query, command: str): async def execute_cli_command(query, command: str):
"""Выполнение CLI команды.""" """Выполнение CLI команды из кнопки меню."""
working_dir = config.get("working_directory", str(Path.home())) user_id = query.from_user.id
state = state_manager.get(user_id)
logger.info(f"Выполнение команды: {command}") # Определяем рабочую директорию: сначала пользовательская, потом из конфига
working_dir = state.working_directory or config.get("working_directory", str(Path.home()))
logger.info(f"Выполнение команды: {command} в директории: {working_dir}")
await query.edit_message_text( await query.edit_message_text(
f"⏳ *Выполнение...*\n\n`{command}`", f"⏳ *Выполнение...*\n\n`{command}`",
@ -631,7 +647,39 @@ async def handle_text_message(update: Update, context: ContextTypes.DEFAULT_TYPE
async def execute_cli_command_from_message(update: Update, command: str): async def execute_cli_command_from_message(update: Update, command: str):
"""Выполнение CLI команды из сообщения.""" """Выполнение CLI команды из сообщения."""
working_dir = config.get("working_directory", str(Path.home())) user_id = update.effective_user.id
state = state_manager.get(user_id)
# Определяем рабочую директорию: сначала пользовательская, потом из конфига
working_dir = state.working_directory or config.get("working_directory", str(Path.home()))
# Обработка команды cd - меняем директорию пользователя
if command.strip().startswith("cd "):
parts = command.strip().split(maxsplit=1)
if len(parts) == 2:
target_dir = parts[1]
# Обработка ~ и относительных путей
if target_dir.startswith("~"):
target_dir = str(Path.home()) + target_dir[1:]
elif not target_dir.startswith("/"):
target_dir = str(Path(working_dir) / target_dir)
# Проверка существования директории
if Path(target_dir).is_dir():
state.working_directory = target_dir
await update.message.reply_text(
f"📁 *Директория изменена:*\n`{target_dir}`",
parse_mode="Markdown"
)
else:
await update.message.reply_text(
f"❌ *Директория не найдена:*\n`{target_dir}`",
parse_mode="Markdown"
)
return
logger.info(f"Выполнение команды: {command} в директории: {working_dir}")
try: try:
process = await asyncio.create_subprocess_shell( process = await asyncio.create_subprocess_shell(