forgexa-cli 1.43.4__tar.gz → 1.43.5__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.
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/PKG-INFO +1 -1
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli/__init__.py +1 -1
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli/agent_core.py +2 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli/daemon.py +31 -13
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli.egg-info/PKG-INFO +1 -1
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/pyproject.toml +1 -1
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/README.md +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli/_build_config.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli/_local_bind.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli/autoupgrade.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli/main.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli/py.typed +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli.egg-info/SOURCES.txt +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli.egg-info/dependency_links.txt +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli.egg-info/entry_points.txt +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli.egg-info/requires.txt +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/forgexa_cli.egg-info/top_level.txt +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/setup.cfg +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/tests/test_auth_and_runtime_commands.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/tests/test_autoupgrade.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/tests/test_check_command.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/tests/test_expiry_warnings_and_revoke.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/tests/test_local_bind_commands.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/tests/test_runtime_credentials.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/tests/test_session_credentials.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/tests/test_silent_install.py +0 -0
- {forgexa_cli-1.43.4 → forgexa_cli-1.43.5}/tests/test_upgrade_observability.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""forgexa-cli — Forgexa command-line client."""
|
|
2
|
-
__version__ = "1.43.
|
|
2
|
+
__version__ = "1.43.5"
|
|
@@ -630,6 +630,7 @@ class AgentDiscovery:
|
|
|
630
630
|
"true",
|
|
631
631
|
stdout=asyncio.subprocess.DEVNULL,
|
|
632
632
|
stderr=asyncio.subprocess.PIPE,
|
|
633
|
+
**_agent_process_group_kwargs(),
|
|
633
634
|
)
|
|
634
635
|
_, stderr = await asyncio.wait_for(proc.communicate(), timeout=5)
|
|
635
636
|
if proc.returncode != 0:
|
|
@@ -745,6 +746,7 @@ def _kill_proc(proc: asyncio.subprocess.Process) -> None:
|
|
|
745
746
|
_subprocess.run(
|
|
746
747
|
["taskkill", "/F", "/T", "/PID", str(proc.pid)],
|
|
747
748
|
capture_output=True,
|
|
749
|
+
**_agent_process_group_kwargs(),
|
|
748
750
|
)
|
|
749
751
|
except Exception:
|
|
750
752
|
pass
|
|
@@ -365,6 +365,7 @@ def _windows_process_is_running(pid: int) -> bool:
|
|
|
365
365
|
capture_output=True,
|
|
366
366
|
text=True,
|
|
367
367
|
timeout=5,
|
|
368
|
+
**_agent_process_group_kwargs(),
|
|
368
369
|
)
|
|
369
370
|
except (OSError, subprocess.TimeoutExpired):
|
|
370
371
|
return False
|
|
@@ -592,6 +593,7 @@ def _try_install_httpx(deps_dir: str) -> tuple[bool, str]:
|
|
|
592
593
|
stderr=subprocess.PIPE,
|
|
593
594
|
text=True,
|
|
594
595
|
timeout=120,
|
|
596
|
+
**_agent_process_group_kwargs(),
|
|
595
597
|
)
|
|
596
598
|
if result.returncode == 0:
|
|
597
599
|
return True, ""
|
|
@@ -910,7 +912,7 @@ except (ImportError, ModuleNotFoundError):
|
|
|
910
912
|
# DAEMON_VERSION is the protocol/logic version of the daemon code.
|
|
911
913
|
# Kept in sync with pyproject.toml version via bump-version.sh.
|
|
912
914
|
# CLIENT_TYPE identifies which packaging/distribution this daemon runs in.
|
|
913
|
-
DAEMON_VERSION = "1.43.
|
|
915
|
+
DAEMON_VERSION = "1.43.5"
|
|
914
916
|
|
|
915
917
|
|
|
916
918
|
def _detect_client_type() -> str:
|
|
@@ -1040,6 +1042,7 @@ def _get_machine_id() -> str | None:
|
|
|
1040
1042
|
result = subprocess.run(
|
|
1041
1043
|
["ioreg", "-rd1", "-c", "IOPlatformExpertDevice"],
|
|
1042
1044
|
capture_output=True, text=True, timeout=5,
|
|
1045
|
+
**_agent_process_group_kwargs(),
|
|
1043
1046
|
)
|
|
1044
1047
|
match = re.search(r'"IOPlatformUUID"\s*=\s*"([^"]+)"', result.stdout)
|
|
1045
1048
|
if match:
|
|
@@ -2455,6 +2458,7 @@ class WorkspaceManager:
|
|
|
2455
2458
|
capture_output=True,
|
|
2456
2459
|
stdin=subprocess.DEVNULL,
|
|
2457
2460
|
timeout=60,
|
|
2461
|
+
**_agent_process_group_kwargs(),
|
|
2458
2462
|
)
|
|
2459
2463
|
if result.returncode != 0 and path.exists():
|
|
2460
2464
|
logger.warning(
|
|
@@ -4509,20 +4513,20 @@ class WorkspaceManager:
|
|
|
4509
4513
|
except OSError:
|
|
4510
4514
|
_known_hosts_null = "NUL" # fallback to null device
|
|
4511
4515
|
try:
|
|
4512
|
-
import subprocess as _subp
|
|
4513
4516
|
_username = (
|
|
4514
4517
|
os.environ.get("USERNAME")
|
|
4515
4518
|
or os.environ.get("USER")
|
|
4516
4519
|
or ""
|
|
4517
4520
|
)
|
|
4518
4521
|
if _username:
|
|
4519
|
-
|
|
4522
|
+
subprocess.run(
|
|
4520
4523
|
[
|
|
4521
4524
|
"icacls", key_path,
|
|
4522
4525
|
"/inheritance:r",
|
|
4523
4526
|
"/grant:r", f"{_username}:(R)",
|
|
4524
4527
|
],
|
|
4525
4528
|
capture_output=True, check=False, timeout=10,
|
|
4529
|
+
**_agent_process_group_kwargs(),
|
|
4526
4530
|
)
|
|
4527
4531
|
except Exception:
|
|
4528
4532
|
pass
|
|
@@ -4647,6 +4651,7 @@ class WorkspaceManager:
|
|
|
4647
4651
|
_subprocess.run(
|
|
4648
4652
|
["taskkill", "/F", "/T", "/PID", str(proc.pid)],
|
|
4649
4653
|
capture_output=True,
|
|
4654
|
+
**_agent_process_group_kwargs(),
|
|
4650
4655
|
)
|
|
4651
4656
|
except Exception:
|
|
4652
4657
|
pass
|
|
@@ -7083,6 +7088,7 @@ class RuntimePreflightMonitor:
|
|
|
7083
7088
|
_subprocess.run(
|
|
7084
7089
|
["taskkill", "/T", "/F", "/PID", str(proc.pid)],
|
|
7085
7090
|
capture_output=True,
|
|
7091
|
+
**_agent_process_group_kwargs(),
|
|
7086
7092
|
)
|
|
7087
7093
|
else:
|
|
7088
7094
|
import signal
|
|
@@ -8484,12 +8490,13 @@ class RuntimeDaemon:
|
|
|
8484
8490
|
msvcrt.locking(self._lock_file.fileno(), msvcrt.LK_NBLCK, 1)
|
|
8485
8491
|
except (IOError, OSError):
|
|
8486
8492
|
# Lock held by another daemon — kill it
|
|
8487
|
-
import subprocess as _sp
|
|
8488
|
-
|
|
8489
8493
|
if old_pid and old_pid != os.getpid():
|
|
8490
8494
|
logger.warning("Another daemon (PID %d) holds the lock. Killing...", old_pid)
|
|
8491
|
-
|
|
8492
|
-
|
|
8495
|
+
subprocess.run(
|
|
8496
|
+
["taskkill", "/PID", str(old_pid), "/F", "/T"],
|
|
8497
|
+
capture_output=True,
|
|
8498
|
+
**_agent_process_group_kwargs(),
|
|
8499
|
+
)
|
|
8493
8500
|
else:
|
|
8494
8501
|
# No daemon.pid or PID matches us — find by process enumeration.
|
|
8495
8502
|
# Uses PowerShell Get-CimInstance (reliable on all modern Windows).
|
|
@@ -8503,17 +8510,24 @@ class RuntimeDaemon:
|
|
|
8503
8510
|
"-and $_.ProcessId -ne " + str(os.getpid()) + " } | "
|
|
8504
8511
|
"Select-Object -ExpandProperty ProcessId"
|
|
8505
8512
|
)
|
|
8506
|
-
result =
|
|
8513
|
+
result = subprocess.run(
|
|
8507
8514
|
["powershell", "-NoProfile", "-NonInteractive", "-Command", ps_script],
|
|
8508
|
-
capture_output=True,
|
|
8515
|
+
capture_output=True,
|
|
8516
|
+
text=True,
|
|
8517
|
+
timeout=15,
|
|
8518
|
+
**_agent_process_group_kwargs(),
|
|
8519
|
+
)
|
|
8509
8520
|
for line in result.stdout.strip().splitlines():
|
|
8510
8521
|
line = line.strip()
|
|
8511
8522
|
if line.isdigit():
|
|
8512
8523
|
pid = int(line)
|
|
8513
8524
|
if pid != os.getpid():
|
|
8514
8525
|
logger.info("Killing orphan daemon process (PID %d)", pid)
|
|
8515
|
-
|
|
8516
|
-
|
|
8526
|
+
subprocess.run(
|
|
8527
|
+
["taskkill", "/PID", str(pid), "/F", "/T"],
|
|
8528
|
+
capture_output=True,
|
|
8529
|
+
**_agent_process_group_kwargs(),
|
|
8530
|
+
)
|
|
8517
8531
|
except Exception as e:
|
|
8518
8532
|
logger.debug("Process enumeration fallback failed: %s", e)
|
|
8519
8533
|
|
|
@@ -8523,9 +8537,13 @@ class RuntimeDaemon:
|
|
|
8523
8537
|
if old_pid and old_pid != os.getpid():
|
|
8524
8538
|
for _ in range(6): # Up to 3 more seconds
|
|
8525
8539
|
try:
|
|
8526
|
-
result =
|
|
8540
|
+
result = subprocess.run(
|
|
8527
8541
|
["tasklist", "/FI", f"PID eq {old_pid}", "/NH", "/FO", "CSV"],
|
|
8528
|
-
capture_output=True,
|
|
8542
|
+
capture_output=True,
|
|
8543
|
+
text=True,
|
|
8544
|
+
timeout=5,
|
|
8545
|
+
**_agent_process_group_kwargs(),
|
|
8546
|
+
)
|
|
8529
8547
|
if str(old_pid) not in result.stdout:
|
|
8530
8548
|
break
|
|
8531
8549
|
except Exception:
|
|
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
|