@@ -1408,6 +1408,50 @@ def main():
14081408 )
14091409 api_parser .set_defaults (action = "api" )
14101410
1411+ # Telegram adapter command (v0.18.2) - supports start|stop|status
1412+ telegram_parser = subparsers .add_parser (
1413+ "telegram" ,
1414+ help = "Manage Telegram messaging adapter (start|stop|status)" ,
1415+ parents = [parent_parser ],
1416+ )
1417+ telegram_subparsers = telegram_parser .add_subparsers (
1418+ dest = "telegram_action" , help = "telegram action to perform"
1419+ )
1420+
1421+ # Start subcommand
1422+ t_start = telegram_subparsers .add_parser (
1423+ "start" , help = "Start the Telegram adapter (polling)"
1424+ )
1425+ t_start .add_argument ("--token" , required = True , help = "Telegram bot token" )
1426+ t_start .add_argument (
1427+ "--allowed-users" ,
1428+ help = "Comma-separated Telegram user IDs allowed to interact (default: allow all)" ,
1429+ )
1430+ t_start .add_argument (
1431+ "--background" ,
1432+ action = "store_true" ,
1433+ help = "Run adapter in background/daemon mode (writes PID and health endpoint)" ,
1434+ )
1435+
1436+ # Stop subcommand
1437+ t_stop = telegram_subparsers .add_parser ("stop" , help = "Stop background Telegram adapter" )
1438+ t_stop .add_argument (
1439+ "--force" ,
1440+ action = "store_true" ,
1441+ help = "Force stop even if graceful shutdown fails" ,
1442+ )
1443+
1444+ # Status subcommand
1445+ t_status = telegram_subparsers .add_parser ("status" , help = "Show status of Telegram adapter" )
1446+ t_status .add_argument (
1447+ "--health-host" , default = "127.0.0.1" , help = "Health server host (default: 127.0.0.1)"
1448+ )
1449+ t_status .add_argument (
1450+ "--health-port" , type = int , default = 8765 , help = "Health server port (default: 8765)"
1451+ )
1452+
1453+ telegram_parser .set_defaults (action = "telegram" )
1454+
14111455 # Add model download command
14121456 download_parser = subparsers .add_parser (
14131457 "download" ,
@@ -2156,6 +2200,85 @@ def main():
21562200 )
21572201 return
21582202
2203+ # Handle telegram scaffold command
2204+ if args .action == "telegram" :
2205+ # Telegram management: start | stop | status
2206+ action = getattr (args , "telegram_action" , None )
2207+ if action == "start" :
2208+ try :
2209+ from gaia .messaging .telegram import run_telegram
2210+ except Exception as e : # pragma: no cover - runtime import error
2211+ print (f"❌ Telegram support is not available: { e } " , file = sys .stderr )
2212+ sys .exit (1 )
2213+
2214+ allowed = None
2215+ if getattr (args , "allowed_users" , None ):
2216+ try :
2217+ allowed = set (int (x .strip ()) for x in args .allowed_users .split ("," ) if x .strip ())
2218+ except Exception :
2219+ print ("Invalid --allowed-users format; expected comma-separated integers" , file = sys .stderr )
2220+ sys .exit (2 )
2221+
2222+ run_telegram (token = args .token , allowed_users = allowed , background = getattr (args , "background" , False ))
2223+ return
2224+
2225+ if action == "stop" :
2226+ import signal
2227+
2228+ pid_path = os .path .expanduser ("~/.gaia/telegram.pid" )
2229+ if not os .path .exists (pid_path ):
2230+ print ("Telegram adapter is not running (no PID file)." )
2231+ return
2232+ try :
2233+ with open (pid_path , "r" , encoding = "utf-8" ) as f :
2234+ pid = int (f .read ().strip ())
2235+ os .kill (pid , signal .SIGTERM )
2236+ print (f"Sent SIGTERM to Telegram adapter (pid { pid } )." )
2237+ try :
2238+ os .remove (pid_path )
2239+ except OSError :
2240+ pass
2241+ except ProcessLookupError :
2242+ print ("Process not found; removing stale PID file." )
2243+ try :
2244+ os .remove (pid_path )
2245+ except OSError :
2246+ pass
2247+ except PermissionError :
2248+ print ("Permission denied when attempting to stop process. Try sudo." )
2249+ sys .exit (1 )
2250+ except Exception as e :
2251+ print (f"Failed to stop Telegram adapter: { e } " )
2252+ sys .exit (1 )
2253+ return
2254+
2255+ if action == "status" :
2256+ # Prefer health endpoint; fallback to pid file existence
2257+ import urllib .request
2258+ import urllib .error
2259+
2260+ host = getattr (args , "health_host" , "127.0.0.1" )
2261+ port = getattr (args , "health_port" , 8765 )
2262+ url = f"http://{ host } :{ port } /healthz"
2263+ try :
2264+ with urllib .request .urlopen (url , timeout = 1 ) as resp :
2265+ body = resp .read ().decode ("utf-8" ).strip ()
2266+ if resp .status == 200 and body == "ok" :
2267+ print (f"Telegram adapter: healthy ({ url } )" )
2268+ return
2269+ except urllib .error .URLError :
2270+ pass
2271+
2272+ pid_path = os .path .expanduser ("~/.gaia/telegram.pid" )
2273+ if os .path .exists (pid_path ):
2274+ print ("Telegram adapter: PID file exists, but health check failed (may be starting or unhealthy)." )
2275+ else :
2276+ print ("Telegram adapter: not running" )
2277+ return
2278+
2279+ print ("No telegram action specified. Use: gaia telegram start|stop|status" , file = sys .stderr )
2280+ return
2281+
21592282 # Handle core Gaia CLI commands
21602283 if args .action in ["prompt" , "chat" , "talk" , "stats" ]:
21612284 kwargs = {
0 commit comments