forgexa-cli 1.47.3__tar.gz → 1.48.0__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 (28) hide show
  1. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/PKG-INFO +9 -3
  2. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/README.md +8 -2
  3. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli/__init__.py +1 -1
  4. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli/agent_core.py +62 -2
  5. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli/daemon.py +609 -52
  6. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli/main.py +27 -4
  7. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli.egg-info/PKG-INFO +9 -3
  8. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/pyproject.toml +1 -1
  9. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/tests/test_auth_and_runtime_commands.py +21 -2
  10. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli/_build_config.py +0 -0
  11. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli/_local_bind.py +0 -0
  12. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli/autoupgrade.py +0 -0
  13. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli/py.typed +0 -0
  14. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli/runtime_evidence.py +0 -0
  15. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli.egg-info/SOURCES.txt +0 -0
  16. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli.egg-info/dependency_links.txt +0 -0
  17. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli.egg-info/entry_points.txt +0 -0
  18. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli.egg-info/requires.txt +0 -0
  19. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/forgexa_cli.egg-info/top_level.txt +0 -0
  20. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/setup.cfg +0 -0
  21. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/tests/test_autoupgrade.py +0 -0
  22. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/tests/test_check_command.py +0 -0
  23. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/tests/test_expiry_warnings_and_revoke.py +0 -0
  24. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/tests/test_local_bind_commands.py +0 -0
  25. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/tests/test_runtime_credentials.py +0 -0
  26. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/tests/test_session_credentials.py +0 -0
  27. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/tests/test_silent_install.py +0 -0
  28. {forgexa_cli-1.47.3 → forgexa_cli-1.48.0}/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.47.3
3
+ Version: 1.48.0
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
@@ -132,10 +132,16 @@ forgexa upgrade --target-version 1.12.3
132
132
 
133
133
  The command detects how `forgexa-cli` was installed:
134
134
 
135
- - `pipx` install: uses `pipx upgrade forgexa-cli`, or `pipx install --force forgexa-cli==<version>` for a pinned version
136
- - `pip` install: uses `python -m pip install --upgrade forgexa-cli`
135
+ - `pipx` install: uses `pipx upgrade --index-url https://pypi.org/simple forgexa-cli`, or `pipx install --force --index-url https://pypi.org/simple forgexa-cli==<version>` for a pinned version
136
+ - `pip` install: uses `python -m pip install --upgrade --index-url https://pypi.org/simple forgexa-cli`
137
137
  - non-editable local path install (`pip install /path/to/cli`): follows the same `pip` upgrade path and switches to the published PyPI release
138
138
 
139
+ Self-upgrades pass `--index-url https://pypi.org/simple` to pip or pipx, matching the official PyPI release check and avoiding a configured mirror that has not yet synchronized a new release. A direct `pip install --upgrade forgexa-cli` command always follows that Python environment's pip configuration. When its mirror is behind, upgrade manually with:
140
+
141
+ ```bash
142
+ python -m pip install --upgrade --index-url https://pypi.org/simple forgexa-cli==1.12.3
143
+ ```
144
+
139
145
  For safety, `forgexa upgrade` stops any running local daemon before upgrading. If the daemon was previously started in background mode, the CLI starts it again automatically after a successful upgrade; otherwise it prints a manual restart hint.
140
146
 
141
147
  `forgexa upgrade` supports standard PyPI / pipx installs and non-editable local path installs. Editable installs, VCS installs, and other direct URL installs are rejected with a manual upgrade hint.
@@ -100,10 +100,16 @@ forgexa upgrade --target-version 1.12.3
100
100
 
101
101
  The command detects how `forgexa-cli` was installed:
102
102
 
103
- - `pipx` install: uses `pipx upgrade forgexa-cli`, or `pipx install --force forgexa-cli==<version>` for a pinned version
104
- - `pip` install: uses `python -m pip install --upgrade forgexa-cli`
103
+ - `pipx` install: uses `pipx upgrade --index-url https://pypi.org/simple forgexa-cli`, or `pipx install --force --index-url https://pypi.org/simple forgexa-cli==<version>` for a pinned version
104
+ - `pip` install: uses `python -m pip install --upgrade --index-url https://pypi.org/simple forgexa-cli`
105
105
  - non-editable local path install (`pip install /path/to/cli`): follows the same `pip` upgrade path and switches to the published PyPI release
106
106
 
107
+ Self-upgrades pass `--index-url https://pypi.org/simple` to pip or pipx, matching the official PyPI release check and avoiding a configured mirror that has not yet synchronized a new release. A direct `pip install --upgrade forgexa-cli` command always follows that Python environment's pip configuration. When its mirror is behind, upgrade manually with:
108
+
109
+ ```bash
110
+ python -m pip install --upgrade --index-url https://pypi.org/simple forgexa-cli==1.12.3
111
+ ```
112
+
107
113
  For safety, `forgexa upgrade` stops any running local daemon before upgrading. If the daemon was previously started in background mode, the CLI starts it again automatically after a successful upgrade; otherwise it prints a manual restart hint.
108
114
 
109
115
  `forgexa upgrade` supports standard PyPI / pipx installs and non-editable local path installs. Editable installs, VCS installs, and other direct URL installs are rejected with a manual upgrade hint.
@@ -1,2 +1,2 @@
1
1
  """forgexa-cli — Forgexa command-line client."""
2
- __version__ = "1.47.3"
2
+ __version__ = "1.48.0"
@@ -1616,14 +1616,74 @@ def build_opencode_command(
1616
1616
  return cmd
1617
1617
 
1618
1618
 
1619
- def opencode_base_env(env: dict[str, str], *, data_home: str | Path) -> dict[str, str]:
1620
- """Isolate each opencode run in its own XDG data directory.
1619
+ def opencode_base_env(
1620
+ env: dict[str, str], *, data_home: str | Path, require_windows_shell: bool = False,
1621
+ ) -> dict[str, str]:
1622
+ """Isolate each OpenCode run in its own XDG data directory.
1621
1623
 
1622
1624
  Prevents concurrent opencode processes from racing on the shared SQLite
1623
1625
  WAL file ('Failed to run the query PRAGMA wal_checkpoint(PASSIVE)').
1624
1626
  """
1625
1627
  env = dict(env)
1626
1628
  env["XDG_DATA_HOME"] = str(data_home)
1629
+ return configure_opencode_windows_shell(env, required=require_windows_shell)
1630
+
1631
+
1632
+ def _find_opencode_windows_shell(env: dict[str, str]) -> str | None:
1633
+ configured = env.get("OPENCODE_GIT_BASH_PATH", "").strip()
1634
+ if configured and Path(configured).is_file():
1635
+ return configured
1636
+
1637
+ git = shutil.which("git", path=env.get("PATH"))
1638
+ if git:
1639
+ git_path = Path(git)
1640
+ for git_root in (git_path.parent.parent, git_path.parent.parent.parent):
1641
+ git_bash = git_root / "bin" / "bash.exe"
1642
+ if git_bash.is_file():
1643
+ return str(git_bash)
1644
+
1645
+ return shutil.which("pwsh", path=env.get("PATH"))
1646
+
1647
+
1648
+ def configure_opencode_windows_shell(
1649
+ env: dict[str, str], *, required: bool = False,
1650
+ ) -> dict[str, str]:
1651
+ """Force OpenCode off classic Windows PowerShell for agent tool calls."""
1652
+ env = dict(env)
1653
+ if sys.platform != "win32":
1654
+ return env
1655
+
1656
+ shell = _find_opencode_windows_shell(env)
1657
+ if not shell:
1658
+ message = (
1659
+ "OpenCode on Windows requires Git Bash or PowerShell 7 (pwsh) so "
1660
+ "agent tool output is UTF-8. Install Git for Windows or PowerShell 7, "
1661
+ "then retry or select another agent."
1662
+ )
1663
+ if required:
1664
+ raise RuntimeError(message)
1665
+ logger.warning(message)
1666
+ return env
1667
+
1668
+ raw_config = env.get("OPENCODE_CONFIG_CONTENT", "").strip()
1669
+ config: dict[str, Any] = {}
1670
+ if raw_config:
1671
+ try:
1672
+ parsed = json.loads(raw_config)
1673
+ except json.JSONDecodeError as exc:
1674
+ raise RuntimeError(
1675
+ "OPENCODE_CONFIG_CONTENT must be a JSON object to configure "
1676
+ "OpenCode's Windows tool shell."
1677
+ ) from exc
1678
+ if not isinstance(parsed, dict):
1679
+ raise RuntimeError(
1680
+ "OPENCODE_CONFIG_CONTENT must be a JSON object to configure "
1681
+ "OpenCode's Windows tool shell."
1682
+ )
1683
+ config = parsed
1684
+
1685
+ config["shell"] = shell
1686
+ env["OPENCODE_CONFIG_CONTENT"] = json.dumps(config, ensure_ascii=False)
1627
1687
  return env
1628
1688
 
1629
1689