diff --git a/bot/commands.py b/bot/commands.py
index e48e2d9..dd406e4 100644
--- a/bot/commands.py
+++ b/bot/commands.py
@@ -44,14 +44,18 @@ def _perm_label(mode: str) -> str:
def parse_command(text: str) -> Optional[Tuple[str, str]]:
"""
- Parse a slash command from text.
+ Parse a bot command from text.
Returns (command, args) or None if not a command.
+ Commands must start with COMMAND_PREFIX (default "//").
"""
+ from config import COMMAND_PREFIX
text = text.strip()
- if not text.startswith("/"):
+ if not text.startswith(COMMAND_PREFIX):
return None
- parts = text.split(None, 1)
- cmd = parts[0].lower()
+ # Strip the prefix, then split into command word and args
+ body = text[len(COMMAND_PREFIX):]
+ parts = body.split(None, 1)
+ cmd = COMMAND_PREFIX + parts[0].lower()
args = parts[1] if len(parts) > 1 else ""
return (cmd, args)
@@ -68,38 +72,39 @@ async def handle_command(user_id: str, text: str) -> Optional[str]:
logger.info("Command: %s args=%r user=...%s", cmd, args[:50], user_id[-8:])
# In ROUTER_MODE, only handle router-specific commands locally.
- # Session commands (/status, /new, /close, etc.) fall through to node forwarding.
- from config import ROUTER_MODE
- if ROUTER_MODE and cmd not in ("/nodes", "/node", "/help", "/h", "/?"):
+ # Session commands (//status, //new, //close, etc.) fall through to node forwarding.
+ from config import ROUTER_MODE, COMMAND_PREFIX
+ P = COMMAND_PREFIX
+ if ROUTER_MODE and cmd not in (P+"nodes", P+"node", P+"help", P+"h", P+"?"):
return None
set_current_user(user_id)
- if cmd in ("/new", "/n"):
+ if cmd in (P+"new", P+"n"):
return await _cmd_new(user_id, args)
- elif cmd in ("/status", "/list", "/ls", "/l"):
+ elif cmd in (P+"status", P+"list", P+"ls", P+"l"):
return await _cmd_status(user_id)
- elif cmd in ("/close", "/c"):
+ elif cmd in (P+"close", P+"c"):
return await _cmd_close(user_id, args)
- elif cmd in ("/switch", "/s"):
+ elif cmd in (P+"switch", P+"s"):
return await _cmd_switch(user_id, args)
- elif cmd == "/retry":
+ elif cmd == P+"retry":
return await _cmd_retry(user_id)
- elif cmd in ("/help", "/h", "/?"):
+ elif cmd in (P+"help", P+"h", P+"?"):
return _cmd_help()
- elif cmd == "/direct":
+ elif cmd == P+"direct":
return _cmd_direct(user_id)
- elif cmd == "/smart":
+ elif cmd == P+"smart":
return _cmd_smart(user_id)
- elif cmd == "/tasks":
+ elif cmd == P+"tasks":
return _cmd_tasks()
- elif cmd == "/shell":
+ elif cmd == P+"shell":
return await _cmd_shell(args)
- elif cmd == "/remind":
+ elif cmd == P+"remind":
return await _cmd_remind(args)
- elif cmd == "/perm":
+ elif cmd == P+"perm":
return await _cmd_perm(user_id, args)
- elif cmd in ("/nodes", "/node"):
+ elif cmd in (P+"nodes", P+"node"):
return await _cmd_nodes(user_id, args)
else:
return None
@@ -431,23 +436,24 @@ async def _cmd_nodes(user_id: str, args: str) -> str:
def _cmd_help() -> str:
"""Show help."""
- return """**Commands:**
-/new
[msg] [--timeout N] [--idle N] [--perm MODE] - Create session
-/status - Show sessions and current mode
-/close [n] - Close session (active or by number)
-/switch - Switch to session by number
-/perm [conv_id] - Set permission mode (bypass/accept/plan)
-/direct - Direct mode: messages → Claude Code (no LLM overhead)
-/smart - Smart mode: messages → LLM routing (default)
-/shell - Run shell command (bypasses LLM)
-/remind