forgexa-cli 1.21.0__tar.gz → 1.21.1__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.
Files changed (21) hide show
  1. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/PKG-INFO +1 -1
  2. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli/__init__.py +1 -1
  3. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli/daemon.py +56 -5
  4. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli.egg-info/PKG-INFO +1 -1
  5. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/pyproject.toml +1 -1
  6. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/README.md +0 -0
  7. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli/_build_config.py +0 -0
  8. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli/autoupgrade.py +0 -0
  9. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli/main.py +0 -0
  10. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli/py.typed +0 -0
  11. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli.egg-info/SOURCES.txt +0 -0
  12. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli.egg-info/dependency_links.txt +0 -0
  13. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli.egg-info/entry_points.txt +0 -0
  14. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli.egg-info/requires.txt +0 -0
  15. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/forgexa_cli.egg-info/top_level.txt +0 -0
  16. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/setup.cfg +0 -0
  17. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/tests/test_auth_and_runtime_commands.py +0 -0
  18. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/tests/test_autoupgrade.py +0 -0
  19. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/tests/test_check_command.py +0 -0
  20. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/tests/test_silent_install.py +0 -0
  21. {forgexa_cli-1.21.0 → forgexa_cli-1.21.1}/tests/test_upgrade_observability.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.21.0
3
+ Version: 1.21.1
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,2 +1,2 @@
1
1
  """forgexa-cli — Forgexa command-line client."""
2
- __version__ = "1.21.0"
2
+ __version__ = "1.21.1"
@@ -555,7 +555,7 @@ except (ImportError, ModuleNotFoundError):
555
555
  # DAEMON_VERSION is the protocol/logic version of the daemon code.
556
556
  # Kept in sync with pyproject.toml version via bump-version.sh.
557
557
  # CLIENT_TYPE identifies which packaging/distribution this daemon runs in.
558
- DAEMON_VERSION = "1.21.0"
558
+ DAEMON_VERSION = "1.21.1"
559
559
 
560
560
 
561
561
  def _detect_client_type() -> str:
@@ -780,8 +780,19 @@ def _prepare_agent_command(command: list[str]) -> list[str]:
780
780
 
781
781
  suffix = Path(command[0]).suffix.lower()
782
782
  if suffix in {".cmd", ".bat"}:
783
+ comspec = os.environ.get("COMSPEC", "")
784
+ if comspec and Path(comspec).is_file():
785
+ command_processor = comspec
786
+ else:
787
+ system_root = os.environ.get("SystemRoot") or os.environ.get("WINDIR", "")
788
+ system_cmd = Path(system_root) / "System32" / "cmd.exe" if system_root else None
789
+ command_processor = (
790
+ str(system_cmd)
791
+ if system_cmd and system_cmd.is_file()
792
+ else shutil.which("cmd.exe") or comspec or "cmd.exe"
793
+ )
783
794
  return [
784
- os.environ.get("COMSPEC", "cmd.exe"),
795
+ command_processor,
785
796
  "/d",
786
797
  "/s",
787
798
  "/c",
@@ -800,6 +811,13 @@ def _prepare_agent_command(command: list[str]) -> list[str]:
800
811
  return command
801
812
 
802
813
 
814
+ def _agent_process_group_kwargs() -> dict[str, bool]:
815
+ """Isolate agent process groups where the platform supports POSIX sessions."""
816
+ # Windows cleanup uses taskkill /T, and starting cmd.exe with a new session
817
+ # differs from the command path proven during agent discovery.
818
+ return {"start_new_session": True} if sys.platform != "win32" else {}
819
+
820
+
803
821
  @dataclass
804
822
  class TaskInfo:
805
823
  task_id: str
@@ -4502,7 +4520,7 @@ class ProcessManager:
4502
4520
  cwd=str(cwd),
4503
4521
  env=env,
4504
4522
  limit=100 * 1024 * 1024, # 100MB line buffer for large JSON output from long sessions
4505
- start_new_session=True, # own process group → killpg on timeout kills all children
4523
+ **_agent_process_group_kwargs(),
4506
4524
  )
4507
4525
  self.active_processes[task_id] = proc
4508
4526
  stdout, stderr, returncode = await self._stream_process(
@@ -4559,6 +4577,16 @@ class ProcessManager:
4559
4577
  error=f"Claude exited with code {returncode}: {stderr[-500:]}",
4560
4578
  metrics=metrics,
4561
4579
  )
4580
+ except FileNotFoundError as exc:
4581
+ logger.exception("Claude executable was not found for task %s", task_id)
4582
+ return TaskResult(
4583
+ status="failed",
4584
+ exit_code=-1,
4585
+ stdout="",
4586
+ stderr="",
4587
+ error=f"Claude launch failed: executable not found: {cmd[0]!r} ({exc})",
4588
+ failure_code="agent_launch_not_found",
4589
+ )
4562
4590
  except asyncio.TimeoutError as exc:
4563
4591
  _kill_proc(self.active_processes.pop(task_id, None) or proc)
4564
4592
  _err = (
@@ -5237,7 +5265,7 @@ class ProcessManager:
5237
5265
  cwd=str(cwd),
5238
5266
  env=env,
5239
5267
  limit=100 * 1024 * 1024,
5240
- start_new_session=True,
5268
+ **_agent_process_group_kwargs(),
5241
5269
  **_win_flags,
5242
5270
  )
5243
5271
  self.active_processes[task_id] = proc
@@ -5367,6 +5395,19 @@ class ProcessManager:
5367
5395
  error=failure_error,
5368
5396
  metrics=metrics,
5369
5397
  )
5398
+ except FileNotFoundError as exc:
5399
+ logger.exception("Copilot executable was not found for task %s", task_id)
5400
+ return TaskResult(
5401
+ status="failed",
5402
+ exit_code=-1,
5403
+ stdout="",
5404
+ stderr="",
5405
+ error=(
5406
+ f"Copilot launch failed: executable not found: {cmd[0]!r}; "
5407
+ f"configured agent path: {agent.command!r} ({exc})"
5408
+ ),
5409
+ failure_code="agent_launch_not_found",
5410
+ )
5370
5411
  except asyncio.TimeoutError as exc:
5371
5412
  _kill_proc(self.active_processes.pop(task_id, None) or proc)
5372
5413
  _err = (
@@ -5428,7 +5469,7 @@ class ProcessManager:
5428
5469
  cwd=str(cwd),
5429
5470
  env=env,
5430
5471
  limit=100 * 1024 * 1024, # 100MB line buffer for large agent output
5431
- start_new_session=True, # own process group → killpg on timeout kills all children
5472
+ **_agent_process_group_kwargs(),
5432
5473
  )
5433
5474
  self.active_processes[task_id] = proc
5434
5475
  stdin_bytes = stdin_input.encode() if stdin_input else None
@@ -5445,6 +5486,16 @@ class ProcessManager:
5445
5486
  stderr=stderr[-10000:],
5446
5487
  error="" if status == "success" else f"Exited with code {returncode}",
5447
5488
  )
5489
+ except FileNotFoundError as exc:
5490
+ logger.exception("Agent executable was not found for task %s", task_id)
5491
+ return TaskResult(
5492
+ status="failed",
5493
+ exit_code=-1,
5494
+ stdout="",
5495
+ stderr="",
5496
+ error=f"Agent launch failed: executable not found: {cmd[0]!r} ({exc})",
5497
+ failure_code="agent_launch_not_found",
5498
+ )
5448
5499
  except asyncio.TimeoutError as exc:
5449
5500
  _kill_proc(self.active_processes.pop(task_id, None) or proc)
5450
5501
  _err = (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.21.0
3
+ Version: 1.21.1
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "forgexa-cli"
3
- version = "1.21.0"
3
+ version = "1.21.1"
4
4
  description = "Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform"
5
5
  requires-python = ">=3.9"
6
6
  license = "MIT"
File without changes
File without changes