computer-use-ootb-internal 0.0.139__tar.gz → 0.0.140__tar.gz
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.
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/PKG-INFO +1 -1
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/pyproject.toml +1 -1
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/guard_service.py +186 -145
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/preparation/star_rail_prepare.py +23 -1
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/.gitignore +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/README.md +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/app_teachmode.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/animation/click_animation.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/animation/icons8-select-cursor-transparent-96.gif +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/animation/test_animation.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/executor/teachmode_executor.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/gui_capture.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/utils.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/uia_tools/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/uia_tools/screenshot_cli.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/uia_tools/screenshot_service.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/llm_utils.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/oai.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/run_litellm.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/run_llm.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/aws_request.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/base.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/bash.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/collection.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/colorful_text.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/computer.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/computer_marbot.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/edit.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/run.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/computer_use_demo/tools/screen_capture.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/dependency_check.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/preparation/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/requirements-lite.txt +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/run_teachmode_ootb_args.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/service_manager.py +0 -0
- {computer_use_ootb_internal-0.0.139 → computer_use_ootb_internal-0.0.140}/src/computer_use_ootb_internal/signal_connection.py +0 -0
@@ -362,49 +362,89 @@ class GuardService(win32serviceutil.ServiceFramework):
|
|
362
362
|
|
363
363
|
# --- Command Handlers --- Now call self. for helpers
|
364
364
|
|
365
|
-
def
|
366
|
-
"""
|
367
|
-
self.log_info("Executing OOTB update...")
|
365
|
+
def _get_python_executable_from_target_exe(self):
|
366
|
+
"""Attempts to find the python.exe associated with the target executable's env."""
|
368
367
|
if not self.target_executable_path:
|
369
|
-
self.log_error("Cannot
|
370
|
-
return
|
368
|
+
self.log_error("Cannot find python.exe: target executable path is not set.")
|
369
|
+
return None
|
370
|
+
try:
|
371
|
+
exe_path_unquoted = self.target_executable_path.strip('"')
|
372
|
+
scripts_dir = os.path.dirname(exe_path_unquoted)
|
373
|
+
# Assume target exe is in a 'Scripts' directory relative to env root
|
374
|
+
env_dir = os.path.dirname(scripts_dir)
|
375
|
+
if os.path.basename(scripts_dir.lower()) != 'scripts':
|
376
|
+
self.log_warning(f"Target executable {exe_path_unquoted} not in expected 'Scripts' directory. Cannot reliably find python.exe.")
|
377
|
+
# Fallback: maybe the target IS python.exe or next to it?
|
378
|
+
env_dir = scripts_dir # Try assuming it's env root
|
379
|
+
|
380
|
+
python_exe_path = os.path.join(env_dir, 'python.exe')
|
381
|
+
self.log_info(f"Checking for python.exe at: {python_exe_path}")
|
382
|
+
if os.path.exists(python_exe_path):
|
383
|
+
self.log_info(f"Found associated python.exe: {python_exe_path}")
|
384
|
+
if " " in python_exe_path and not python_exe_path.startswith('"'):
|
385
|
+
return f'"{python_exe_path}"'
|
386
|
+
return python_exe_path
|
387
|
+
else:
|
388
|
+
self.log_error(f"Associated python.exe not found at {python_exe_path}")
|
389
|
+
# Fallback: Check pythonw.exe?
|
390
|
+
pythonw_exe_path = os.path.join(env_dir, 'pythonw.exe')
|
391
|
+
if os.path.exists(pythonw_exe_path):
|
392
|
+
self.log_info(f"Found associated pythonw.exe as fallback: {pythonw_exe_path}")
|
393
|
+
if " " in pythonw_exe_path and not pythonw_exe_path.startswith('"'):
|
394
|
+
return f'"{pythonw_exe_path}"'
|
395
|
+
return pythonw_exe_path
|
396
|
+
else:
|
397
|
+
self.log_error(f"Associated pythonw.exe also not found.")
|
398
|
+
return None
|
399
|
+
|
400
|
+
except Exception as e:
|
401
|
+
self.log_error(f"Error finding associated python executable: {e}")
|
402
|
+
return None
|
403
|
+
|
404
|
+
def handle_update(self):
|
405
|
+
"""Handles the update command by running pip install --upgrade directly."""
|
406
|
+
self.log_info("Executing OOTB update via pip...")
|
407
|
+
|
408
|
+
python_exe = self._get_python_executable_from_target_exe()
|
409
|
+
if not python_exe:
|
410
|
+
self.log_error("Cannot update: Could not find associated python.exe for pip.")
|
411
|
+
return "failed_python_not_found"
|
371
412
|
|
372
|
-
#
|
373
|
-
|
374
|
-
|
375
|
-
#
|
376
|
-
|
377
|
-
|
413
|
+
# Package name needs to be defined (replace with actual package name)
|
414
|
+
package_name = "computer-use-ootb-internal" # Make sure this is correct
|
415
|
+
|
416
|
+
# Construct the command: "C:\path\to\python.exe" -m pip install --upgrade --no-cache-dir package_name
|
417
|
+
python_exe_unquoted = python_exe.strip('"')
|
418
|
+
pip_args = ["-m", "pip", "install", "--upgrade", "--no-cache-dir", package_name]
|
419
|
+
update_command_display = f'{python_exe} {" ".join(pip_args)}'
|
378
420
|
|
379
|
-
self.log_info(f"Running update command: {
|
421
|
+
self.log_info(f"Running update command: {update_command_display}")
|
380
422
|
try:
|
381
|
-
# Execute the command directly. Running as LocalSystem should have rights
|
382
|
-
# Capture output for logging.
|
423
|
+
# Execute the pip command directly. Running as LocalSystem should have rights.
|
383
424
|
result = subprocess.run(
|
384
|
-
[
|
425
|
+
[python_exe_unquoted] + pip_args,
|
385
426
|
capture_output=True,
|
386
427
|
text=True,
|
387
|
-
check=False, #
|
428
|
+
check=False, # Check manually
|
388
429
|
encoding='utf-8',
|
389
430
|
errors='ignore'
|
390
431
|
)
|
391
432
|
|
392
|
-
# Log stdout/stderr regardless of exit code
|
393
433
|
if result.stdout:
|
394
434
|
self.log_info(f"Update process STDOUT:\n{result.stdout.strip()}")
|
395
435
|
if result.stderr:
|
396
|
-
self.log_warning(f"Update process STDERR:\n{result.stderr.strip()}")
|
436
|
+
self.log_warning(f"Update process STDERR:\n{result.stderr.strip()}")
|
397
437
|
|
398
438
|
if result.returncode == 0:
|
399
439
|
self.log_info("Update process completed successfully (Exit Code 0).")
|
400
440
|
return "success"
|
401
441
|
else:
|
402
442
|
self.log_error(f"Update process failed (Exit Code {result.returncode}).")
|
403
|
-
return f"
|
443
|
+
return f"failed_pip_exit_code_{result.returncode}"
|
404
444
|
|
405
445
|
except FileNotFoundError:
|
406
|
-
self.log_error(f"Update failed:
|
407
|
-
return "
|
446
|
+
self.log_error(f"Update failed: Python executable not found at '{python_exe_unquoted}'.")
|
447
|
+
return "failed_python_not_found"
|
408
448
|
except Exception as e:
|
409
449
|
self.log_error(f"Update failed with exception: {e}", exc_info=True)
|
410
450
|
return "failed_exception"
|
@@ -448,135 +488,136 @@ class GuardService(win32serviceutil.ServiceFramework):
|
|
448
488
|
return ootb_procs
|
449
489
|
|
450
490
|
def handle_stop(self, target_user="all_active"):
|
491
|
+
"""Stops the OOTB process for specified user(s). Uses psutil first, then taskkill fallback."""
|
451
492
|
self.log_info(f"Executing stop OOTB for target '{target_user}'...")
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
# No need for all_system_users for stop, we only care about active or the specific target
|
459
|
-
try:
|
460
|
-
sessions = win32ts.WTSEnumerateSessions(win32ts.WTS_CURRENT_SERVER_HANDLE)
|
461
|
-
for session in sessions:
|
462
|
-
if session['State'] == win32ts.WTSActive:
|
463
|
-
try:
|
464
|
-
user = win32ts.WTSQuerySessionInformation(win32ts.WTS_CURRENT_SERVER_HANDLE, session['SessionId'], win32ts.WTSUserName)
|
465
|
-
if user:
|
466
|
-
active_sessions[user.lower()] = session['SessionId']
|
467
|
-
except Exception as query_err:
|
468
|
-
self.log_error(f"Could not query session {session['SessionId']} during stop: {query_err}")
|
469
|
-
except Exception as user_enum_err:
|
470
|
-
self.log_error(f"Error enumerating users/sessions during stop: {user_enum_err}", exc_info=True)
|
471
|
-
return "failed_user_enumeration"
|
472
|
-
|
473
|
-
self.log_info(f"Stop target: '{target_user}'. Active sessions: {active_sessions}")
|
474
|
-
|
475
|
-
target_users_normalized = set()
|
476
|
-
if target_user == "all_active":
|
477
|
-
# Target only currently active users for stop all
|
478
|
-
target_users_normalized = set(active_sessions.keys())
|
479
|
-
self.log_info(f"Stop targeting all active users: {target_users_normalized}")
|
480
|
-
else:
|
481
|
-
# Target the specific user, regardless of active status (for task removal)
|
482
|
-
normalized_target = target_user.lower()
|
483
|
-
target_users_normalized.add(normalized_target)
|
484
|
-
self.log_info(f"Stop targeting specific user: {normalized_target}")
|
485
|
-
|
486
|
-
if not target_users_normalized:
|
487
|
-
self.log_info("No target users identified for stop.")
|
488
|
-
return "failed_no_target_users" # Or success if none were targeted?
|
489
|
-
|
490
|
-
# --- Process each target user ---
|
491
|
-
for user in target_users_normalized:
|
492
|
-
task_removed_status = "task_unknown"
|
493
|
-
immediate_stop_status = "stop_not_attempted"
|
494
|
-
stopped_count = 0
|
495
|
-
|
496
|
-
self.log_info(f"Processing stop for user '{user}'...")
|
497
|
-
|
498
|
-
# 1. Always try to remove the scheduled task
|
499
|
-
try:
|
500
|
-
# remove_logon_task always returns True for now, just logs attempt
|
501
|
-
self.remove_logon_task(user)
|
502
|
-
task_removed_status = "task_removed_attempted"
|
503
|
-
except Exception as task_err:
|
504
|
-
self.log_error(f"Exception removing scheduled task for {user}: {task_err}", exc_info=True)
|
505
|
-
task_removed_status = "task_exception"
|
506
|
-
failed_users.add(user)
|
507
|
-
# Continue to try and stop process if active
|
508
|
-
|
509
|
-
# 2. If user is active, try to terminate process
|
510
|
-
is_active = user in active_sessions
|
511
|
-
|
512
|
-
if is_active:
|
513
|
-
immediate_stop_status = "stop_attempted"
|
514
|
-
self.log_info(f"User '{user}' is active. Attempting to terminate OOTB process(es)...")
|
515
|
-
# Pass the specific username to _get_ootb_processes
|
516
|
-
procs_to_stop = self._get_ootb_processes(user)
|
517
|
-
|
518
|
-
if not procs_to_stop:
|
519
|
-
self.log_info(f"No running OOTB processes found for active user '{user}'.")
|
520
|
-
immediate_stop_status = "stop_skipped_not_running"
|
521
|
-
else:
|
522
|
-
self.log_info(f"Found {len(procs_to_stop)} process(es) for user '{user}' to stop.")
|
523
|
-
for proc in procs_to_stop:
|
524
|
-
try:
|
525
|
-
pid = proc.pid # Get pid before potential termination
|
526
|
-
username = proc.info.get('username', 'unknown_user')
|
527
|
-
self.log_info(f"Terminating process PID={pid}, User={username}")
|
528
|
-
proc.terminate()
|
529
|
-
try:
|
530
|
-
proc.wait(timeout=3)
|
531
|
-
self.log_info(f"Process PID={pid} terminated successfully.")
|
532
|
-
stopped_count += 1
|
533
|
-
except psutil.TimeoutExpired:
|
534
|
-
self.log_error(f"Process PID={pid} did not terminate gracefully, killing.")
|
535
|
-
proc.kill()
|
536
|
-
stopped_count += 1
|
537
|
-
except psutil.NoSuchProcess:
|
538
|
-
self.log_info(f"Process PID={pid} already terminated.")
|
539
|
-
# Don't increment stopped_count here as we didn't stop it now
|
540
|
-
except psutil.AccessDenied:
|
541
|
-
self.log_error(f"Access denied trying to terminate process PID={pid}.")
|
542
|
-
failed_users.add(user) # Mark user as failed if stop fails
|
543
|
-
except Exception as e:
|
544
|
-
self.log_error(f"Error stopping process PID={pid}: {e}", exc_info=True)
|
545
|
-
failed_users.add(user) # Mark user as failed
|
546
|
-
|
547
|
-
# Determine status based on how many were found vs stopped
|
548
|
-
if user in failed_users:
|
549
|
-
immediate_stop_status = f"stop_errors_terminated_{stopped_count}_of_{len(procs_to_stop)}"
|
550
|
-
elif stopped_count == len(procs_to_stop):
|
551
|
-
immediate_stop_status = f"stop_success_terminated_{stopped_count}"
|
552
|
-
else: # Should ideally not happen if NoSuchProcess doesn't count
|
553
|
-
immediate_stop_status = f"stop_partial_terminated_{stopped_count}_of_{len(procs_to_stop)}"
|
554
|
-
|
555
|
-
else: # User not active
|
556
|
-
self.log_info(f"User '{user}' is not active. Skipping immediate process stop (task removal attempted).")
|
557
|
-
immediate_stop_status = "stop_skipped_inactive"
|
558
|
-
|
559
|
-
# Record final results for this user
|
560
|
-
stop_results[user] = (task_removed_status, immediate_stop_status)
|
561
|
-
|
562
|
-
|
563
|
-
# --- Consolidate status ---
|
564
|
-
total_processed = len(target_users_normalized)
|
565
|
-
final_status = "partial_success" if failed_users else "success"
|
566
|
-
if not stop_results: final_status = "no_targets_processed"
|
567
|
-
if len(failed_users) == total_processed and total_processed > 0 : final_status = "failed"
|
568
|
-
|
569
|
-
self.log_info(f"Finished stopping OOTB. Overall Status: {final_status}. Results: {stop_results}")
|
493
|
+
stopped_count_psutil = 0
|
494
|
+
stopped_count_taskkill = 0
|
495
|
+
errors = []
|
496
|
+
|
497
|
+
target_users_lower = set()
|
498
|
+
if target_user == "all_active":
|
570
499
|
try:
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
500
|
+
for user_session in psutil.users():
|
501
|
+
username_lower = user_session.name.split('\\')[-1].lower()
|
502
|
+
target_users_lower.add(username_lower)
|
503
|
+
self.log_info(f"Targeting all users found by psutil: {target_users_lower}")
|
504
|
+
except Exception as e:
|
505
|
+
self.log_error(f"Could not list users via psutil for stop all: {e}")
|
506
|
+
errors.append("failed_user_enumeration")
|
507
|
+
target_users_lower = set() # Avoid proceeding if user list failed
|
508
|
+
else:
|
509
|
+
target_users_lower.add(target_user.lower())
|
510
|
+
self.log_info(f"Targeting specific user: {target_user.lower()}")
|
575
511
|
|
512
|
+
if not target_users_lower and target_user == "all_active":
|
513
|
+
self.log_info("No active users found to stop.")
|
514
|
+
# If specific user targeted, proceed even if psutil didn't list them (maybe inactive)
|
515
|
+
|
516
|
+
procs_to_kill_by_user = {user: [] for user in target_users_lower}
|
517
|
+
|
518
|
+
# --- Attempt 1: psutil find and terminate ---
|
519
|
+
self.log_info("Attempting stop using psutil...")
|
520
|
+
try:
|
521
|
+
all_running = self._get_ootb_processes("all") # Get all regardless of user first
|
522
|
+
for proc in all_running:
|
523
|
+
try:
|
524
|
+
proc_user = proc.info.get('username')
|
525
|
+
if proc_user:
|
526
|
+
user_lower = proc_user.split('\\')[-1].lower()
|
527
|
+
if user_lower in target_users_lower:
|
528
|
+
procs_to_kill_by_user[user_lower].append(proc)
|
529
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
530
|
+
pass # Process ended or we can't access it
|
576
531
|
except Exception as e:
|
577
|
-
self.log_error(f"Error
|
578
|
-
|
532
|
+
self.log_error(f"Error getting process list for psutil stop: {e}")
|
533
|
+
errors.append("failed_psutil_list")
|
579
534
|
|
535
|
+
for user, procs in procs_to_kill_by_user.items():
|
536
|
+
if not procs:
|
537
|
+
self.log_info(f"psutil: No OOTB processes found running for user '{user}'.")
|
538
|
+
continue
|
539
|
+
|
540
|
+
self.log_info(f"psutil: Found {len(procs)} OOTB process(es) for user '{user}'. Attempting terminate...")
|
541
|
+
for proc in procs:
|
542
|
+
try:
|
543
|
+
pid = proc.pid
|
544
|
+
self.log_info(f"psutil: Terminating PID {pid} for user '{user}'...")
|
545
|
+
proc.terminate()
|
546
|
+
try:
|
547
|
+
proc.wait(timeout=3) # Wait a bit for termination
|
548
|
+
self.log_info(f"psutil: PID {pid} terminated successfully.")
|
549
|
+
stopped_count_psutil += 1
|
550
|
+
except psutil.TimeoutExpired:
|
551
|
+
self.log_warning(f"psutil: PID {pid} did not terminate within timeout. Will try taskkill.")
|
552
|
+
# No error append yet, let taskkill try
|
553
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
554
|
+
self.log_info(f"psutil: PID {pid} already gone or access denied after terminate.")
|
555
|
+
stopped_count_psutil += 1 # Count it as stopped
|
556
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied) as term_err:
|
557
|
+
self.log_warning(f"psutil: Error terminating PID {proc.pid if 'proc' in locals() and proc else 'unknown'}: {term_err}. It might be gone already.")
|
558
|
+
# If it's gone, count it?
|
559
|
+
stopped_count_psutil += 1 # Assume it's gone if NoSuchProcess
|
560
|
+
except Exception as term_ex:
|
561
|
+
self.log_error(f"psutil: Unexpected error terminating PID {proc.pid if 'proc' in locals() and proc else 'unknown'}: {term_ex}")
|
562
|
+
errors.append(f"failed_psutil_terminate_{user}")
|
563
|
+
|
564
|
+
# --- Attempt 2: taskkill fallback (for users where psutil didn't find/stop) ---
|
565
|
+
# Only run taskkill if psutil didn't stop anything for a specific user OR if target was specific user
|
566
|
+
|
567
|
+
if not self.target_executable_path:
|
568
|
+
errors.append("skipped_taskkill_no_exe_path")
|
569
|
+
else:
|
570
|
+
executable_name = os.path.basename(self.target_executable_path.strip('"'))
|
571
|
+
for user in target_users_lower:
|
572
|
+
run_taskkill = False
|
573
|
+
if user not in procs_to_kill_by_user or not procs_to_kill_by_user[user]:
|
574
|
+
# psutil didn't find anything for this user initially
|
575
|
+
run_taskkill = True
|
576
|
+
self.log_info(f"taskkill: psutil found no processes for '{user}', attempting taskkill as fallback.")
|
577
|
+
elif any(p.is_running() for p in procs_to_kill_by_user.get(user, []) if p): # Check if any psutil targets still running
|
578
|
+
run_taskkill = True
|
579
|
+
self.log_info(f"taskkill: Some processes for '{user}' may remain after psutil, attempting taskkill cleanup.")
|
580
|
+
|
581
|
+
if run_taskkill:
|
582
|
+
# Construct taskkill command
|
583
|
+
# Username format might need adjustment (e.g., DOMAIN\user). Try simple first.
|
584
|
+
taskkill_command = [
|
585
|
+
"taskkill", "/F", # Force
|
586
|
+
"/IM", executable_name, # Image name
|
587
|
+
"/FI", f"USERNAME eq {user}" # Filter by username
|
588
|
+
]
|
589
|
+
self.log_info(f"Running taskkill command: {' '.join(taskkill_command)}")
|
590
|
+
try:
|
591
|
+
result = subprocess.run(taskkill_command, capture_output=True, text=True, check=False)
|
592
|
+
if result.returncode == 0:
|
593
|
+
self.log_info(f"taskkill successful for user '{user}' (Exit Code 0).")
|
594
|
+
# Can't easily count how many were killed here, assume success if exit 0
|
595
|
+
stopped_count_taskkill += 1 # Indicate taskkill ran successfully for user
|
596
|
+
elif result.returncode == 128: # Code 128: No tasks found matching criteria
|
597
|
+
self.log_info(f"taskkill: No matching processes found for user '{user}'.")
|
598
|
+
else:
|
599
|
+
self.log_error(f"taskkill failed for user '{user}' (Exit Code {result.returncode}).")
|
600
|
+
self.log_error(f" taskkill STDOUT: {result.stdout.strip()}")
|
601
|
+
self.log_error(f" taskkill STDERR: {result.stderr.strip()}")
|
602
|
+
errors.append(f"failed_taskkill_{user}")
|
603
|
+
except FileNotFoundError:
|
604
|
+
self.log_error("taskkill command not found.")
|
605
|
+
errors.append("failed_taskkill_not_found")
|
606
|
+
break # Stop trying taskkill if command is missing
|
607
|
+
except Exception as tk_ex:
|
608
|
+
self.log_error(f"Exception running taskkill for '{user}': {tk_ex}")
|
609
|
+
errors.append(f"failed_taskkill_exception_{user}")
|
610
|
+
|
611
|
+
# --- Consolidate status ---
|
612
|
+
final_status = "failed" # Default to failed if errors occurred
|
613
|
+
if stopped_count_psutil > 0 or stopped_count_taskkill > 0:
|
614
|
+
final_status = "success" if not errors else "partial_success"
|
615
|
+
elif not errors:
|
616
|
+
final_status = "success_no_processes_found"
|
617
|
+
|
618
|
+
details = f"psutil_stopped={stopped_count_psutil}, taskkill_users_attempted={stopped_count_taskkill}, errors={len(errors)}"
|
619
|
+
self.log_info(f"Finished stopping OOTB. Status: {final_status}. Details: {details}")
|
620
|
+
return f"{final_status}::{details}" # Return status and details
|
580
621
|
|
581
622
|
def handle_start(self, target_user="all_active"):
|
582
623
|
"""Handles external start command request (finds users, calls internal trigger)."""
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# src/computer_use_ootb_internal/preparation/star_rail_prepare.py
|
2
2
|
import time
|
3
3
|
import platform
|
4
|
+
import subprocess # Added for taskkill
|
4
5
|
import pyautogui
|
5
6
|
import webbrowser
|
6
7
|
import logging # Use logging instead of print for better practice
|
@@ -11,7 +12,8 @@ log = logging.getLogger(__name__)
|
|
11
12
|
def run_preparation(state):
|
12
13
|
"""
|
13
14
|
Performs environment preparation specific to Star Rail on Windows.
|
14
|
-
|
15
|
+
Closes existing Edge browsers, opens the specified URL in a new Edge instance,
|
16
|
+
and performs initial clicks.
|
15
17
|
"""
|
16
18
|
if platform.system() != "Windows":
|
17
19
|
log.info("Star Rail preparation skipped: Not running on Windows.")
|
@@ -21,11 +23,31 @@ def run_preparation(state):
|
|
21
23
|
url = "https://sr.mihoyo.com/cloud/#/" # Consider making this configurable later
|
22
24
|
browser_opened = False
|
23
25
|
try:
|
26
|
+
# Attempt to close existing Microsoft Edge processes
|
27
|
+
log.info("Attempting to close existing Microsoft Edge processes...")
|
28
|
+
try:
|
29
|
+
# /F forces termination, /IM specifies image name
|
30
|
+
result = subprocess.run(['taskkill', '/F', '/IM', 'msedge.exe'],
|
31
|
+
capture_output=True, text=True, check=False)
|
32
|
+
if result.returncode == 0:
|
33
|
+
log.info("Successfully sent termination signal to msedge.exe processes.")
|
34
|
+
elif "not found" in result.stderr.lower() or "not found" in result.stdout.lower():
|
35
|
+
log.info("No running msedge.exe processes found to close.")
|
36
|
+
else:
|
37
|
+
log.warning(f"taskkill command finished with return code {result.returncode}. Output: {result.stdout} Stderr: {result.stderr}")
|
38
|
+
time.sleep(2) # Give processes time to close
|
39
|
+
except FileNotFoundError:
|
40
|
+
log.error("Error: 'taskkill' command not found. Make sure it's in the system PATH.")
|
41
|
+
except Exception as e:
|
42
|
+
log.error(f"Error occurred while trying to close Edge: {e}", exc_info=True)
|
43
|
+
|
24
44
|
# Use only webbrowser.open
|
25
45
|
log.info(f"Attempting to open {url} using webbrowser.open()...")
|
26
46
|
if webbrowser.open(url):
|
27
47
|
log.info(f"Successfully requested browser to open {url} via webbrowser.open().")
|
28
48
|
browser_opened = True
|
49
|
+
# Ensure sleep time for browser load before clicks is present
|
50
|
+
time.sleep(5)
|
29
51
|
else:
|
30
52
|
log.warning("webbrowser.open() returned False, indicating potential failure.")
|
31
53
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|