@elizaos/sweagent-root 2.0.0-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +270 -0
- package/package.json +71 -0
- package/python/LICENSE +21 -0
- package/python/config/README.md +15 -0
- package/python/config/bash_only.yaml +222 -0
- package/python/config/benchmarks/250212_sweagent_heavy_sbl.yaml +188 -0
- package/python/config/benchmarks/250225_anthropic_filemap_simple_review.yaml +75 -0
- package/python/config/benchmarks/250522_anthropic_filemap_simple_review.yaml +92 -0
- package/python/config/benchmarks/250526_anthropic_filemap_simple_review_sbl.yaml +93 -0
- package/python/config/benchmarks/anthropic_filemap_multilingual.yaml +66 -0
- package/python/config/coding_challenge.yaml +104 -0
- package/python/config/default.yaml +69 -0
- package/python/config/default_backticks.yaml +69 -0
- package/python/config/default_mm_no_images.yaml +82 -0
- package/python/config/default_mm_with_images.yaml +83 -0
- package/python/config/demo/default.yaml +80 -0
- package/python/config/demo/no_instructions.yaml +69 -0
- package/python/config/demo/only_bash.yaml +60 -0
- package/python/config/exotic/default_shell.yaml +52 -0
- package/python/config/exotic/windowed_replace.yaml +125 -0
- package/python/config/exotic/windowed_replace_late_repro.yaml +127 -0
- package/python/config/human/human.yaml +24 -0
- package/python/config/human/human_demo.yaml +52 -0
- package/python/config/sweagent_0_7/07.yaml +101 -0
- package/python/config/sweagent_0_7/07_fcalling.yaml +100 -0
- package/python/config/sweagent_0_7/07_from_url.yaml +114 -0
- package/python/config/sweagent_0_7/07_thought_action.yaml +102 -0
- package/python/config/sweagent_0_7/07_thought_action_xml.yaml +96 -0
- package/python/mlc_config.json +44 -0
- package/python/pyproject.toml +262 -0
- package/python/sweagent/__init__.py +114 -0
- package/python/sweagent/__main__.py +4 -0
- package/python/sweagent/agent/__init__.py +0 -0
- package/python/sweagent/agent/action_sampler.py +317 -0
- package/python/sweagent/agent/agents.py +1294 -0
- package/python/sweagent/agent/extra/shell_agent.py +106 -0
- package/python/sweagent/agent/history_processors.py +399 -0
- package/python/sweagent/agent/hooks/__init__.py +0 -0
- package/python/sweagent/agent/hooks/abstract.py +139 -0
- package/python/sweagent/agent/hooks/status.py +34 -0
- package/python/sweagent/agent/models.py +896 -0
- package/python/sweagent/agent/problem_statement.py +312 -0
- package/python/sweagent/agent/reviewer.py +664 -0
- package/python/sweagent/environment/__init__.py +0 -0
- package/python/sweagent/environment/hooks/__init__.py +0 -0
- package/python/sweagent/environment/hooks/abstract.py +60 -0
- package/python/sweagent/environment/hooks/status.py +28 -0
- package/python/sweagent/environment/repo.py +219 -0
- package/python/sweagent/environment/swe_env.py +276 -0
- package/python/sweagent/exceptions.py +54 -0
- package/python/sweagent/inspector/README.md +6 -0
- package/python/sweagent/inspector/__init__.py +0 -0
- package/python/sweagent/inspector/favicon.ico +0 -0
- package/python/sweagent/inspector/fileViewer.js +354 -0
- package/python/sweagent/inspector/icons/computer.png +0 -0
- package/python/sweagent/inspector/icons/edit_icon.svg +11 -0
- package/python/sweagent/inspector/icons/swe-agent-logo-50.png +0 -0
- package/python/sweagent/inspector/icons/swellama_blue.png +0 -0
- package/python/sweagent/inspector/icons/swellama_brown.png +0 -0
- package/python/sweagent/inspector/icons/swellama_grey.png +0 -0
- package/python/sweagent/inspector/icons/swellama_tan.png +0 -0
- package/python/sweagent/inspector/index.html +25 -0
- package/python/sweagent/inspector/server.py +354 -0
- package/python/sweagent/inspector/static.py +169 -0
- package/python/sweagent/inspector/style.css +454 -0
- package/python/sweagent/run/__init__.py +0 -0
- package/python/sweagent/run/_progress.py +158 -0
- package/python/sweagent/run/batch_instances.py +419 -0
- package/python/sweagent/run/common.py +387 -0
- package/python/sweagent/run/compare_runs.py +123 -0
- package/python/sweagent/run/extract_pred.py +19 -0
- package/python/sweagent/run/hooks/__init__.py +0 -0
- package/python/sweagent/run/hooks/abstract.py +67 -0
- package/python/sweagent/run/hooks/apply_patch.py +106 -0
- package/python/sweagent/run/hooks/open_pr.py +244 -0
- package/python/sweagent/run/hooks/swe_bench_evaluate.py +113 -0
- package/python/sweagent/run/inspector_cli.py +493 -0
- package/python/sweagent/run/merge_predictions.py +64 -0
- package/python/sweagent/run/quick_stats.py +96 -0
- package/python/sweagent/run/remove_unfinished.py +63 -0
- package/python/sweagent/run/rich_test.py +91 -0
- package/python/sweagent/run/run.py +147 -0
- package/python/sweagent/run/run_batch.py +442 -0
- package/python/sweagent/run/run_replay.py +219 -0
- package/python/sweagent/run/run_shell.py +155 -0
- package/python/sweagent/run/run_single.py +225 -0
- package/python/sweagent/run/run_traj_to_demo.py +85 -0
- package/python/sweagent/tools/__init__.py +0 -0
- package/python/sweagent/tools/bundle.py +57 -0
- package/python/sweagent/tools/commands.py +220 -0
- package/python/sweagent/tools/parsing.py +619 -0
- package/python/sweagent/tools/tools.py +430 -0
- package/python/sweagent/tools/utils.py +108 -0
- package/python/sweagent/types.py +102 -0
- package/python/sweagent/utils/__init__.py +0 -0
- package/python/sweagent/utils/config.py +80 -0
- package/python/sweagent/utils/files.py +27 -0
- package/python/sweagent/utils/github.py +118 -0
- package/python/sweagent/utils/jinja_warnings.py +14 -0
- package/python/sweagent/utils/log.py +175 -0
- package/python/sweagent/utils/patch_formatter.py +152 -0
- package/python/sweagent/utils/serialization.py +45 -0
- package/python/tests/__init__.py +0 -0
- package/python/tests/conftest.py +191 -0
- package/python/tests/test_agent.py +258 -0
- package/python/tests/test_batch_instance.py +43 -0
- package/python/tests/test_commands/_interactive_dummy.py +35 -0
- package/python/tests/test_commands/interactive_dummy_wrapper.sh +29 -0
- package/python/tests/test_data/config_files/dummy_interactive.yaml +62 -0
- package/python/tests/test_data/data_sources/ctf/crypto/Katy/Dockerfile +20 -0
- package/python/tests/test_data/data_sources/ctf/crypto/Katy/README.md +13 -0
- package/python/tests/test_data/data_sources/ctf/crypto/Katy/challenge.json +12 -0
- package/python/tests/test_data/data_sources/ctf/crypto/Katy/customrandom.c +50 -0
- package/python/tests/test_data/data_sources/ctf/crypto/Katy/docker-compose.yml +14 -0
- package/python/tests/test_data/data_sources/ctf/crypto/Katy/release +0 -0
- package/python/tests/test_data/data_sources/ctf/crypto/Katy/server +0 -0
- package/python/tests/test_data/data_sources/ctf/crypto/Katy/solver.py +12 -0
- package/python/tests/test_data/data_sources/ctf/forensics/flash/README.md +16 -0
- package/python/tests/test_data/data_sources/ctf/forensics/flash/challenge.json +9 -0
- package/python/tests/test_data/data_sources/ctf/forensics/flash/flash_c8429a430278283c0e571baebca3d139.zip +0 -0
- package/python/tests/test_data/data_sources/ctf/misc/networking_1/README.md +15 -0
- package/python/tests/test_data/data_sources/ctf/misc/networking_1/challenge.json +10 -0
- package/python/tests/test_data/data_sources/ctf/misc/networking_1/networking.pcap +0 -0
- package/python/tests/test_data/data_sources/ctf/pwn/warmup/Dockerfile +28 -0
- package/python/tests/test_data/data_sources/ctf/pwn/warmup/README.md +14 -0
- package/python/tests/test_data/data_sources/ctf/pwn/warmup/challenge.json +14 -0
- package/python/tests/test_data/data_sources/ctf/pwn/warmup/docker-compose.yml +14 -0
- package/python/tests/test_data/data_sources/ctf/pwn/warmup/flag.txt +1 -0
- package/python/tests/test_data/data_sources/ctf/pwn/warmup/warmup +0 -0
- package/python/tests/test_data/data_sources/ctf/pwn/warmup/warmup.c +26 -0
- package/python/tests/test_data/data_sources/ctf/pwn/warmup/warmup.py +9 -0
- package/python/tests/test_data/data_sources/ctf/rev/rock/README.md +14 -0
- package/python/tests/test_data/data_sources/ctf/rev/rock/challenge.json +8 -0
- package/python/tests/test_data/data_sources/ctf/rev/rock/rock +0 -0
- package/python/tests/test_data/data_sources/ctf/rev/rock/rock.cpp +167 -0
- package/python/tests/test_data/data_sources/ctf/rev/rock/solution.cpp +24 -0
- package/python/tests/test_data/data_sources/ctf/rev/rock/test_solver/solution.py +6 -0
- package/python/tests/test_data/data_sources/ctf/rev/rock/test_solver/test.sh +10 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/000-default.conf +18 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/Dockerfile +20 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/cgi/file.pl +38 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/cgi/forms.pl +40 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/cgi/hello.pl +11 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/challenge.json +12 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/docker-compose.yml +14 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/flag +1 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/index.html +11 -0
- package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/solution.txt +1 -0
- package/python/tests/test_data/data_sources/debug_20240322.json +1 -0
- package/python/tests/test_data/data_sources/expert_instances.yaml +16 -0
- package/python/tests/test_data/data_sources/human_eval.json +1 -0
- package/python/tests/test_data/data_sources/simple_instances.yaml +3 -0
- package/python/tests/test_data/data_sources/simple_instances_long.yaml +30 -0
- package/python/tests/test_data/data_sources/swe-bench-dev-easy.json +1 -0
- package/python/tests/test_data/data_sources/swe-bench-dev-easy_first_only.json +1 -0
- package/python/tests/test_data/data_sources/swe-bench-lite-test.json +1 -0
- package/python/tests/test_data/trajectories/gpt4__swe-agent-test-repo__default_from_url__t-0.00__p-0.95__c-3.00__install-1/6e44b9__sweagenttestrepo-1c2844.traj +342 -0
- package/python/tests/test_data/trajectories/gpt4__swe-agent-test-repo__default_from_url__t-0.00__p-0.95__c-3.00__install-1/solution_missing_colon.py +15 -0
- package/python/tests/test_data/trajectories/gpt4__swe-agent__test-repo__default_from_url__t-0.00__p-0.95__c-3.00__install-1/args.yaml +518 -0
- package/python/tests/test_data/trajectories/gpt4__swe-agent__test-repo__default_from_url__t-0.00__p-0.95__c-3.00__install-1/swe-agent__test-repo-i1.traj +124 -0
- package/python/tests/test_data/trajectories/gpt4__swe-bench-dev-easy_first_only__default__t-0.00__p-0.95__c-3.00__install-1/all_preds.jsonl +1 -0
- package/python/tests/test_data/trajectories/gpt4__swe-bench-dev-easy_first_only__default__t-0.00__p-0.95__c-3.00__install-1/args.yaml +520 -0
- package/python/tests/test_data/trajectories/gpt4__swe-bench-dev-easy_first_only__default__t-0.00__p-0.95__c-3.00__install-1/patches/pydicom__pydicom-1458.patch +18 -0
- package/python/tests/test_data/trajectories/gpt4__swe-bench-dev-easy_first_only__default__t-0.00__p-0.95__c-3.00__install-1/pydicom__pydicom-1458.traj +257 -0
- package/python/tests/test_env.py +66 -0
- package/python/tests/test_env_utils.py +129 -0
- package/python/tests/test_history_processors.py +40 -0
- package/python/tests/test_models.py +23 -0
- package/python/tests/test_openai_live.py +164 -0
- package/python/tests/test_packaging.py +7 -0
- package/python/tests/test_parsing.py +131 -0
- package/python/tests/test_problem_statement_multimodal.py +111 -0
- package/python/tests/test_quick_stats.py +42 -0
- package/python/tests/test_run.py +37 -0
- package/python/tests/test_run_batch.py +110 -0
- package/python/tests/test_run_hooks.py +114 -0
- package/python/tests/test_run_replay.py +33 -0
- package/python/tests/test_run_single.py +125 -0
- package/python/tests/test_tools_command_parsing.py +193 -0
- package/python/tests/test_utils.py +15 -0
- package/python/tests/tools/__init__.py +0 -0
- package/python/tests/tools/conftest.py +12 -0
- package/python/tests/tools/test_default_utils.py +153 -0
- package/python/tests/tools/test_edit_replace.py +0 -0
- package/python/tests/tools/test_split_string.py +82 -0
- package/python/tests/utils.py +29 -0
- package/python/tools/diff_state/bin/_state_diff_state +52 -0
- package/python/tools/diff_state/config.yaml +2 -0
- package/python/tools/edit_anthropic/bin/_state_anthropic +21 -0
- package/python/tools/edit_anthropic/bin/str_replace_editor +710 -0
- package/python/tools/edit_anthropic/config.yaml +56 -0
- package/python/tools/edit_anthropic/install.sh +3 -0
- package/python/tools/filemap/bin/filemap +45 -0
- package/python/tools/filemap/config.yaml +9 -0
- package/python/tools/filemap/install.sh +2 -0
- package/python/tools/forfeit/bin/exit_forfeit +5 -0
- package/python/tools/forfeit/config.yaml +5 -0
- package/python/tools/image_tools/bin/view_image +36 -0
- package/python/tools/image_tools/config.yaml +9 -0
- package/python/tools/multilingual_setup/bin/do_nothing +2 -0
- package/python/tools/multilingual_setup/config.yaml +1 -0
- package/python/tools/multilingual_setup/install.sh +45 -0
- package/python/tools/registry/bin/_read_env +10 -0
- package/python/tools/registry/bin/_write_env +10 -0
- package/python/tools/registry/config.yaml +1 -0
- package/python/tools/registry/install.sh +6 -0
- package/python/tools/registry/lib/__init__.py +0 -0
- package/python/tools/registry/lib/registry.py +56 -0
- package/python/tools/review_on_submit_m/README.md +6 -0
- package/python/tools/review_on_submit_m/bin/submit +54 -0
- package/python/tools/review_on_submit_m/config.yaml +6 -0
- package/python/tools/review_on_submit_m/install.sh +0 -0
- package/python/tools/search/bin/find_file +31 -0
- package/python/tools/search/bin/search_dir +39 -0
- package/python/tools/search/bin/search_file +55 -0
- package/python/tools/search/config.yaml +37 -0
- package/python/tools/search/install.sh +3 -0
- package/python/tools/submit/bin/submit +17 -0
- package/python/tools/submit/config.yaml +5 -0
- package/python/tools/web_browser/bin/click_mouse +41 -0
- package/python/tools/web_browser/bin/close_site +28 -0
- package/python/tools/web_browser/bin/double_click_mouse +37 -0
- package/python/tools/web_browser/bin/drag_mouse +46 -0
- package/python/tools/web_browser/bin/execute_script_on_page +39 -0
- package/python/tools/web_browser/bin/get_console_output +48 -0
- package/python/tools/web_browser/bin/move_mouse +35 -0
- package/python/tools/web_browser/bin/navigate_back +33 -0
- package/python/tools/web_browser/bin/navigate_forward +33 -0
- package/python/tools/web_browser/bin/open_site +36 -0
- package/python/tools/web_browser/bin/press_keys_on_page +51 -0
- package/python/tools/web_browser/bin/reload_page +33 -0
- package/python/tools/web_browser/bin/run_web_browser_server +394 -0
- package/python/tools/web_browser/bin/screenshot_site +38 -0
- package/python/tools/web_browser/bin/scroll_on_page +40 -0
- package/python/tools/web_browser/bin/set_browser_window_size +40 -0
- package/python/tools/web_browser/bin/type_text +34 -0
- package/python/tools/web_browser/bin/wait_time +39 -0
- package/python/tools/web_browser/config.yaml +155 -0
- package/python/tools/web_browser/install.sh +22 -0
- package/python/tools/web_browser/lib/browser_manager.py +404 -0
- package/python/tools/web_browser/lib/web_browser_config.py +33 -0
- package/python/tools/web_browser/lib/web_browser_utils.py +126 -0
- package/python/tools/web_browser/test_console.html +1 -0
- package/python/tools/windowed/bin/_state +25 -0
- package/python/tools/windowed/bin/create +29 -0
- package/python/tools/windowed/bin/goto +37 -0
- package/python/tools/windowed/bin/open +49 -0
- package/python/tools/windowed/bin/scroll_down +12 -0
- package/python/tools/windowed/bin/scroll_up +13 -0
- package/python/tools/windowed/config.yaml +38 -0
- package/python/tools/windowed/install.sh +15 -0
- package/python/tools/windowed/lib/__init__.py +0 -0
- package/python/tools/windowed/lib/flake8_utils.py +147 -0
- package/python/tools/windowed/lib/windowed_file.py +312 -0
- package/python/tools/windowed_edit_linting/bin/edit +128 -0
- package/python/tools/windowed_edit_linting/config.yaml +31 -0
- package/python/tools/windowed_edit_linting/install.sh +5 -0
- package/python/tools/windowed_edit_replace/bin/edit +172 -0
- package/python/tools/windowed_edit_replace/bin/insert +77 -0
- package/python/tools/windowed_edit_replace/config.yaml +60 -0
- package/python/tools/windowed_edit_replace/install.sh +5 -0
- package/python/tools/windowed_edit_rewrite/bin/edit +78 -0
- package/python/tools/windowed_edit_rewrite/config.yaml +11 -0
- package/python/tools/windowed_edit_rewrite/install.sh +5 -0
- package/python/trajectories/demonstrations/ctf/crypto/BabyEncryption.traj +318 -0
- package/python/trajectories/demonstrations/ctf/crypto/BabyTimeCapsule.traj +197 -0
- package/python/trajectories/demonstrations/ctf/crypto/eps.traj +289 -0
- package/python/trajectories/demonstrations/ctf/crypto/katy.traj +368 -0
- package/python/trajectories/demonstrations/ctf/forensics/flash.traj +102 -0
- package/python/trajectories/demonstrations/ctf/misc/networking_1.traj +102 -0
- package/python/trajectories/demonstrations/ctf/pwn/warmup.traj +159 -0
- package/python/trajectories/demonstrations/ctf/rev/rock.traj +251 -0
- package/python/trajectories/demonstrations/ctf/web/i_got_id_demo.traj +422 -0
- package/python/trajectories/demonstrations/function_calling_simple.traj +151 -0
- package/python/trajectories/demonstrations/human_thought__swe-bench-HumanEvalFix-python__lcb__t-0.00__p-0.95__c-4.00__install-0/humanevalfix-python-0.traj +129 -0
- package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__default__t-0.20__p-0.95__c-2.00__install-1___install_from_source/marshmallow-code__marshmallow-1867.traj +318 -0
- package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__default_sys-env_cursors_window100__t-0.20__p-0.95__c-2.00__install-1/marshmallow-code__marshmallow-1867.traj +251 -0
- package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__default_sys-env_window100__t-0.20__p-0.95__c-2.00__install-1/marshmallow-code__marshmallow-1867.traj +399 -0
- package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__function_calling__install-1/marshmallow-code__marshmallow-1867.traj +594 -0
- package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__function_calling_replace__install-1/marshmallow-code__marshmallow-1867.traj +592 -0
- package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__function_calling_replace_from_source/marshmallow-code__marshmallow-1867.traj +3316 -0
- package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__xml_sys-env_cursors_window100__t-0.20__p-0.95__c-2.00__install-1/marshmallow-code__marshmallow-1867.traj +251 -0
- package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__xml_sys-env_window100__t-0.20__p-0.95__c-2.00__install-1/marshmallow-code__marshmallow-1867.traj +399 -0
- package/python/trajectories/demonstrations/str_replace_anthropic_demo.yaml +432 -0
- package/rust/Cargo.toml +100 -0
- package/rust/README.md +49 -0
- package/rust/src/agent/action_sampler.rs +130 -0
- package/rust/src/agent/agents.rs +1029 -0
- package/rust/src/agent/history_processors.rs +277 -0
- package/rust/src/agent/hooks/mod.rs +208 -0
- package/rust/src/agent/mod.rs +24 -0
- package/rust/src/agent/models.rs +837 -0
- package/rust/src/agent/problem_statement.rs +355 -0
- package/rust/src/agent/reviewer.rs +505 -0
- package/rust/src/bin/sweagent.rs +784 -0
- package/rust/src/environment/deployment.rs +631 -0
- package/rust/src/environment/hooks/mod.rs +114 -0
- package/rust/src/environment/mod.rs +16 -0
- package/rust/src/environment/repo.rs +265 -0
- package/rust/src/environment/runtime.rs +237 -0
- package/rust/src/environment/swe_env.rs +248 -0
- package/rust/src/exceptions.rs +228 -0
- package/rust/src/lib.rs +68 -0
- package/rust/src/monitoring.rs +482 -0
- package/rust/src/run/hooks/mod.rs +134 -0
- package/rust/src/run/mod.rs +12 -0
- package/rust/src/run/run_batch.rs +563 -0
- package/rust/src/run/run_single.rs +196 -0
- package/rust/src/tools/bundle.rs +224 -0
- package/rust/src/tools/commands.rs +173 -0
- package/rust/src/tools/mod.rs +295 -0
- package/rust/src/tools/parsing.rs +354 -0
- package/rust/src/tools/registry.rs +143 -0
- package/rust/src/types.rs +554 -0
- package/rust/src/utils/config.rs +105 -0
- package/rust/src/utils/files.rs +137 -0
- package/rust/src/utils/github.rs +171 -0
- package/rust/src/utils/log.rs +65 -0
- package/rust/src/utils/mod.rs +17 -0
- package/rust/src/utils/serialization.rs +181 -0
- package/rust/src/utils/template.rs +173 -0
- package/typescript/README.md +335 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
#!/root/python3.11/bin/python3
|
|
2
|
+
"""Web Browser server ‒ Flask + Playwright backend."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import atexit
|
|
7
|
+
import functools
|
|
8
|
+
import signal
|
|
9
|
+
import sys
|
|
10
|
+
import time
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
lib_path = str(Path(__file__).resolve().parent.parent / "lib")
|
|
15
|
+
sys.path.insert(0, lib_path)
|
|
16
|
+
|
|
17
|
+
from browser_manager import BrowserManager
|
|
18
|
+
from flask import Flask, Response, jsonify, request
|
|
19
|
+
from web_browser_config import ServerConfig
|
|
20
|
+
from web_browser_utils import catch_error, normalize_url, validate_request
|
|
21
|
+
|
|
22
|
+
config = ServerConfig()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
browser_manager = BrowserManager()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def cleanup_on_exit():
|
|
29
|
+
"""Cleanup function for atexit and signal handlers."""
|
|
30
|
+
browser_manager.cleanup()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def signal_handler(signum, frame):
|
|
34
|
+
"""Handle shutdown signals."""
|
|
35
|
+
print(f"\nReceived signal {signum}, shutting down...")
|
|
36
|
+
cleanup_on_exit()
|
|
37
|
+
sys.exit(0)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# register cleanup handlers
|
|
41
|
+
atexit.register(cleanup_on_exit)
|
|
42
|
+
signal.signal(signal.SIGINT, signal_handler)
|
|
43
|
+
signal.signal(signal.SIGTERM, signal_handler)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
app = Flask(__name__)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def require_website_open(func):
|
|
50
|
+
"""Decorator to ensure a website is open before executing the route."""
|
|
51
|
+
|
|
52
|
+
@functools.wraps(func)
|
|
53
|
+
def wrapper(*args, **kwargs):
|
|
54
|
+
if not browser_manager.is_website_open():
|
|
55
|
+
return create_response({"status": "error", "message": "Please open a website first."}, False)
|
|
56
|
+
return func(*args, **kwargs)
|
|
57
|
+
|
|
58
|
+
return wrapper
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _get_response_metadata() -> dict[str, Any]:
|
|
62
|
+
"""Gather comprehensive metadata for API responses."""
|
|
63
|
+
metadata = {}
|
|
64
|
+
if browser_manager.is_website_open():
|
|
65
|
+
metadata["Browser Type"] = browser_manager.browser_name
|
|
66
|
+
metadata["Mouse Position"] = f"({browser_manager.mouse_x},{browser_manager.mouse_y})"
|
|
67
|
+
metadata["Viewport Size"] = f"{browser_manager.window_width}×{browser_manager.window_height}"
|
|
68
|
+
with browser_manager._browser_lock() as page:
|
|
69
|
+
metadata["Current URL"] = page.url
|
|
70
|
+
metadata["Page Title"] = page.title()
|
|
71
|
+
|
|
72
|
+
scroll_info = page.evaluate("""() => ({
|
|
73
|
+
scroll_position: { x: window.pageXOffset || document.documentElement.scrollLeft, y: window.pageYOffset || document.documentElement.scrollTop },
|
|
74
|
+
page_dimensions: { width: document.documentElement.scrollWidth, height: document.documentElement.scrollHeight },
|
|
75
|
+
visible_dimensions: { width: window.innerWidth, height: window.innerHeight }
|
|
76
|
+
})""")
|
|
77
|
+
scroll_pos = scroll_info["scroll_position"]
|
|
78
|
+
page_dims = scroll_info["page_dimensions"]
|
|
79
|
+
visible_dims = scroll_info["visible_dimensions"]
|
|
80
|
+
metadata["Scroll Position"] = f"({scroll_pos['x']},{scroll_pos['y']})"
|
|
81
|
+
metadata["Page Dimensions"] = f"{page_dims['width']}×{page_dims['height']}"
|
|
82
|
+
metadata["Visible Dimensions"] = f"{visible_dims['width']}×{visible_dims['height']}"
|
|
83
|
+
return metadata
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def create_response(data: dict[str, Any], return_screenshot: bool) -> Response:
|
|
87
|
+
"""Create a JSON response with comprehensive metadata and optional screenshot."""
|
|
88
|
+
response_data = {**data}
|
|
89
|
+
if return_screenshot:
|
|
90
|
+
response_data.update(browser_manager.take_screenshot())
|
|
91
|
+
if "metadata" not in response_data:
|
|
92
|
+
response_data["metadata"] = {}
|
|
93
|
+
response_data["metadata"].update(_get_response_metadata())
|
|
94
|
+
return jsonify(response_data)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@app.route("/info", methods=["GET"])
|
|
98
|
+
@catch_error
|
|
99
|
+
def info():
|
|
100
|
+
if not browser_manager.is_website_open():
|
|
101
|
+
return create_response({"status": "success", "message": "No page open"}, False)
|
|
102
|
+
data = {
|
|
103
|
+
"status": "success",
|
|
104
|
+
"message": "Loaded info for current page",
|
|
105
|
+
}
|
|
106
|
+
return create_response(data, False)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@app.route("/close", methods=["POST"])
|
|
110
|
+
@catch_error
|
|
111
|
+
def close_browser():
|
|
112
|
+
browser_manager.cleanup()
|
|
113
|
+
browser_manager._init_browser()
|
|
114
|
+
return create_response({"status": "success", "message": "Closed browser"}, False)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@app.route("/set_window_size", methods=["POST"])
|
|
118
|
+
@validate_request("width", "height", "return_screenshot")
|
|
119
|
+
@require_website_open
|
|
120
|
+
@catch_error
|
|
121
|
+
def set_window_size():
|
|
122
|
+
width, height = request.json["width"], request.json["height"]
|
|
123
|
+
return_screenshot = request.json["return_screenshot"]
|
|
124
|
+
if width <= 0 or height <= 0:
|
|
125
|
+
return create_response(
|
|
126
|
+
{"status": "error", "message": f"Invalid dimensions ({width},{height}). Must be positive"}, False
|
|
127
|
+
)
|
|
128
|
+
with browser_manager._browser_lock() as page:
|
|
129
|
+
page.set_viewport_size({"width": width, "height": height})
|
|
130
|
+
browser_manager.window_width = width
|
|
131
|
+
browser_manager.window_height = height
|
|
132
|
+
browser_manager.constrain_mouse_position(page)
|
|
133
|
+
data = {"status": "success", "message": f"Set viewport to {width}×{height}"}
|
|
134
|
+
return create_response(data, return_screenshot)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@app.route("/screenshot", methods=["GET"])
|
|
138
|
+
@require_website_open
|
|
139
|
+
def screenshot():
|
|
140
|
+
data = {"status": "success", "message": "Screenshot"}
|
|
141
|
+
return create_response(data, True)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@app.route("/click", methods=["POST"])
|
|
145
|
+
@validate_request("x", "y", "button", "return_screenshot")
|
|
146
|
+
@catch_error
|
|
147
|
+
@require_website_open
|
|
148
|
+
def click():
|
|
149
|
+
x, y = round(request.json["x"]), round(request.json["y"])
|
|
150
|
+
button = request.json["button"]
|
|
151
|
+
return_screenshot = request.json["return_screenshot"]
|
|
152
|
+
x_valid, y_valid = browser_manager.validate_coordinates(x, y)
|
|
153
|
+
if not x_valid or not y_valid:
|
|
154
|
+
return create_response(
|
|
155
|
+
{
|
|
156
|
+
"status": "error",
|
|
157
|
+
"message": f"Invalid coordinates ({x},{y}). Must be within {browser_manager.window_width}x{browser_manager.window_height}",
|
|
158
|
+
},
|
|
159
|
+
False,
|
|
160
|
+
)
|
|
161
|
+
with browser_manager._browser_lock() as page:
|
|
162
|
+
page.mouse.click(x, y, button=button)
|
|
163
|
+
browser_manager.mouse_x, browser_manager.mouse_y = x, y
|
|
164
|
+
data = {"status": "success", "message": f"Clicked '{button}' at ({x},{y})"}
|
|
165
|
+
return create_response(data, return_screenshot)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@app.route("/double_click", methods=["POST"])
|
|
169
|
+
@validate_request("x", "y", "return_screenshot")
|
|
170
|
+
@catch_error
|
|
171
|
+
@require_website_open
|
|
172
|
+
def double_click():
|
|
173
|
+
x, y = round(request.json["x"]), round(request.json["y"])
|
|
174
|
+
return_screenshot = request.json["return_screenshot"]
|
|
175
|
+
x_valid, y_valid = browser_manager.validate_coordinates(x, y)
|
|
176
|
+
if not x_valid or not y_valid:
|
|
177
|
+
return create_response(
|
|
178
|
+
{
|
|
179
|
+
"status": "error",
|
|
180
|
+
"message": f"Invalid coordinates ({x},{y}). Must be within {browser_manager.window_width}x{browser_manager.window_height}",
|
|
181
|
+
},
|
|
182
|
+
False,
|
|
183
|
+
)
|
|
184
|
+
with browser_manager._browser_lock() as page:
|
|
185
|
+
page.mouse.dblclick(x, y)
|
|
186
|
+
browser_manager.mouse_x, browser_manager.mouse_y = x, y
|
|
187
|
+
data = {"status": "success", "message": f"Double‑clicked at ({x},{y})"}
|
|
188
|
+
return create_response(data, return_screenshot)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@app.route("/move", methods=["POST"])
|
|
192
|
+
@validate_request("x", "y", "return_screenshot")
|
|
193
|
+
@catch_error
|
|
194
|
+
@require_website_open
|
|
195
|
+
def move():
|
|
196
|
+
x, y = request.json["x"], request.json["y"]
|
|
197
|
+
return_screenshot = request.json["return_screenshot"]
|
|
198
|
+
x_valid, y_valid = browser_manager.validate_coordinates(x, y)
|
|
199
|
+
if not x_valid or not y_valid:
|
|
200
|
+
return create_response(
|
|
201
|
+
{
|
|
202
|
+
"status": "error",
|
|
203
|
+
"message": f"Invalid coordinates ({x},{y}). Must be within {browser_manager.window_width}x{browser_manager.window_height}",
|
|
204
|
+
},
|
|
205
|
+
False,
|
|
206
|
+
)
|
|
207
|
+
with browser_manager._browser_lock() as page:
|
|
208
|
+
page.mouse.move(x, y)
|
|
209
|
+
browser_manager.mouse_x, browser_manager.mouse_y = x, y
|
|
210
|
+
data = {"status": "success", "message": f"Moved mouse to ({x},{y})"}
|
|
211
|
+
return create_response(data, return_screenshot)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@app.route("/drag", methods=["POST"])
|
|
215
|
+
@validate_request("path", "return_screenshot")
|
|
216
|
+
@catch_error
|
|
217
|
+
@require_website_open
|
|
218
|
+
def drag():
|
|
219
|
+
path: list[list[int]] = request.json["path"]
|
|
220
|
+
return_screenshot = request.json["return_screenshot"]
|
|
221
|
+
if not path or len(path) < 2:
|
|
222
|
+
return create_response({"status": "error", "message": "Path needs at least two points"}, False)
|
|
223
|
+
for ix, point in enumerate(path):
|
|
224
|
+
if len(point) != 2:
|
|
225
|
+
return create_response(
|
|
226
|
+
{"status": "error", "message": f"Path point {ix} must have exactly 2 coordinates"}, False
|
|
227
|
+
)
|
|
228
|
+
x, y = point
|
|
229
|
+
x_valid, y_valid = browser_manager.validate_coordinates(x, y)
|
|
230
|
+
if not x_valid or not y_valid:
|
|
231
|
+
return create_response(
|
|
232
|
+
{
|
|
233
|
+
"status": "error",
|
|
234
|
+
"message": f"Invalid coordinates ({x},{y}) at path point {ix}. Must be within {browser_manager.window_width}x{browser_manager.window_height}",
|
|
235
|
+
},
|
|
236
|
+
False,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
with browser_manager._browser_lock() as page:
|
|
240
|
+
page.mouse.move(*path[0])
|
|
241
|
+
page.mouse.down()
|
|
242
|
+
for x, y in path[1:]:
|
|
243
|
+
page.mouse.move(x, y)
|
|
244
|
+
page.mouse.up()
|
|
245
|
+
browser_manager.mouse_x, browser_manager.mouse_y = path[-1]
|
|
246
|
+
data = {"status": "success", "message": "Dragged the mouse along the path"}
|
|
247
|
+
return create_response(data, return_screenshot)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@app.route("/type", methods=["POST"])
|
|
251
|
+
@validate_request("text", "return_screenshot")
|
|
252
|
+
@catch_error
|
|
253
|
+
@require_website_open
|
|
254
|
+
def type_():
|
|
255
|
+
text = request.json["text"]
|
|
256
|
+
return_screenshot = request.json["return_screenshot"]
|
|
257
|
+
with browser_manager._browser_lock() as page:
|
|
258
|
+
page.keyboard.type(text)
|
|
259
|
+
data = {"status": "success", "message": f"Typed '{text}'"}
|
|
260
|
+
return create_response(data, return_screenshot)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@app.route("/scroll", methods=["POST"])
|
|
264
|
+
@validate_request("scroll_x", "scroll_y", "return_screenshot")
|
|
265
|
+
@catch_error
|
|
266
|
+
@require_website_open
|
|
267
|
+
def scroll():
|
|
268
|
+
delta_x, delta_y = request.json["scroll_x"], request.json["scroll_y"]
|
|
269
|
+
return_screenshot = request.json["return_screenshot"]
|
|
270
|
+
with browser_manager._browser_lock() as page:
|
|
271
|
+
page.mouse.wheel(delta_x, delta_y)
|
|
272
|
+
data = {"status": "success", "message": f"Scrolled by ({delta_x},{delta_y})"}
|
|
273
|
+
return create_response(data, return_screenshot)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@app.route("/execute_script", methods=["POST"])
|
|
277
|
+
@validate_request("script", "return_screenshot")
|
|
278
|
+
@catch_error
|
|
279
|
+
@require_website_open
|
|
280
|
+
def exec_script():
|
|
281
|
+
script = request.json["script"]
|
|
282
|
+
return_screenshot = request.json["return_screenshot"]
|
|
283
|
+
with browser_manager._browser_lock() as page:
|
|
284
|
+
result = page.evaluate(script)
|
|
285
|
+
data = {"status": "success", "message": (f"Script executed.\n<script_result>\n{result}\n</script_result>")}
|
|
286
|
+
return create_response(data, return_screenshot)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
@app.route("/back", methods=["POST"])
|
|
290
|
+
@validate_request("return_screenshot")
|
|
291
|
+
@catch_error
|
|
292
|
+
@require_website_open
|
|
293
|
+
def back():
|
|
294
|
+
return_screenshot = request.json["return_screenshot"]
|
|
295
|
+
with browser_manager._browser_lock() as page:
|
|
296
|
+
page.go_back()
|
|
297
|
+
data = {"status": "success", "message": "Navigated back"}
|
|
298
|
+
return create_response(data, return_screenshot)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
@app.route("/forward", methods=["POST"])
|
|
302
|
+
@validate_request("return_screenshot")
|
|
303
|
+
@catch_error
|
|
304
|
+
@require_website_open
|
|
305
|
+
def forward():
|
|
306
|
+
return_screenshot = request.json["return_screenshot"]
|
|
307
|
+
with browser_manager._browser_lock() as page:
|
|
308
|
+
page.go_forward()
|
|
309
|
+
data = {"status": "success", "message": "Navigated forward"}
|
|
310
|
+
return create_response(data, return_screenshot)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
@app.route("/reload", methods=["POST"])
|
|
314
|
+
@validate_request("return_screenshot")
|
|
315
|
+
@catch_error
|
|
316
|
+
@require_website_open
|
|
317
|
+
def reload():
|
|
318
|
+
return_screenshot = request.json["return_screenshot"]
|
|
319
|
+
with browser_manager._browser_lock() as page:
|
|
320
|
+
page.reload()
|
|
321
|
+
data = {"status": "success", "message": "Reloaded the page"}
|
|
322
|
+
return create_response(data, return_screenshot)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
@app.route("/wait", methods=["POST"])
|
|
326
|
+
@validate_request("ms", "return_screenshot")
|
|
327
|
+
@catch_error
|
|
328
|
+
@require_website_open
|
|
329
|
+
def wait():
|
|
330
|
+
milliseconds = request.json["ms"]
|
|
331
|
+
return_screenshot = request.json["return_screenshot"]
|
|
332
|
+
time.sleep(milliseconds / 1000.0)
|
|
333
|
+
data = {"status": "success", "message": f"Waited {milliseconds} ms"}
|
|
334
|
+
return create_response(data, return_screenshot)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
@app.route("/keypress", methods=["POST"])
|
|
338
|
+
@validate_request("keys", "return_screenshot")
|
|
339
|
+
@catch_error
|
|
340
|
+
@require_website_open
|
|
341
|
+
def keypress():
|
|
342
|
+
keys: list[str] = request.json["keys"]
|
|
343
|
+
return_screenshot = request.json["return_screenshot"]
|
|
344
|
+
if not isinstance(keys, list):
|
|
345
|
+
return create_response({"status": "error", "message": "Keys must be a list"}, False)
|
|
346
|
+
if not keys:
|
|
347
|
+
return create_response({"status": "error", "message": "Keys list empty"}, False)
|
|
348
|
+
with browser_manager._browser_lock() as _:
|
|
349
|
+
for key in keys[:-1]:
|
|
350
|
+
browser_manager.key_down(key)
|
|
351
|
+
browser_manager.key_press(keys[-1])
|
|
352
|
+
for key in reversed(keys[:-1]):
|
|
353
|
+
browser_manager.key_up(key)
|
|
354
|
+
data = {"status": "success", "message": f"Pressed keys {keys}"}
|
|
355
|
+
return create_response(data, return_screenshot)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@app.route("/goto", methods=["POST"])
|
|
359
|
+
@validate_request("url", "return_screenshot")
|
|
360
|
+
@catch_error
|
|
361
|
+
def goto():
|
|
362
|
+
url = normalize_url(request.json["url"])
|
|
363
|
+
return_screenshot = request.json["return_screenshot"]
|
|
364
|
+
with browser_manager._browser_lock() as page:
|
|
365
|
+
page.goto(url, wait_until="load")
|
|
366
|
+
data = {"status": "success", "message": f"Navigated to {url}"}
|
|
367
|
+
return create_response(data, return_screenshot)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@app.route("/console", methods=["GET"])
|
|
371
|
+
@catch_error
|
|
372
|
+
@require_website_open
|
|
373
|
+
def get_console():
|
|
374
|
+
console_messages = browser_manager.get_console_output()
|
|
375
|
+
data = {
|
|
376
|
+
"status": "success",
|
|
377
|
+
"message": f"Retrieved {len(console_messages)} console messages",
|
|
378
|
+
"console_messages": console_messages,
|
|
379
|
+
}
|
|
380
|
+
return create_response(data, False)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def main():
|
|
384
|
+
"""Run the Flask server with proper cleanup handling."""
|
|
385
|
+
try:
|
|
386
|
+
app.run(host="0.0.0.0", port=config.port, threaded=False, use_reloader=False)
|
|
387
|
+
except KeyboardInterrupt:
|
|
388
|
+
print("\nShutting down gracefully...")
|
|
389
|
+
finally:
|
|
390
|
+
cleanup_on_exit()
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
if __name__ == "__main__":
|
|
394
|
+
main()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/root/python3.11/bin/python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
from argparse import ArgumentParser
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
lib_path = str(Path(__file__).resolve().parent.parent / "lib")
|
|
9
|
+
sys.path.insert(0, lib_path)
|
|
10
|
+
|
|
11
|
+
from web_browser_config import ClientConfig
|
|
12
|
+
from web_browser_utils import (
|
|
13
|
+
ScreenshotMode,
|
|
14
|
+
_handle_screenshot,
|
|
15
|
+
_print_response_with_metadata,
|
|
16
|
+
send_request,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
config = ClientConfig()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def screenshot():
|
|
23
|
+
"""Capture a screenshot and handle it according to the default config.screenshot_mode."""
|
|
24
|
+
response = send_request(config.port, "screenshot", "GET")
|
|
25
|
+
if response is None:
|
|
26
|
+
return
|
|
27
|
+
screenshot_data = response["screenshot"]
|
|
28
|
+
_print_response_with_metadata(response)
|
|
29
|
+
if config.screenshot_mode == ScreenshotMode.SAVE:
|
|
30
|
+
_handle_screenshot(screenshot_data, ScreenshotMode.SAVE)
|
|
31
|
+
else:
|
|
32
|
+
_handle_screenshot(screenshot_data, ScreenshotMode.PRINT)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
parser = ArgumentParser()
|
|
37
|
+
args = parser.parse_args()
|
|
38
|
+
screenshot()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/root/python3.11/bin/python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
from argparse import ArgumentParser
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
lib_path = str(Path(__file__).resolve().parent.parent / "lib")
|
|
9
|
+
sys.path.insert(0, lib_path)
|
|
10
|
+
|
|
11
|
+
from web_browser_config import ClientConfig
|
|
12
|
+
from web_browser_utils import (
|
|
13
|
+
_autosave_screenshot_from_response,
|
|
14
|
+
_print_response_with_metadata,
|
|
15
|
+
send_request,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
config = ClientConfig()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def scroll(scroll_x, scroll_y):
|
|
22
|
+
"""Scroll by (scroll_x, scroll_y) pixels at current mouse position."""
|
|
23
|
+
response = send_request(
|
|
24
|
+
config.port,
|
|
25
|
+
"scroll",
|
|
26
|
+
"POST",
|
|
27
|
+
{"scroll_x": scroll_x, "scroll_y": scroll_y, "return_screenshot": config.autoscreenshot},
|
|
28
|
+
)
|
|
29
|
+
if response is None:
|
|
30
|
+
return
|
|
31
|
+
_print_response_with_metadata(response)
|
|
32
|
+
_autosave_screenshot_from_response(response, config.screenshot_mode)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
parser = ArgumentParser()
|
|
37
|
+
parser.add_argument("scroll_x", type=int, help="The number of pixels to scroll horizontally")
|
|
38
|
+
parser.add_argument("scroll_y", type=int, help="The number of pixels to scroll vertically")
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
scroll(args.scroll_x, args.scroll_y)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/root/python3.11/bin/python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
from argparse import ArgumentParser
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
lib_path = str(Path(__file__).resolve().parent.parent / "lib")
|
|
9
|
+
sys.path.insert(0, lib_path)
|
|
10
|
+
|
|
11
|
+
from web_browser_config import ClientConfig
|
|
12
|
+
from web_browser_utils import (
|
|
13
|
+
_autosave_screenshot_from_response,
|
|
14
|
+
_print_response_with_metadata,
|
|
15
|
+
send_request,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
config = ClientConfig()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def set_window_size(width, height):
|
|
22
|
+
"""Set the browser window size to the specified width and height."""
|
|
23
|
+
response = send_request(
|
|
24
|
+
config.port,
|
|
25
|
+
"set_window_size",
|
|
26
|
+
"POST",
|
|
27
|
+
{"width": width, "height": height, "return_screenshot": config.autoscreenshot},
|
|
28
|
+
)
|
|
29
|
+
if response is None:
|
|
30
|
+
return
|
|
31
|
+
_print_response_with_metadata(response)
|
|
32
|
+
_autosave_screenshot_from_response(response, config.screenshot_mode)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
parser = ArgumentParser()
|
|
37
|
+
parser.add_argument("width", type=int, help="The new width of the browser window")
|
|
38
|
+
parser.add_argument("height", type=int, help="The new height of the browser window")
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
set_window_size(args.width, args.height)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/root/python3.11/bin/python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
from argparse import ArgumentParser
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
lib_path = str(Path(__file__).resolve().parent.parent / "lib")
|
|
9
|
+
sys.path.insert(0, lib_path)
|
|
10
|
+
|
|
11
|
+
from web_browser_config import ClientConfig
|
|
12
|
+
from web_browser_utils import (
|
|
13
|
+
_autosave_screenshot_from_response,
|
|
14
|
+
_print_response_with_metadata,
|
|
15
|
+
send_request,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
config = ClientConfig()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def type(text):
|
|
22
|
+
"""Type the given text at the current cursor position."""
|
|
23
|
+
response = send_request(config.port, "type", "POST", {"text": text, "return_screenshot": config.autoscreenshot})
|
|
24
|
+
if response is None:
|
|
25
|
+
return
|
|
26
|
+
_print_response_with_metadata(response)
|
|
27
|
+
_autosave_screenshot_from_response(response, config.screenshot_mode)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
if __name__ == "__main__":
|
|
31
|
+
parser = ArgumentParser()
|
|
32
|
+
parser.add_argument("text", type=str, help="The text to type at the currently focused element")
|
|
33
|
+
args = parser.parse_args()
|
|
34
|
+
type(args.text)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/root/python3.11/bin/python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
from argparse import ArgumentParser
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
lib_path = str(Path(__file__).resolve().parent.parent / "lib")
|
|
9
|
+
sys.path.insert(0, lib_path)
|
|
10
|
+
|
|
11
|
+
from web_browser_config import ClientConfig
|
|
12
|
+
from web_browser_utils import (
|
|
13
|
+
_autosave_screenshot_from_response,
|
|
14
|
+
_print_response_with_metadata,
|
|
15
|
+
send_request,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
config = ClientConfig()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def wait(ms):
|
|
22
|
+
"""Wait for the specified number of milliseconds."""
|
|
23
|
+
response = send_request(
|
|
24
|
+
config.port,
|
|
25
|
+
"wait",
|
|
26
|
+
"POST",
|
|
27
|
+
{"ms": ms, "return_screenshot": config.autoscreenshot},
|
|
28
|
+
)
|
|
29
|
+
if response is None:
|
|
30
|
+
return
|
|
31
|
+
_print_response_with_metadata(response)
|
|
32
|
+
_autosave_screenshot_from_response(response, config.screenshot_mode)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
parser = ArgumentParser()
|
|
37
|
+
parser.add_argument("ms", type=int, help="The number of milliseconds to wait")
|
|
38
|
+
args = parser.parse_args()
|
|
39
|
+
wait(args.ms)
|