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.
@@ -0,0 +1,5 @@
1
+ include pi4py_build_backend.py
2
+ include tools/prune_npm_runtime.py
3
+ include src/pi4py/py.typed
4
+ recursive-include src/pi4py/_shim *
5
+ recursive-include src/pi4py/_vendor/npm_runtime *
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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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,4 @@
1
+ from __future__ import annotations
2
+
3
+ PI_PACKAGE_NAME = "@jamwil/pi-coding-agent"
4
+ PI_VERSION = "0.79.7-jamwil.0"
@@ -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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+ PYTHON_EXECUTABLE="${PI4PY_PYTHON_EXECUTABLE:-python}"
4
+ exec "$PYTHON_EXECUTABLE" -m pi4py._nodejs corepack "$@"
@@ -0,0 +1,4 @@
1
+ @echo off
2
+ set "PYTHON_EXECUTABLE=%PI4PY_PYTHON_EXECUTABLE%"
3
+ if not defined PYTHON_EXECUTABLE set "PYTHON_EXECUTABLE=python"
4
+ "%PYTHON_EXECUTABLE%" -m pi4py._nodejs corepack %*
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+ PYTHON_EXECUTABLE="${PI4PY_PYTHON_EXECUTABLE:-python}"
4
+ exec "$PYTHON_EXECUTABLE" -m pi4py._nodejs node "$@"
@@ -0,0 +1,4 @@
1
+ @echo off
2
+ set "PYTHON_EXECUTABLE=%PI4PY_PYTHON_EXECUTABLE%"
3
+ if not defined PYTHON_EXECUTABLE set "PYTHON_EXECUTABLE=python"
4
+ "%PYTHON_EXECUTABLE%" -m pi4py._nodejs node %*
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+ PYTHON_EXECUTABLE="${PI4PY_PYTHON_EXECUTABLE:-python}"
4
+ exec "$PYTHON_EXECUTABLE" -m pi4py._nodejs npm "$@"
@@ -0,0 +1,4 @@
1
+ @echo off
2
+ set "PYTHON_EXECUTABLE=%PI4PY_PYTHON_EXECUTABLE%"
3
+ if not defined PYTHON_EXECUTABLE set "PYTHON_EXECUTABLE=python"
4
+ "%PYTHON_EXECUTABLE%" -m pi4py._nodejs npm %*
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+ PYTHON_EXECUTABLE="${PI4PY_PYTHON_EXECUTABLE:-python}"
4
+ exec "$PYTHON_EXECUTABLE" -m pi4py._nodejs npx "$@"
@@ -0,0 +1,4 @@
1
+ @echo off
2
+ set "PYTHON_EXECUTABLE=%PI4PY_PYTHON_EXECUTABLE%"
3
+ if not defined PYTHON_EXECUTABLE set "PYTHON_EXECUTABLE=python"
4
+ "%PYTHON_EXECUTABLE%" -m pi4py._nodejs npx %*
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,2 @@
1
+ [console_scripts]
2
+ pi = pi4py._launcher:main
@@ -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())