From 6d9a3a4902e6cb978c9d2a1b2c3ba6cadcb13942 Mon Sep 17 00:00:00 2001 From: Matvii Sakhnenko Date: Tue, 7 Apr 2026 13:04:16 +0200 Subject: [PATCH] feat: add vault commands to Telegram bot menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add /today, /closeday, /capture, /schedule, /context to get_bot_commands() for Telegram menu visibility. These commands are forwarded to Claude via _handle_unknown_command — this patch only affects menu display. Ref: upstream issue #173 --- src/bot/orchestrator.py | 6 +++++ tests/unit/test_orchestrator.py | 40 ++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/bot/orchestrator.py b/src/bot/orchestrator.py index 6d9719f0..46765b56 100644 --- a/src/bot/orchestrator.py +++ b/src/bot/orchestrator.py @@ -461,6 +461,12 @@ async def get_bot_commands(self) -> list: # type: ignore[type-arg] BotCommand("verbose", "Set output verbosity (0/1/2)"), BotCommand("repo", "List repos / switch workspace"), BotCommand("restart", "Restart the bot"), + # Vault commands (forwarded to Claude via _handle_unknown_command) + BotCommand("today", "Morning briefing and daily plan"), + BotCommand("closeday", "End of day review and reflection"), + BotCommand("capture", "Quick capture a thought"), + BotCommand("schedule", "Plan your week"), + BotCommand("context", "Load context for a topic"), ] if self.settings.enable_project_threads: commands.append(BotCommand("sync_threads", "Sync project topics")) diff --git a/tests/unit/test_orchestrator.py b/tests/unit/test_orchestrator.py index ce5e419e..cd595fdb 100644 --- a/tests/unit/test_orchestrator.py +++ b/tests/unit/test_orchestrator.py @@ -156,13 +156,16 @@ def test_agentic_registers_text_document_photo_handlers(agentic_settings, deps): async def test_agentic_bot_commands(agentic_settings, deps): - """Agentic mode returns 6 bot commands.""" + """Agentic mode returns 11 bot commands (6 core + 5 vault).""" orchestrator = MessageOrchestrator(agentic_settings, deps) commands = await orchestrator.get_bot_commands() - assert len(commands) == 6 + assert len(commands) == 11 cmd_names = [c.command for c in commands] - assert cmd_names == ["start", "new", "status", "verbose", "repo", "restart"] + assert cmd_names == [ + "start", "new", "status", "verbose", "repo", "restart", + "today", "closeday", "capture", "schedule", "context", + ] async def test_classic_bot_commands(classic_settings, deps): @@ -990,3 +993,34 @@ async def test_bot_suffixed_command_not_forwarded(agentic_settings, deps): ) as mock_claude: await orchestrator._handle_unknown_command(update, context) mock_claude.assert_not_called() + + +# --- Vault commands menu tests --- + +VAULT_COMMANDS = {"today", "closeday", "capture", "schedule", "context"} + + +class TestVaultCommandsMenu: + """Vault commands appear in the bot menu but pass through to Claude.""" + + async def test_vault_commands_in_bot_command_list(self, agentic_settings, deps): + """Vault commands appear in the Telegram command menu.""" + orchestrator = MessageOrchestrator(agentic_settings, deps) + commands = await orchestrator.get_bot_commands() + cmd_names = {c.command for c in commands} + assert VAULT_COMMANDS.issubset(cmd_names), ( + f"Missing vault commands: {VAULT_COMMANDS - cmd_names}" + ) + + async def test_vault_commands_not_in_known_commands(self, agentic_settings, deps): + """Vault commands are NOT in _known_commands so they forward to Claude.""" + orchestrator = MessageOrchestrator(agentic_settings, deps) + # register_handlers populates _known_commands + app = MagicMock() + app.add_handler = MagicMock() + orchestrator.register_handlers(app) + + for cmd in VAULT_COMMANDS: + assert cmd not in orchestrator._known_commands, ( + f"/{cmd} should NOT be a known command — it must pass through to Claude" + )