"""CLI entry point: python -m argus [options]""" from __future__ import annotations import argparse import asyncio import json import logging import sys from argus.config import CAPTURE_INTERVAL_S from argus.loop import run_loop from argus.vlm import StepInfo, TaskContext def _parse_args() -> argparse.Namespace: p = argparse.ArgumentParser( prog="argus", description="Argus VLM — proactive focus assistant screen analyzer", ) p.add_argument("--session-id", default="00000000-0000-0000-0000-000000000000") p.add_argument("--task-title", default="(no task)") p.add_argument("--task-goal", default="") p.add_argument( "--steps-json", default=None, help='JSON array of steps: [{"id":"...", "sort_order":1, "title":"...", "status":"pending"}]', ) p.add_argument("--window-title", default="") p.add_argument("--vlm", choices=["ollama", "gemini"], default=None, help="VLM backend (default: ollama)") p.add_argument("--gemini-key", default=None, help="Override GEMINI_API_KEY env var") p.add_argument("--jwt", default=None, help="Override BACKEND_JWT env var") p.add_argument("--backend-url", default=None, help="Override BACKEND_BASE_URL env var") p.add_argument("--dry-run", action="store_true", help="Print JSON instead of POSTing") p.add_argument("--execute", action="store_true", help="Enable notification + executor flow") p.add_argument("--mock-sessions", default=None, help='JSON array of mock sessions: [{"task_title":"...", "status":"interrupted", "last_app":"VS Code", "last_file":"solution.cpp", "checkpoint_note":"stuck on impl"}]') p.add_argument("--iterations", type=int, default=None, help="Stop after N iterations") p.add_argument("-v", "--verbose", action="store_true") return p.parse_args() def main() -> None: args = _parse_args() logging.basicConfig( level=logging.DEBUG if args.verbose else logging.INFO, format="%(asctime)s %(levelname)-5s %(name)s %(message)s", datefmt="%H:%M:%S", ) # httpx logs every request/response at INFO — suppress to WARNING to avoid noisy 404s logging.getLogger("httpx").setLevel(logging.WARNING) logging.getLogger("httpcore").setLevel(logging.WARNING) steps: list[StepInfo] = [] if args.steps_json: for s in json.loads(args.steps_json): steps.append( StepInfo( id=s["id"], sort_order=s["sort_order"], title=s["title"], status=s.get("status", "pending"), checkpoint_note=s.get("checkpoint_note"), ) ) ctx = TaskContext( task_title=args.task_title, task_goal=args.task_goal, steps=steps, window_title=args.window_title, session_id=args.session_id, ) # Parse mock sessions if provided mock_sessions = None if args.mock_sessions: from argus.session import SessionInfo mock_sessions = [] for i, s in enumerate(json.loads(args.mock_sessions)): mock_sessions.append( SessionInfo( session_id=s.get("session_id", f"mock-{i}"), task_id=s.get("task_id"), task_title=s.get("task_title", ""), task_goal=s.get("task_goal", ""), status=s.get("status", "interrupted"), last_app=s.get("last_app", ""), last_file=s.get("last_file", ""), checkpoint_note=s.get("checkpoint_note", ""), started_at=s.get("started_at", ""), ended_at=s.get("ended_at"), minutes_ago=s.get("minutes_ago", 30), ) ) asyncio.run( run_loop( ctx, api_key=args.gemini_key, vlm_backend=args.vlm, jwt=args.jwt, base_url=args.backend_url, dry_run=args.dry_run, max_iterations=args.iterations, auto_execute=args.execute, mock_sessions=mock_sessions, ) ) if __name__ == "__main__": main()