Files
LockInBroMacOS/argus/__main__.py

114 lines
4.1 KiB
Python
Raw Normal View History

2026-03-29 06:29:18 -04:00
"""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()