imurun 0.1.3__py3-none-any.whl

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.
imurun/__init__.py ADDED
@@ -0,0 +1,218 @@
1
+ """
2
+ IMURUN - the Python launcher.
3
+
4
+ ``pip install imurun`` puts a single ``imurun`` command on your PATH. IMURUN
5
+ itself is a compiled program, so this package does the one thing a Python
6
+ install can do that a downloaded file cannot: pick the right build for the
7
+ machine, put it somewhere sensible, and run it.
8
+
9
+ The first run downloads the matching standalone executable from the project's
10
+ GitHub releases and caches it under ``~/.imurun/python``. Later runs start
11
+ straight away. Nothing is installed system-wide, no administrator rights are
12
+ needed, and the download is verified against the size published with the
13
+ release.
14
+
15
+ If you would rather install the program itself, see https://imutechz.in and the
16
+ project README - the same command works from npm (``npm install -g imurun``)
17
+ and from a standalone binary.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import os
23
+ import platform
24
+ import shutil
25
+ import stat
26
+ import sys
27
+ import urllib.error
28
+ import urllib.request
29
+ from pathlib import Path
30
+
31
+ __all__ = ["__version__", "main", "launcher_path", "download_url"]
32
+
33
+ __version__ = "0.1.3"
34
+
35
+ #: Where the releases live. One place, so a move is a one-line change.
36
+ REPO = "shubham001312/imurun"
37
+
38
+ #: The fallback channel: the newest published release, whatever it is called.
39
+ LATEST = f"https://github.com/{REPO}/releases/latest/download"
40
+
41
+
42
+ def user_home() -> Path:
43
+ """The user's home directory, resolved the way the platform expects."""
44
+ override = os.environ.get("IMURUN_HOME")
45
+ if override:
46
+ return Path(override).expanduser()
47
+ return Path.home()
48
+
49
+
50
+ def cache_dir() -> Path:
51
+ """Where the downloaded executable lives."""
52
+ return user_home() / ".imurun" / "python"
53
+
54
+
55
+ def platform_key() -> str:
56
+ """The release asset name for this machine, e.g. ``imurun-linux-x64``."""
57
+ system = platform.system().lower()
58
+ machine = platform.machine().lower()
59
+
60
+ if system == "windows":
61
+ os_name = "windows"
62
+ elif system == "darwin":
63
+ os_name = "darwin"
64
+ else:
65
+ os_name = "linux"
66
+
67
+ if machine in ("x86_64", "amd64", "x64"):
68
+ arch = "x64"
69
+ elif machine in ("arm64", "aarch64"):
70
+ arch = "arm64"
71
+ elif machine in ("i386", "i686", "x86"):
72
+ arch = "x64" # the 32-bit builds are not published; x64 is the closest
73
+ else:
74
+ arch = "x64"
75
+
76
+ return f"imurun-{os_name}-{arch}"
77
+
78
+
79
+ def is_windows() -> bool:
80
+ return platform.system().lower() == "windows"
81
+
82
+
83
+ def binary_name() -> str:
84
+ """The file name the executable is stored under on this machine."""
85
+ return f"{platform_key()}.exe" if is_windows() else platform_key()
86
+
87
+
88
+ def download_url() -> str:
89
+ """Where the executable for this machine is fetched from."""
90
+ return f"{LATEST}/{binary_name()}"
91
+
92
+
93
+ def launcher_path() -> Path:
94
+ """The full path of the cached executable."""
95
+ return cache_dir() / binary_name()
96
+
97
+
98
+ def _chmod_executable(path: Path) -> None:
99
+ """Make the file runnable. A no-op on Windows, where the bit means nothing."""
100
+ if is_windows():
101
+ return
102
+ mode = path.stat().st_mode
103
+ path.chmod(mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
104
+
105
+
106
+ def download_executable(destination: Path, url: str | None = None) -> Path:
107
+ """
108
+ Fetch the executable for this machine.
109
+
110
+ The download lands in a temporary file first and is moved into place only
111
+ once it has arrived whole, so an interrupted download never leaves a
112
+ truncated program behind that a later run would happily try to execute.
113
+ """
114
+ source = url or download_url()
115
+ destination.parent.mkdir(parents=True, exist_ok=True)
116
+ partial = destination.with_suffix(destination.suffix + ".part")
117
+
118
+ print(f"Downloading IMURUN for this machine…\n {source}", file=sys.stderr)
119
+ try:
120
+ with urllib.request.urlopen(source, timeout=120) as response:
121
+ total = response.headers.get("Content-Length")
122
+ expected = int(total) if total and total.isdigit() else 0
123
+ written = 0
124
+ with open(partial, "wb") as handle:
125
+ while True:
126
+ chunk = response.read(1 << 20)
127
+ if not chunk:
128
+ break
129
+ handle.write(chunk)
130
+ written += len(chunk)
131
+ if expected:
132
+ percent = int(written * 100 / expected)
133
+ print(f"\r {percent:3d}% ({written >> 20} MB)", end="", file=sys.stderr)
134
+ if expected and written != expected:
135
+ raise OSError(f"the download was incomplete ({written} of {expected} bytes)")
136
+ except urllib.error.URLError as error:
137
+ partial.unlink(missing_ok=True)
138
+ raise SystemExit(
139
+ f"Could not download IMURUN: {error}\n"
140
+ f"You can also install it directly:\n"
141
+ f" npm install -g imurun\n"
142
+ f" or download it from https://github.com/{REPO}/releases/latest"
143
+ ) from error
144
+ except BaseException:
145
+ partial.unlink(missing_ok=True)
146
+ raise
147
+
148
+ if expected:
149
+ print(file=sys.stderr)
150
+ _chmod_executable(partial)
151
+ partial.replace(destination)
152
+ return destination
153
+
154
+
155
+ def ensure_executable() -> Path:
156
+ """Return the cached executable, downloading it the first time."""
157
+ path = launcher_path()
158
+ if path.exists():
159
+ return path
160
+ return download_executable(path)
161
+
162
+
163
+ def main(argv: list[str] | None = None) -> int:
164
+ """
165
+ The ``imurun`` entry point.
166
+
167
+ Everything after the command name is handed straight to the program, so
168
+ ``imurun models install qwen2.5-coder-7b`` behaves exactly as it does when
169
+ installed any other way.
170
+ """
171
+ args = list(sys.argv[1:] if argv is None else argv)
172
+
173
+ if args and args[0] in ("--version", "-V"):
174
+ print(f"imurun {__version__}")
175
+ return 0
176
+
177
+ if args and args[0] in ("--help", "-h") and len(args) == 1:
178
+ print(__doc__.strip())
179
+ print(f"\nProject: https://github.com/{REPO}")
180
+ print("Website: https://imutechz.in")
181
+ return 0
182
+
183
+ executable = ensure_executable()
184
+
185
+ # A local build in the source tree wins, so a developer can run the
186
+ # program they are editing without a download.
187
+ local = Path.cwd() / "dist" / "imurun.js"
188
+ if local.exists():
189
+ return _run_bun(local, args)
190
+
191
+ return _run(executable, args)
192
+
193
+
194
+ def _run(executable: Path, args: list[str]) -> int:
195
+ """Run the executable, replacing this process when the platform allows it."""
196
+ try:
197
+ os.execv(str(executable), [str(executable), *args])
198
+ except OSError:
199
+ # execv replaces the process on POSIX; on Windows it is not available
200
+ # for the same reason, so the child is spawned and waited on instead.
201
+ import subprocess
202
+
203
+ return subprocess.call([str(executable), *args])
204
+ return 0
205
+
206
+
207
+ def _run_bun(bundle: Path, args: list[str]) -> int:
208
+ """Run a local bundle with Bun, when Bun is available."""
209
+ import subprocess
210
+
211
+ bun = shutil.which("bun")
212
+ if bun is None:
213
+ raise SystemExit("Bun is required to run a local build: https://bun.sh")
214
+ return subprocess.call([bun, str(bundle), *args])
215
+
216
+
217
+ if __name__ == "__main__": # pragma: no cover
218
+ raise SystemExit(main())
imurun/__main__.py ADDED
@@ -0,0 +1,10 @@
1
+ """The console entry point: ``imurun`` on PATH after ``pip install imurun``."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+
7
+ from . import main
8
+
9
+ if __name__ == "__main__":
10
+ sys.exit(main())
@@ -0,0 +1,70 @@
1
+ Metadata-Version: 2.5
2
+ Name: imurun
3
+ Version: 0.1.3
4
+ Summary: IMURUN - local-first AI coding agent. Installs, manages and runs local LLMs on your own machine.
5
+ Project-URL: Homepage, https://imutechz.in
6
+ Project-URL: Repository, https://github.com/shubham001312/imurun
7
+ Project-URL: Issues, https://github.com/shubham001312/imurun/issues
8
+ Author-email: Shubham Mallick <dev@imutechz.in>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,ai,cli,coding,llama.cpp,llm,local,offline
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+
24
+ # IMURUN — Python launcher
25
+
26
+ `pip install imurun` puts a single **`imurun`** command on your PATH.
27
+
28
+ IMURUN itself is a compiled program, so this package does the one thing a
29
+ Python install can do that a downloaded file cannot: pick the right build for
30
+ the machine, cache it under `~/.imurun/python`, and run it.
31
+
32
+ ```bash
33
+ pip install imurun
34
+
35
+ imurun # the interactive terminal UI
36
+ imurun models # what this machine can run
37
+ imurun models install qwen2.5-coder-7b
38
+ imurun run "explain this project"
39
+ ```
40
+
41
+ The first run downloads the matching standalone executable from the project's
42
+ GitHub releases (Windows, Linux and macOS on x64 and arm64). Later runs start
43
+ immediately. Nothing is installed system-wide and no administrator rights are
44
+ needed.
45
+
46
+ ## Other ways to install
47
+
48
+ The command is the same everywhere — pick whichever suits your machine:
49
+
50
+ ```bash
51
+ npm install -g imurun # needs Bun 1.2+
52
+ npm install -g https://github.com/shubham001312/imurun/releases/latest/download/imurun-npm.tgz
53
+ pip install imurun # this package
54
+ ```
55
+
56
+ Or download a standalone binary from
57
+ <https://github.com/shubham001312/imurun/releases/latest> — it needs nothing
58
+ else installed.
59
+
60
+ ## What it does
61
+
62
+ - Installs, manages and runs local language models on your own hardware.
63
+ - No cloud dependency, no account, no telemetry.
64
+ - Works offline once the model is downloaded.
65
+ - MIT licensed, by [ImuTechz](https://imutechz.in) — Shubham Mallick
66
+ (<dev@imutechz.in>).
67
+
68
+ ## License
69
+
70
+ MIT. See the project repository for the full text.
@@ -0,0 +1,7 @@
1
+ imurun/__init__.py,sha256=szUfpQh6wI9E_OIRG7EreFNRIPIRJDG7qbUIWzxZZpI,7163
2
+ imurun/__main__.py,sha256=9-aAgxuLLDG30sZLs5w9jC70ifYxjlqujj-1bu33uc0,197
3
+ imurun-0.1.3.dist-info/METADATA,sha256=8muLMiha098PJoDmuXy2LqAp2Evv2D1S665awstB3B4,2575
4
+ imurun-0.1.3.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
5
+ imurun-0.1.3.dist-info/entry_points.txt,sha256=70xbAN0BxXsWQ31vyo3x8ULP_KcWG5CvFDKQq4-tMos,39
6
+ imurun-0.1.3.dist-info/licenses/LICENSE,sha256=IAKsKr6zE6I8OuL_8a0JHQiuW93muQ8V4VbRbXCEMW8,1065
7
+ imurun-0.1.3.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ imurun = imurun:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ImuTechz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.