pi4py 0.79.7__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.
- pi4py-0.79.7/MANIFEST.in +5 -0
- pi4py-0.79.7/PKG-INFO +80 -0
- pi4py-0.79.7/README.md +70 -0
- pi4py-0.79.7/pi4py_build_backend.py +138 -0
- pi4py-0.79.7/pyproject.toml +30 -0
- pi4py-0.79.7/setup.cfg +4 -0
- pi4py-0.79.7/src/pi4py/__init__.py +1 -0
- pi4py-0.79.7/src/pi4py/_launcher.py +53 -0
- pi4py-0.79.7/src/pi4py/_nodejs.py +57 -0
- pi4py-0.79.7/src/pi4py/_pi.py +4 -0
- pi4py-0.79.7/src/pi4py/_runtime.py +24 -0
- pi4py-0.79.7/src/pi4py/_shim/corepack +4 -0
- pi4py-0.79.7/src/pi4py/_shim/corepack.cmd +4 -0
- pi4py-0.79.7/src/pi4py/_shim/node +4 -0
- pi4py-0.79.7/src/pi4py/_shim/node.cmd +4 -0
- pi4py-0.79.7/src/pi4py/_shim/npm +4 -0
- pi4py-0.79.7/src/pi4py/_shim/npm.cmd +4 -0
- pi4py-0.79.7/src/pi4py/_shim/npx +4 -0
- pi4py-0.79.7/src/pi4py/_shim/npx.cmd +4 -0
- pi4py-0.79.7/src/pi4py/py.typed +0 -0
- pi4py-0.79.7/src/pi4py.egg-info/PKG-INFO +80 -0
- pi4py-0.79.7/src/pi4py.egg-info/SOURCES.txt +25 -0
- pi4py-0.79.7/src/pi4py.egg-info/dependency_links.txt +1 -0
- pi4py-0.79.7/src/pi4py.egg-info/entry_points.txt +2 -0
- pi4py-0.79.7/src/pi4py.egg-info/requires.txt +1 -0
- pi4py-0.79.7/src/pi4py.egg-info/top_level.txt +1 -0
- pi4py-0.79.7/tools/prune_npm_runtime.py +125 -0
pi4py-0.79.7/MANIFEST.in
ADDED
pi4py-0.79.7/PKG-INFO
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pi4py
|
|
3
|
+
Version: 0.79.7
|
|
4
|
+
Summary: Python wheel wrapper for the @jamwil/pi coding agent
|
|
5
|
+
Author-email: James Williams <jamwil@gmail.com>
|
|
6
|
+
Project-URL: Repository, https://github.com/jamwil/pi4py
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: nodejs-wheel-binaries~=24.14
|
|
10
|
+
|
|
11
|
+
# pi4py
|
|
12
|
+
|
|
13
|
+
`pi4py` packages a Python launcher for the `@jamwil/pi-coding-agent` npm CLI.
|
|
14
|
+
|
|
15
|
+
`@jamwil/pi-coding-agent` is a slow fork of `@mariozechner/pi-coding-agent`.
|
|
16
|
+
|
|
17
|
+
The primary use for this is to expose a self-contained `pi` executable that can
|
|
18
|
+
be used from python using rpc mode.
|
|
19
|
+
|
|
20
|
+
## What it installs
|
|
21
|
+
|
|
22
|
+
- a `pi` console script
|
|
23
|
+
- `nodejs-wheel-binaries` as the bundled Node.js runtime
|
|
24
|
+
- a build hook that installs the pinned `@jamwil/pi-coding-agent` npm package
|
|
25
|
+
and packages the resulting npm runtime into the Python wheel
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
Install the wheel and invoke the console script with `pi` from the command line
|
|
30
|
+
or from Python with `subprocess.Popen`:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import subprocess
|
|
34
|
+
|
|
35
|
+
process = subprocess.Popen(["pi", "--help"])
|
|
36
|
+
process.wait()
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The `pi` entry point launches the bundled `@jamwil/pi-coding-agent` CLI with the
|
|
40
|
+
bundled Node.js executable. The npm dependencies, including
|
|
41
|
+
`@jamwil/pi-coding-agent` itself, are installed during wheel build / pip install
|
|
42
|
+
from sdist, not on first launch.
|
|
43
|
+
|
|
44
|
+
It also routes `npm`, `npx`, `node`, and `corepack` lookups to bundled shims and
|
|
45
|
+
isolates npm global installs under `PI_CODING_AGENT_DIR/npm-global` by default.
|
|
46
|
+
|
|
47
|
+
Useful environment variables:
|
|
48
|
+
|
|
49
|
+
- `PI4PY_NPM_PREFIX`: override the npm global prefix used by launched pi
|
|
50
|
+
subprocesses
|
|
51
|
+
- `PI4PY_SKIP_NPM_BUILD`: skip the npm build hook for metadata/debug builds
|
|
52
|
+
only; the resulting package will not run unless a runtime is already present
|
|
53
|
+
|
|
54
|
+
## Updating the pinned pi version
|
|
55
|
+
|
|
56
|
+
Sync dependencies, then update the pinned npm version:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv sync
|
|
60
|
+
uv run python tools/update_pi_version.py --version 0.66.1-jamwil.0
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Building
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv build
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Building downloads the pinned `@jamwil/pi-coding-agent` npm package plus its
|
|
70
|
+
production npm dependencies into `src/pi4py/_vendor/npm_runtime`, prunes the
|
|
71
|
+
runtime, and includes it in the wheel.
|
|
72
|
+
|
|
73
|
+
## Testing the bundled wheel
|
|
74
|
+
|
|
75
|
+
`uv run pi` may run the local editable/source checkout rather than the wheel
|
|
76
|
+
artifact. To test the actual bundled runtime:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uv run --no-editable pi --help
|
|
80
|
+
```
|
pi4py-0.79.7/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# pi4py
|
|
2
|
+
|
|
3
|
+
`pi4py` packages a Python launcher for the `@jamwil/pi-coding-agent` npm CLI.
|
|
4
|
+
|
|
5
|
+
`@jamwil/pi-coding-agent` is a slow fork of `@mariozechner/pi-coding-agent`.
|
|
6
|
+
|
|
7
|
+
The primary use for this is to expose a self-contained `pi` executable that can
|
|
8
|
+
be used from python using rpc mode.
|
|
9
|
+
|
|
10
|
+
## What it installs
|
|
11
|
+
|
|
12
|
+
- a `pi` console script
|
|
13
|
+
- `nodejs-wheel-binaries` as the bundled Node.js runtime
|
|
14
|
+
- a build hook that installs the pinned `@jamwil/pi-coding-agent` npm package
|
|
15
|
+
and packages the resulting npm runtime into the Python wheel
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Install the wheel and invoke the console script with `pi` from the command line
|
|
20
|
+
or from Python with `subprocess.Popen`:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import subprocess
|
|
24
|
+
|
|
25
|
+
process = subprocess.Popen(["pi", "--help"])
|
|
26
|
+
process.wait()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The `pi` entry point launches the bundled `@jamwil/pi-coding-agent` CLI with the
|
|
30
|
+
bundled Node.js executable. The npm dependencies, including
|
|
31
|
+
`@jamwil/pi-coding-agent` itself, are installed during wheel build / pip install
|
|
32
|
+
from sdist, not on first launch.
|
|
33
|
+
|
|
34
|
+
It also routes `npm`, `npx`, `node`, and `corepack` lookups to bundled shims and
|
|
35
|
+
isolates npm global installs under `PI_CODING_AGENT_DIR/npm-global` by default.
|
|
36
|
+
|
|
37
|
+
Useful environment variables:
|
|
38
|
+
|
|
39
|
+
- `PI4PY_NPM_PREFIX`: override the npm global prefix used by launched pi
|
|
40
|
+
subprocesses
|
|
41
|
+
- `PI4PY_SKIP_NPM_BUILD`: skip the npm build hook for metadata/debug builds
|
|
42
|
+
only; the resulting package will not run unless a runtime is already present
|
|
43
|
+
|
|
44
|
+
## Updating the pinned pi version
|
|
45
|
+
|
|
46
|
+
Sync dependencies, then update the pinned npm version:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv sync
|
|
50
|
+
uv run python tools/update_pi_version.py --version 0.66.1-jamwil.0
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Building
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uv build
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Building downloads the pinned `@jamwil/pi-coding-agent` npm package plus its
|
|
60
|
+
production npm dependencies into `src/pi4py/_vendor/npm_runtime`, prunes the
|
|
61
|
+
runtime, and includes it in the wheel.
|
|
62
|
+
|
|
63
|
+
## Testing the bundled wheel
|
|
64
|
+
|
|
65
|
+
`uv run pi` may run the local editable/source checkout rather than the wheel
|
|
66
|
+
artifact. To test the actual bundled runtime:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv run --no-editable pi --help
|
|
70
|
+
```
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
import tempfile
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from setuptools import build_meta as _setuptools_build_meta
|
|
11
|
+
from setuptools.build_meta import * # noqa: F401,F403 - re-export PEP 517 hooks
|
|
12
|
+
|
|
13
|
+
from tools.prune_npm_runtime import prune_npm_runtime
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
from nodejs_wheel.executable import npm
|
|
17
|
+
except Exception as exc: # pragma: no cover - build-time dependency error path
|
|
18
|
+
npm = None # type: ignore[assignment]
|
|
19
|
+
_NODE_IMPORT_ERROR = exc
|
|
20
|
+
else:
|
|
21
|
+
_NODE_IMPORT_ERROR = None
|
|
22
|
+
|
|
23
|
+
PROJECT_ROOT = Path(__file__).resolve().parent
|
|
24
|
+
RUNTIME_DIR = PROJECT_ROOT / "src" / "pi4py" / "_vendor" / "npm_runtime"
|
|
25
|
+
RUNTIME_METADATA = PROJECT_ROOT / "src" / "pi4py" / "_vendor" / "runtime.json"
|
|
26
|
+
PI_PACKAGE_NAME = "@jamwil/pi-coding-agent"
|
|
27
|
+
PI_VERSION = "0.79.7-jamwil.0"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _run_npm(args: list[str], cwd: Path, env: dict[str, str]) -> None:
|
|
31
|
+
if npm is None:
|
|
32
|
+
raise RuntimeError(
|
|
33
|
+
"nodejs-wheel-binaries is required to build the pi runtime"
|
|
34
|
+
) from _NODE_IMPORT_ERROR
|
|
35
|
+
npm(args, cwd=str(cwd), env=env, check=True)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _build_env() -> dict[str, str]:
|
|
39
|
+
env = os.environ.copy()
|
|
40
|
+
env.setdefault("npm_config_audit", "false")
|
|
41
|
+
env.setdefault("npm_config_fund", "false")
|
|
42
|
+
env.setdefault("npm_config_update_notifier", "false")
|
|
43
|
+
env.setdefault("npm_config_progress", "false")
|
|
44
|
+
env.setdefault("npm_config_loglevel", "warn")
|
|
45
|
+
return env
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _install_runtime(runtime_project_dir: Path, env: dict[str, str]) -> None:
|
|
49
|
+
(runtime_project_dir / "package.json").write_text(
|
|
50
|
+
json.dumps(
|
|
51
|
+
{
|
|
52
|
+
"name": "pi4py-runtime",
|
|
53
|
+
"private": True,
|
|
54
|
+
"dependencies": {PI_PACKAGE_NAME: PI_VERSION},
|
|
55
|
+
},
|
|
56
|
+
indent=2,
|
|
57
|
+
)
|
|
58
|
+
+ "\n",
|
|
59
|
+
encoding="utf-8",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
_run_npm(
|
|
63
|
+
[
|
|
64
|
+
"install",
|
|
65
|
+
"--omit=dev",
|
|
66
|
+
"--omit=optional",
|
|
67
|
+
"--ignore-scripts",
|
|
68
|
+
"--no-audit",
|
|
69
|
+
"--no-fund",
|
|
70
|
+
],
|
|
71
|
+
cwd=runtime_project_dir,
|
|
72
|
+
env=env,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
cli_js = runtime_project_dir / "node_modules" / "@jamwil" / "pi-coding-agent" / "dist" / "cli.js"
|
|
76
|
+
if not cli_js.is_file():
|
|
77
|
+
raise RuntimeError(f"Installed pi CLI was not found: {cli_js}")
|
|
78
|
+
|
|
79
|
+
shutil.rmtree(runtime_project_dir / "node_modules" / ".bin", ignore_errors=True)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _clean_runtime() -> None:
|
|
83
|
+
shutil.rmtree(RUNTIME_DIR, ignore_errors=True)
|
|
84
|
+
RUNTIME_METADATA.unlink(missing_ok=True)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _build_pi_runtime() -> None:
|
|
88
|
+
if os.environ.get("PI4PY_SKIP_NPM_BUILD"):
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
_clean_runtime()
|
|
92
|
+
env = _build_env()
|
|
93
|
+
|
|
94
|
+
with tempfile.TemporaryDirectory(prefix="pi4py-build-") as temp_dir_name:
|
|
95
|
+
temp_dir = Path(temp_dir_name)
|
|
96
|
+
runtime_project_dir = temp_dir / "runtime"
|
|
97
|
+
runtime_project_dir.mkdir()
|
|
98
|
+
|
|
99
|
+
_install_runtime(runtime_project_dir, env)
|
|
100
|
+
|
|
101
|
+
RUNTIME_DIR.parent.mkdir(parents=True, exist_ok=True)
|
|
102
|
+
shutil.copytree(runtime_project_dir / "node_modules", RUNTIME_DIR / "node_modules")
|
|
103
|
+
prune_npm_runtime(RUNTIME_DIR / "node_modules")
|
|
104
|
+
shutil.copy2(runtime_project_dir / "package.json", RUNTIME_DIR / "package.json")
|
|
105
|
+
package_lock = runtime_project_dir / "package-lock.json"
|
|
106
|
+
if package_lock.is_file():
|
|
107
|
+
shutil.copy2(package_lock, RUNTIME_DIR / "package-lock.json")
|
|
108
|
+
|
|
109
|
+
RUNTIME_METADATA.write_text(
|
|
110
|
+
json.dumps(
|
|
111
|
+
{
|
|
112
|
+
"package": PI_PACKAGE_NAME,
|
|
113
|
+
"version": PI_VERSION,
|
|
114
|
+
"source": "npm",
|
|
115
|
+
"built_at": datetime.now(timezone.utc).isoformat(),
|
|
116
|
+
},
|
|
117
|
+
indent=2,
|
|
118
|
+
)
|
|
119
|
+
+ "\n",
|
|
120
|
+
encoding="utf-8",
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
|
125
|
+
_build_pi_runtime()
|
|
126
|
+
return _setuptools_build_meta.build_wheel(wheel_directory, config_settings, metadata_directory)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def build_editable(wheel_directory, config_settings=None, metadata_directory=None):
|
|
130
|
+
_build_pi_runtime()
|
|
131
|
+
return _setuptools_build_meta.build_editable(wheel_directory, config_settings, metadata_directory)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def build_sdist(sdist_directory, config_settings=None):
|
|
135
|
+
# Keep sdists source-only. Wheels built from the sdist will run build_wheel
|
|
136
|
+
# and generate src/pi4py/_vendor/npm_runtime then.
|
|
137
|
+
_clean_runtime()
|
|
138
|
+
return _setuptools_build_meta.build_sdist(sdist_directory, config_settings)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pi4py"
|
|
3
|
+
version = "0.79.7"
|
|
4
|
+
description = "Python wheel wrapper for the @jamwil/pi coding agent"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "James Williams", email = "jamwil@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.9"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"nodejs-wheel-binaries~=24.14",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
Repository = "https://github.com/jamwil/pi4py"
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
pi = "pi4py._launcher:main"
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["setuptools>=80", "wheel", "nodejs-wheel-binaries~=24.14"]
|
|
22
|
+
build-backend = "pi4py_build_backend"
|
|
23
|
+
backend-path = ["."]
|
|
24
|
+
|
|
25
|
+
[tool.setuptools]
|
|
26
|
+
package-dir = { "" = "src" }
|
|
27
|
+
include-package-data = true
|
|
28
|
+
|
|
29
|
+
[tool.setuptools.packages.find]
|
|
30
|
+
where = ["src"]
|
pi4py-0.79.7/setup.cfg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""pi4py package."""
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from pi4py._nodejs import node_executable
|
|
9
|
+
from pi4py._runtime import ensure_cli
|
|
10
|
+
|
|
11
|
+
_PACKAGE_DIR = Path(__file__).resolve().parent
|
|
12
|
+
_SHIM_DIR = _PACKAGE_DIR / "_shim"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _build_env() -> dict[str, str]:
|
|
16
|
+
env = os.environ.copy()
|
|
17
|
+
path = env.get("PATH")
|
|
18
|
+
shim_dir = str(_SHIM_DIR)
|
|
19
|
+
env["PATH"] = shim_dir if not path else os.pathsep.join([shim_dir, path])
|
|
20
|
+
env["PI4PY_PYTHON_EXECUTABLE"] = sys.executable
|
|
21
|
+
|
|
22
|
+
agent_dir = Path(env.get("PI_CODING_AGENT_DIR", Path.home() / ".pi" / "agent"))
|
|
23
|
+
npm_prefix = Path(env.get("PI4PY_NPM_PREFIX", agent_dir / "npm-global"))
|
|
24
|
+
npm_prefix.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
env.setdefault("NPM_CONFIG_PREFIX", str(npm_prefix))
|
|
26
|
+
env.setdefault("npm_config_prefix", str(npm_prefix))
|
|
27
|
+
|
|
28
|
+
env.setdefault("npm_config_update_notifier", "false")
|
|
29
|
+
env.setdefault("npm_config_fund", "false")
|
|
30
|
+
return env
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _argv(env: dict[str, str]) -> list[str]:
|
|
34
|
+
try:
|
|
35
|
+
pi_cli = ensure_cli()
|
|
36
|
+
except Exception as exc:
|
|
37
|
+
raise SystemExit(f"Unable to locate bundled @jamwil/pi-coding-agent runtime: {exc}") from exc
|
|
38
|
+
|
|
39
|
+
return [node_executable(), str(pi_cli), *sys.argv[1:]]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def main() -> int:
|
|
43
|
+
env = _build_env()
|
|
44
|
+
argv = _argv(env)
|
|
45
|
+
|
|
46
|
+
if os.name != "nt":
|
|
47
|
+
os.execvpe(argv[0], argv, env)
|
|
48
|
+
|
|
49
|
+
return subprocess.call(argv, env=env, close_fds=False)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from nodejs_wheel import executable as nodejs_executable
|
|
9
|
+
|
|
10
|
+
_ROOT_DIR = Path(nodejs_executable.ROOT_DIR)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def node_executable() -> str:
|
|
14
|
+
if os.name == "nt":
|
|
15
|
+
return str(_ROOT_DIR / "node.exe")
|
|
16
|
+
return str(_ROOT_DIR / "bin" / "node")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def npm_cli() -> str:
|
|
20
|
+
return str(_ROOT_DIR / "lib" / "node_modules" / "npm" / "bin" / "npm-cli.js")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def npx_cli() -> str:
|
|
24
|
+
return str(_ROOT_DIR / "lib" / "node_modules" / "npm" / "bin" / "npx-cli.js")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def corepack_cli() -> str:
|
|
28
|
+
return str(_ROOT_DIR / "lib" / "node_modules" / "corepack" / "dist" / "corepack.js")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def command_argv(command: str, args: list[str]) -> list[str]:
|
|
32
|
+
if command == "node":
|
|
33
|
+
return [node_executable(), *args]
|
|
34
|
+
if command == "npm":
|
|
35
|
+
return [node_executable(), npm_cli(), *args]
|
|
36
|
+
if command == "npx":
|
|
37
|
+
return [node_executable(), npx_cli(), *args]
|
|
38
|
+
if command == "corepack":
|
|
39
|
+
return [node_executable(), corepack_cli(), *args]
|
|
40
|
+
raise ValueError(f"Unsupported nodejs helper command: {command}")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def run(command: str, args: list[str]) -> int:
|
|
44
|
+
argv = command_argv(command, args)
|
|
45
|
+
if os.name != "nt":
|
|
46
|
+
os.execv(argv[0], argv)
|
|
47
|
+
return subprocess.call(argv, close_fds=False)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def main() -> int:
|
|
51
|
+
if len(sys.argv) < 2:
|
|
52
|
+
raise SystemExit("Usage: python -m pi4py._nodejs <node|npm|npx|corepack> [args...]")
|
|
53
|
+
return run(sys.argv[1], sys.argv[2:])
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
_PACKAGE_DIR = Path(__file__).resolve().parent
|
|
6
|
+
_RUNTIME_DIR = _PACKAGE_DIR / "_vendor" / "npm_runtime"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def install_root() -> Path:
|
|
10
|
+
return _RUNTIME_DIR
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def cli_path() -> Path:
|
|
14
|
+
return install_root() / "node_modules" / "@jamwil" / "pi-coding-agent" / "dist" / "cli.js"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def ensure_cli() -> Path:
|
|
18
|
+
pi_cli = cli_path()
|
|
19
|
+
if not pi_cli.is_file():
|
|
20
|
+
raise RuntimeError(
|
|
21
|
+
"The bundled pi runtime is missing. Reinstall pi4py from a wheel or rebuild it "
|
|
22
|
+
"without PI4PY_SKIP_NPM_BUILD."
|
|
23
|
+
)
|
|
24
|
+
return pi_cli
|
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pi4py
|
|
3
|
+
Version: 0.79.7
|
|
4
|
+
Summary: Python wheel wrapper for the @jamwil/pi coding agent
|
|
5
|
+
Author-email: James Williams <jamwil@gmail.com>
|
|
6
|
+
Project-URL: Repository, https://github.com/jamwil/pi4py
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: nodejs-wheel-binaries~=24.14
|
|
10
|
+
|
|
11
|
+
# pi4py
|
|
12
|
+
|
|
13
|
+
`pi4py` packages a Python launcher for the `@jamwil/pi-coding-agent` npm CLI.
|
|
14
|
+
|
|
15
|
+
`@jamwil/pi-coding-agent` is a slow fork of `@mariozechner/pi-coding-agent`.
|
|
16
|
+
|
|
17
|
+
The primary use for this is to expose a self-contained `pi` executable that can
|
|
18
|
+
be used from python using rpc mode.
|
|
19
|
+
|
|
20
|
+
## What it installs
|
|
21
|
+
|
|
22
|
+
- a `pi` console script
|
|
23
|
+
- `nodejs-wheel-binaries` as the bundled Node.js runtime
|
|
24
|
+
- a build hook that installs the pinned `@jamwil/pi-coding-agent` npm package
|
|
25
|
+
and packages the resulting npm runtime into the Python wheel
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
Install the wheel and invoke the console script with `pi` from the command line
|
|
30
|
+
or from Python with `subprocess.Popen`:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import subprocess
|
|
34
|
+
|
|
35
|
+
process = subprocess.Popen(["pi", "--help"])
|
|
36
|
+
process.wait()
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The `pi` entry point launches the bundled `@jamwil/pi-coding-agent` CLI with the
|
|
40
|
+
bundled Node.js executable. The npm dependencies, including
|
|
41
|
+
`@jamwil/pi-coding-agent` itself, are installed during wheel build / pip install
|
|
42
|
+
from sdist, not on first launch.
|
|
43
|
+
|
|
44
|
+
It also routes `npm`, `npx`, `node`, and `corepack` lookups to bundled shims and
|
|
45
|
+
isolates npm global installs under `PI_CODING_AGENT_DIR/npm-global` by default.
|
|
46
|
+
|
|
47
|
+
Useful environment variables:
|
|
48
|
+
|
|
49
|
+
- `PI4PY_NPM_PREFIX`: override the npm global prefix used by launched pi
|
|
50
|
+
subprocesses
|
|
51
|
+
- `PI4PY_SKIP_NPM_BUILD`: skip the npm build hook for metadata/debug builds
|
|
52
|
+
only; the resulting package will not run unless a runtime is already present
|
|
53
|
+
|
|
54
|
+
## Updating the pinned pi version
|
|
55
|
+
|
|
56
|
+
Sync dependencies, then update the pinned npm version:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv sync
|
|
60
|
+
uv run python tools/update_pi_version.py --version 0.66.1-jamwil.0
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Building
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv build
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Building downloads the pinned `@jamwil/pi-coding-agent` npm package plus its
|
|
70
|
+
production npm dependencies into `src/pi4py/_vendor/npm_runtime`, prunes the
|
|
71
|
+
runtime, and includes it in the wheel.
|
|
72
|
+
|
|
73
|
+
## Testing the bundled wheel
|
|
74
|
+
|
|
75
|
+
`uv run pi` may run the local editable/source checkout rather than the wheel
|
|
76
|
+
artifact. To test the actual bundled runtime:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uv run --no-editable pi --help
|
|
80
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.md
|
|
3
|
+
pi4py_build_backend.py
|
|
4
|
+
pyproject.toml
|
|
5
|
+
src/pi4py/__init__.py
|
|
6
|
+
src/pi4py/_launcher.py
|
|
7
|
+
src/pi4py/_nodejs.py
|
|
8
|
+
src/pi4py/_pi.py
|
|
9
|
+
src/pi4py/_runtime.py
|
|
10
|
+
src/pi4py/py.typed
|
|
11
|
+
src/pi4py.egg-info/PKG-INFO
|
|
12
|
+
src/pi4py.egg-info/SOURCES.txt
|
|
13
|
+
src/pi4py.egg-info/dependency_links.txt
|
|
14
|
+
src/pi4py.egg-info/entry_points.txt
|
|
15
|
+
src/pi4py.egg-info/requires.txt
|
|
16
|
+
src/pi4py.egg-info/top_level.txt
|
|
17
|
+
src/pi4py/_shim/corepack
|
|
18
|
+
src/pi4py/_shim/corepack.cmd
|
|
19
|
+
src/pi4py/_shim/node
|
|
20
|
+
src/pi4py/_shim/node.cmd
|
|
21
|
+
src/pi4py/_shim/npm
|
|
22
|
+
src/pi4py/_shim/npm.cmd
|
|
23
|
+
src/pi4py/_shim/npx
|
|
24
|
+
src/pi4py/_shim/npx.cmd
|
|
25
|
+
tools/prune_npm_runtime.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nodejs-wheel-binaries~=24.14
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pi4py
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
7
|
+
DEFAULT_RUNTIME_ROOT = PROJECT_ROOT / "src" / "pi4py" / "_vendor" / "npm_runtime" / "node_modules"
|
|
8
|
+
|
|
9
|
+
REMOVABLE_DIRECTORIES = {
|
|
10
|
+
".github",
|
|
11
|
+
".husky",
|
|
12
|
+
"__mocks__",
|
|
13
|
+
"__tests__",
|
|
14
|
+
"benchmark",
|
|
15
|
+
"benchmarks",
|
|
16
|
+
"coverage",
|
|
17
|
+
"docs",
|
|
18
|
+
"example",
|
|
19
|
+
"examples",
|
|
20
|
+
"scripts",
|
|
21
|
+
"test",
|
|
22
|
+
"tests",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
REMOVABLE_SUFFIXES = (
|
|
26
|
+
".d.cts.map",
|
|
27
|
+
".d.mts.map",
|
|
28
|
+
".d.ts.map",
|
|
29
|
+
".js.map",
|
|
30
|
+
".mjs.map",
|
|
31
|
+
".cjs.map",
|
|
32
|
+
".cts",
|
|
33
|
+
".mts",
|
|
34
|
+
".ts",
|
|
35
|
+
".tsx",
|
|
36
|
+
".map",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
REMOVABLE_NAMES = {
|
|
40
|
+
".babelrc",
|
|
41
|
+
".editorconfig",
|
|
42
|
+
".eslintignore",
|
|
43
|
+
".eslintrc",
|
|
44
|
+
".eslintrc.cjs",
|
|
45
|
+
".eslintrc.js",
|
|
46
|
+
".gitattributes",
|
|
47
|
+
".gitignore",
|
|
48
|
+
".npmignore",
|
|
49
|
+
".nycrc",
|
|
50
|
+
".prettierignore",
|
|
51
|
+
".prettierrc",
|
|
52
|
+
".prettierrc.json",
|
|
53
|
+
".prettierrc.yaml",
|
|
54
|
+
".travis.yml",
|
|
55
|
+
"appveyor.yml",
|
|
56
|
+
"bower.json",
|
|
57
|
+
"changelog",
|
|
58
|
+
"changelog.md",
|
|
59
|
+
"changelog.markdown",
|
|
60
|
+
"contributing.md",
|
|
61
|
+
"eslint.config.js",
|
|
62
|
+
"gruntfile.js",
|
|
63
|
+
"gulpfile.js",
|
|
64
|
+
"makefile",
|
|
65
|
+
"package-lock.json",
|
|
66
|
+
"pnpm-lock.yaml",
|
|
67
|
+
"readme",
|
|
68
|
+
"readme.md",
|
|
69
|
+
"readme.markdown",
|
|
70
|
+
"rollup.config.js",
|
|
71
|
+
"tsconfig.json",
|
|
72
|
+
"tsconfig.build.json",
|
|
73
|
+
"typedoc.json",
|
|
74
|
+
"yarn.lock",
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Keep pi's own user-facing docs/examples because the system prompt points to them.
|
|
78
|
+
KEEP_PREFIX_PARTS = {
|
|
79
|
+
("@jamwil", "pi-coding-agent", "docs"),
|
|
80
|
+
("@jamwil", "pi-coding-agent", "examples"),
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _relative_parts(path: Path, root: Path) -> tuple[str, ...]:
|
|
85
|
+
try:
|
|
86
|
+
return path.relative_to(root).parts
|
|
87
|
+
except ValueError:
|
|
88
|
+
return ()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _is_kept(path: Path, root: Path) -> bool:
|
|
92
|
+
parts = _relative_parts(path, root)
|
|
93
|
+
if any(parts[: len(prefix)] == prefix for prefix in KEEP_PREFIX_PARTS):
|
|
94
|
+
return True
|
|
95
|
+
return parts[:2] == ("@jamwil", "pi-coding-agent") and path.name.lower() in {"readme.md", "changelog.md"}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def prune_npm_runtime(root: Path = DEFAULT_RUNTIME_ROOT) -> None:
|
|
99
|
+
if not root.is_dir():
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
for path in sorted(root.rglob("*"), key=lambda p: len(p.parts), reverse=True):
|
|
103
|
+
if _is_kept(path, root):
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
lower_name = path.name.lower()
|
|
107
|
+
if path.is_dir():
|
|
108
|
+
if lower_name in REMOVABLE_DIRECTORIES:
|
|
109
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
if not path.is_file():
|
|
113
|
+
continue
|
|
114
|
+
|
|
115
|
+
if lower_name in REMOVABLE_NAMES or lower_name.endswith(REMOVABLE_SUFFIXES):
|
|
116
|
+
path.unlink()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def main() -> int:
|
|
120
|
+
prune_npm_runtime()
|
|
121
|
+
return 0
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
if __name__ == "__main__":
|
|
125
|
+
raise SystemExit(main())
|