()
| 2911 | |
| 2912 | |
| 2913 | def main(): |
| 2914 | global args, log_root_path, log_manager |
| 2915 | |
| 2916 | parser = argparse.ArgumentParser(description="Agent Log Dashboard") |
| 2917 | parser.add_argument("log_file", nargs="?", help="Path to log file to watch") |
| 2918 | parser.add_argument( |
| 2919 | "--port", type=int, default=5050, help="Dashboard port (default: 5050)" |
| 2920 | ) |
| 2921 | parser.add_argument( |
| 2922 | "--host", |
| 2923 | type=str, |
| 2924 | default="127.0.0.1", |
| 2925 | help="Dashboard host (default: 127.0.0.1)", |
| 2926 | ) |
| 2927 | parser.add_argument( |
| 2928 | "--log-root", type=str, default=None, help="Root directory to search for logs" |
| 2929 | ) |
| 2930 | parser.add_argument( |
| 2931 | "--no-browser", action="store_true", help="Don't open browser automatically" |
| 2932 | ) |
| 2933 | parser.add_argument( |
| 2934 | "--no-auto-close", |
| 2935 | action="store_false", |
| 2936 | dest="auto_close", |
| 2937 | help="Keep running after all browsers disconnect (default: auto close)", |
| 2938 | ) |
| 2939 | parser.set_defaults(auto_close=True) |
| 2940 | args = parser.parse_args() |
| 2941 | |
| 2942 | if args.log_root: |
| 2943 | log_root_path = Path(args.log_root).expanduser().resolve() |
| 2944 | else: |
| 2945 | workspace_persistent = os.environ.get("WORKSPACE_PERSISTENT") |
| 2946 | if workspace_persistent: |
| 2947 | default_root = Path(workspace_persistent) / "outputs" |
| 2948 | else: |
| 2949 | repo_root = Path(__file__).resolve().parents[1] |
| 2950 | default_root = repo_root / "outputs" |
| 2951 | log_root_path = default_root if default_root.exists() else None |
| 2952 | |
| 2953 | initial_path: Optional[Path] = None |
| 2954 | if args.log_file: |
| 2955 | try: |
| 2956 | candidate = Path(args.log_file).expanduser().resolve() |
| 2957 | except Exception: |
| 2958 | candidate = None |
| 2959 | if candidate and log_root_path: |
| 2960 | try: |
| 2961 | # Only allow selecting logs within log_root_path. |
| 2962 | candidate.relative_to(log_root_path) |
| 2963 | # Allow initial_path even if the file doesn't exist yet; |
| 2964 | # LogSession._watch_loop polls for missing files. |
| 2965 | initial_path = candidate |
| 2966 | except Exception: |
| 2967 | initial_path = None |
| 2968 | |
| 2969 | log_manager = LogManager( |
| 2970 | log_root_path, socketio, shutdown_event, initial_path=initial_path |
no test coverage detected