imurun 0.1.3__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.
- imurun-0.1.3/.gitignore +5 -0
- imurun-0.1.3/LICENSE +21 -0
- imurun-0.1.3/PKG-INFO +70 -0
- imurun-0.1.3/README.md +47 -0
- imurun-0.1.3/imurun/__init__.py +218 -0
- imurun-0.1.3/imurun/__main__.py +10 -0
- imurun-0.1.3/pyproject.toml +39 -0
imurun-0.1.3/.gitignore
ADDED
imurun-0.1.3/LICENSE
ADDED
|
@@ -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.
|
imurun-0.1.3/PKG-INFO
ADDED
|
@@ -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.
|
imurun-0.1.3/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# IMURUN — Python launcher
|
|
2
|
+
|
|
3
|
+
`pip install imurun` puts a single **`imurun`** command on your PATH.
|
|
4
|
+
|
|
5
|
+
IMURUN itself is a compiled program, so this package does the one thing a
|
|
6
|
+
Python install can do that a downloaded file cannot: pick the right build for
|
|
7
|
+
the machine, cache it under `~/.imurun/python`, and run it.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install imurun
|
|
11
|
+
|
|
12
|
+
imurun # the interactive terminal UI
|
|
13
|
+
imurun models # what this machine can run
|
|
14
|
+
imurun models install qwen2.5-coder-7b
|
|
15
|
+
imurun run "explain this project"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The first run downloads the matching standalone executable from the project's
|
|
19
|
+
GitHub releases (Windows, Linux and macOS on x64 and arm64). Later runs start
|
|
20
|
+
immediately. Nothing is installed system-wide and no administrator rights are
|
|
21
|
+
needed.
|
|
22
|
+
|
|
23
|
+
## Other ways to install
|
|
24
|
+
|
|
25
|
+
The command is the same everywhere — pick whichever suits your machine:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g imurun # needs Bun 1.2+
|
|
29
|
+
npm install -g https://github.com/shubham001312/imurun/releases/latest/download/imurun-npm.tgz
|
|
30
|
+
pip install imurun # this package
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or download a standalone binary from
|
|
34
|
+
<https://github.com/shubham001312/imurun/releases/latest> — it needs nothing
|
|
35
|
+
else installed.
|
|
36
|
+
|
|
37
|
+
## What it does
|
|
38
|
+
|
|
39
|
+
- Installs, manages and runs local language models on your own hardware.
|
|
40
|
+
- No cloud dependency, no account, no telemetry.
|
|
41
|
+
- Works offline once the model is downloaded.
|
|
42
|
+
- MIT licensed, by [ImuTechz](https://imutechz.in) — Shubham Mallick
|
|
43
|
+
(<dev@imutechz.in>).
|
|
44
|
+
|
|
45
|
+
## License
|
|
46
|
+
|
|
47
|
+
MIT. See the project repository for the full text.
|
|
@@ -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())
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "imurun"
|
|
7
|
+
version = "0.1.3"
|
|
8
|
+
description = "IMURUN - local-first AI coding agent. Installs, manages and runs local LLMs on your own machine."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Shubham Mallick", email = "dev@imutechz.in" }]
|
|
13
|
+
keywords = ["ai", "agent", "llm", "local", "llama.cpp", "coding", "cli", "offline"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Operating System :: MacOS",
|
|
20
|
+
"Operating System :: Microsoft :: Windows",
|
|
21
|
+
"Operating System :: POSIX :: Linux",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
|
+
]
|
|
25
|
+
dependencies = []
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://imutechz.in"
|
|
29
|
+
Repository = "https://github.com/shubham001312/imurun"
|
|
30
|
+
Issues = "https://github.com/shubham001312/imurun/issues"
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
imurun = "imurun:main"
|
|
34
|
+
|
|
35
|
+
[tool.hatch.build.targets.wheel]
|
|
36
|
+
packages = ["imurun"]
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.sdist]
|
|
39
|
+
include = ["imurun", "README.md", "LICENSE"]
|