urun-cli 0.5.32__tar.gz → 0.6.1__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.
- {urun_cli-0.5.32 → urun_cli-0.6.1}/PKG-INFO +34 -22
- {urun_cli-0.5.32 → urun_cli-0.6.1}/README.md +33 -21
- urun_cli-0.6.1/hatch_build.py +145 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/pyproject.toml +12 -1
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/api.py +21 -10
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/catalog.py +151 -6
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/cli.py +1047 -557
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/client_tokens.py +38 -16
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/dev.py +225 -31
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/devconsole.py +2 -2
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/devstream.py +151 -8
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/frontend_launch.py +344 -22
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/launch_auth.py +63 -17
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/nodes.py +4 -2
- urun_cli-0.5.32/hatch_build.py +0 -93
- {urun_cli-0.5.32 → urun_cli-0.6.1}/.gitignore +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/CHANGELOG.md +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/LICENSE +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/SECURITY.md +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/__init__.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/_bin/README.md +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/buildlogs.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/config.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/deps.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/discovery.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/errors.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/fleet.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/manifest.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/openai_proxy_bin.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/repo_deps.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/retry.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/runtime_health.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/scratch.py +0 -0
- {urun_cli-0.5.32 → urun_cli-0.6.1}/src/urun/serve.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: urun-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: End-user CLI for deploying apps to urun
|
|
5
5
|
Project-URL: Homepage, https://urun.sh
|
|
6
6
|
Project-URL: Repository, https://github.com/urun-sh/urun-cli
|
|
@@ -108,8 +108,8 @@ urun deploy prompt_canary/backend/app.py --name prompt-canary --timeout 900
|
|
|
108
108
|
urun demo prompt-canary --examples-root ~/workspace/urun-examples
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
The positional argument is the **deployed app slug** (as shown by `urun
|
|
112
|
-
|
|
111
|
+
The positional argument is the **deployed app slug** (as shown by `urun app
|
|
112
|
+
list`). Nothing is declared in a manifest — every value is discovered:
|
|
113
113
|
|
|
114
114
|
| value | where it comes from |
|
|
115
115
|
| --- | --- |
|
|
@@ -193,7 +193,7 @@ row instead of rendering one.
|
|
|
193
193
|
List every app deployed in your org and its current status:
|
|
194
194
|
|
|
195
195
|
```bash
|
|
196
|
-
urun list
|
|
196
|
+
urun app list
|
|
197
197
|
```
|
|
198
198
|
|
|
199
199
|
Sample output:
|
|
@@ -226,21 +226,22 @@ endpoint, which is in development.
|
|
|
226
226
|
|
|
227
227
|
## View logs
|
|
228
228
|
|
|
229
|
-
Use `urun
|
|
229
|
+
Use `urun build logs`, `urun app logs`, `urun function logs`, `urun session logs`,
|
|
230
|
+
or `urun log list` for build logs or runtime logs scoped to an app, a function
|
|
230
231
|
within an app, or a session:
|
|
231
232
|
|
|
232
233
|
```bash
|
|
233
|
-
urun list
|
|
234
|
-
urun logs
|
|
235
|
-
urun logs
|
|
236
|
-
urun logs
|
|
237
|
-
urun logs
|
|
234
|
+
urun log list
|
|
235
|
+
urun build logs <build-id>
|
|
236
|
+
urun app logs <app>
|
|
237
|
+
urun function logs <app> <function>
|
|
238
|
+
urun session logs <session>
|
|
238
239
|
```
|
|
239
240
|
|
|
240
241
|
Runtime commands accept `--follow`/`-f` for live output and `--json` for JSON
|
|
241
|
-
(one-shot) or NDJSON (followed) output. Use `urun list
|
|
242
|
+
(one-shot) or NDJSON (followed) output. Use `urun log list` without filters to
|
|
242
243
|
list all accessible logs, or add the same app, function, session, level, text,
|
|
243
|
-
and time filters. `urun tail
|
|
244
|
+
and time filters. `urun log tail` remains available for the legacy follow
|
|
244
245
|
workflow. The current logs API does not filter by environment.
|
|
245
246
|
|
|
246
247
|
## Inspect sessions
|
|
@@ -249,10 +250,10 @@ List live and historical sessions in your org. Newest sessions appear at the
|
|
|
249
250
|
**bottom** of the table so the command works well with `tail`:
|
|
250
251
|
|
|
251
252
|
```bash
|
|
252
|
-
urun list
|
|
253
|
-
urun list
|
|
254
|
-
urun list
|
|
255
|
-
urun list
|
|
253
|
+
urun session list
|
|
254
|
+
urun session list | tail -20
|
|
255
|
+
urun session list --state failed
|
|
256
|
+
urun session list --limit 500
|
|
256
257
|
```
|
|
257
258
|
|
|
258
259
|
Sample output:
|
|
@@ -289,7 +290,7 @@ endpoint, which is in development.
|
|
|
289
290
|
List the compute slices your org currently has provisioned:
|
|
290
291
|
|
|
291
292
|
```bash
|
|
292
|
-
urun list
|
|
293
|
+
urun compute list
|
|
293
294
|
```
|
|
294
295
|
|
|
295
296
|
Sample output:
|
|
@@ -309,8 +310,8 @@ reporting.
|
|
|
309
310
|
|
|
310
311
|
Slices with no provisioned capacity are omitted, so this command answers
|
|
311
312
|
"what is running right now". For the full deployment catalogue
|
|
312
|
-
(including paused / failed / unprovisioned apps) use `urun list
|
|
313
|
-
for historical or in-flight sessions use `urun list
|
|
313
|
+
(including paused / failed / unprovisioned apps) use `urun app list`;
|
|
314
|
+
for historical or in-flight sessions use `urun session list`.
|
|
314
315
|
|
|
315
316
|
Pass `--limit` to control how many rows are fetched (default 100).
|
|
316
317
|
|
|
@@ -320,10 +321,10 @@ endpoint, which is in development.
|
|
|
320
321
|
## Manage apps
|
|
321
322
|
|
|
322
323
|
Manage the lifecycle of a single deployed app. The app is addressed by its
|
|
323
|
-
slug (the name shown under `APP` in `urun list
|
|
324
|
+
slug (the name shown under `APP` in `urun app list`); every operation is
|
|
324
325
|
org-scoped via your API key.
|
|
325
326
|
|
|
326
|
-
Show detailed status for one app (the single-app complement to `list
|
|
327
|
+
Show detailed status for one app (the single-app complement to `app list`):
|
|
327
328
|
|
|
328
329
|
```bash
|
|
329
330
|
urun app status lingbot
|
|
@@ -370,10 +371,21 @@ Enable a disabled app and bring it back online:
|
|
|
370
371
|
urun app enable lingbot-handle
|
|
371
372
|
```
|
|
372
373
|
|
|
374
|
+
If `urun deploy` or `urun dev --attach` reports that a function was paused
|
|
375
|
+
after repeated startup failures, inspect its runtime logs before overriding
|
|
376
|
+
the safety pause. Then explicitly resume every paused function:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
urun app enable rapid-clips --force
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
`--force` may restart a known-crashing function; it does not change the
|
|
383
|
+
platform's automatic pause policy.
|
|
384
|
+
|
|
373
385
|
Stop a queued, starting, or live session:
|
|
374
386
|
|
|
375
387
|
```bash
|
|
376
|
-
urun stop
|
|
388
|
+
urun session stop sess_123 --yes
|
|
377
389
|
```
|
|
378
390
|
|
|
379
391
|
All `app` subcommands accept `--environment` (default `prod`) and `--json`.
|
|
@@ -86,8 +86,8 @@ urun deploy prompt_canary/backend/app.py --name prompt-canary --timeout 900
|
|
|
86
86
|
urun demo prompt-canary --examples-root ~/workspace/urun-examples
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
The positional argument is the **deployed app slug** (as shown by `urun
|
|
90
|
-
|
|
89
|
+
The positional argument is the **deployed app slug** (as shown by `urun app
|
|
90
|
+
list`). Nothing is declared in a manifest — every value is discovered:
|
|
91
91
|
|
|
92
92
|
| value | where it comes from |
|
|
93
93
|
| --- | --- |
|
|
@@ -171,7 +171,7 @@ row instead of rendering one.
|
|
|
171
171
|
List every app deployed in your org and its current status:
|
|
172
172
|
|
|
173
173
|
```bash
|
|
174
|
-
urun list
|
|
174
|
+
urun app list
|
|
175
175
|
```
|
|
176
176
|
|
|
177
177
|
Sample output:
|
|
@@ -204,21 +204,22 @@ endpoint, which is in development.
|
|
|
204
204
|
|
|
205
205
|
## View logs
|
|
206
206
|
|
|
207
|
-
Use `urun
|
|
207
|
+
Use `urun build logs`, `urun app logs`, `urun function logs`, `urun session logs`,
|
|
208
|
+
or `urun log list` for build logs or runtime logs scoped to an app, a function
|
|
208
209
|
within an app, or a session:
|
|
209
210
|
|
|
210
211
|
```bash
|
|
211
|
-
urun list
|
|
212
|
-
urun logs
|
|
213
|
-
urun logs
|
|
214
|
-
urun logs
|
|
215
|
-
urun logs
|
|
212
|
+
urun log list
|
|
213
|
+
urun build logs <build-id>
|
|
214
|
+
urun app logs <app>
|
|
215
|
+
urun function logs <app> <function>
|
|
216
|
+
urun session logs <session>
|
|
216
217
|
```
|
|
217
218
|
|
|
218
219
|
Runtime commands accept `--follow`/`-f` for live output and `--json` for JSON
|
|
219
|
-
(one-shot) or NDJSON (followed) output. Use `urun list
|
|
220
|
+
(one-shot) or NDJSON (followed) output. Use `urun log list` without filters to
|
|
220
221
|
list all accessible logs, or add the same app, function, session, level, text,
|
|
221
|
-
and time filters. `urun tail
|
|
222
|
+
and time filters. `urun log tail` remains available for the legacy follow
|
|
222
223
|
workflow. The current logs API does not filter by environment.
|
|
223
224
|
|
|
224
225
|
## Inspect sessions
|
|
@@ -227,10 +228,10 @@ List live and historical sessions in your org. Newest sessions appear at the
|
|
|
227
228
|
**bottom** of the table so the command works well with `tail`:
|
|
228
229
|
|
|
229
230
|
```bash
|
|
230
|
-
urun list
|
|
231
|
-
urun list
|
|
232
|
-
urun list
|
|
233
|
-
urun list
|
|
231
|
+
urun session list
|
|
232
|
+
urun session list | tail -20
|
|
233
|
+
urun session list --state failed
|
|
234
|
+
urun session list --limit 500
|
|
234
235
|
```
|
|
235
236
|
|
|
236
237
|
Sample output:
|
|
@@ -267,7 +268,7 @@ endpoint, which is in development.
|
|
|
267
268
|
List the compute slices your org currently has provisioned:
|
|
268
269
|
|
|
269
270
|
```bash
|
|
270
|
-
urun list
|
|
271
|
+
urun compute list
|
|
271
272
|
```
|
|
272
273
|
|
|
273
274
|
Sample output:
|
|
@@ -287,8 +288,8 @@ reporting.
|
|
|
287
288
|
|
|
288
289
|
Slices with no provisioned capacity are omitted, so this command answers
|
|
289
290
|
"what is running right now". For the full deployment catalogue
|
|
290
|
-
(including paused / failed / unprovisioned apps) use `urun list
|
|
291
|
-
for historical or in-flight sessions use `urun list
|
|
291
|
+
(including paused / failed / unprovisioned apps) use `urun app list`;
|
|
292
|
+
for historical or in-flight sessions use `urun session list`.
|
|
292
293
|
|
|
293
294
|
Pass `--limit` to control how many rows are fetched (default 100).
|
|
294
295
|
|
|
@@ -298,10 +299,10 @@ endpoint, which is in development.
|
|
|
298
299
|
## Manage apps
|
|
299
300
|
|
|
300
301
|
Manage the lifecycle of a single deployed app. The app is addressed by its
|
|
301
|
-
slug (the name shown under `APP` in `urun list
|
|
302
|
+
slug (the name shown under `APP` in `urun app list`); every operation is
|
|
302
303
|
org-scoped via your API key.
|
|
303
304
|
|
|
304
|
-
Show detailed status for one app (the single-app complement to `list
|
|
305
|
+
Show detailed status for one app (the single-app complement to `app list`):
|
|
305
306
|
|
|
306
307
|
```bash
|
|
307
308
|
urun app status lingbot
|
|
@@ -348,10 +349,21 @@ Enable a disabled app and bring it back online:
|
|
|
348
349
|
urun app enable lingbot-handle
|
|
349
350
|
```
|
|
350
351
|
|
|
352
|
+
If `urun deploy` or `urun dev --attach` reports that a function was paused
|
|
353
|
+
after repeated startup failures, inspect its runtime logs before overriding
|
|
354
|
+
the safety pause. Then explicitly resume every paused function:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
urun app enable rapid-clips --force
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
`--force` may restart a known-crashing function; it does not change the
|
|
361
|
+
platform's automatic pause policy.
|
|
362
|
+
|
|
351
363
|
Stop a queued, starting, or live session:
|
|
352
364
|
|
|
353
365
|
```bash
|
|
354
|
-
urun stop
|
|
366
|
+
urun session stop sess_123 --yes
|
|
355
367
|
```
|
|
356
368
|
|
|
357
369
|
All `app` subcommands accept `--environment` (default `prod`) and `--json`.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Hatch build hook: platform-tag wheels that carry the vendored urun-openai binary.
|
|
2
|
+
|
|
3
|
+
The `urun compat` proxy binary (see ``src/urun/_bin/README.md``) is a native
|
|
4
|
+
executable, so a wheel that ships it must NOT claim ``py3-none-any`` — pip
|
|
5
|
+
would happily install a mac binary on linux. This hook makes the wheel tag
|
|
6
|
+
tell the truth, both ways:
|
|
7
|
+
|
|
8
|
+
- binary PRESENT at ``src/urun/_bin/urun-openai`` → ``pure_python = False``
|
|
9
|
+
and an explicit ``py3-none-<platform>`` tag. NOT ``infer_tag`` — that would
|
|
10
|
+
stamp ``cp3XX-cp3XX-<platform>`` and needlessly bind the (pure-Python) code
|
|
11
|
+
to the building interpreter's minor version; the only platform-specific
|
|
12
|
+
content is the data binary. A present-but-non-executable binary fails the
|
|
13
|
+
build loudly — shipping it would only fail later on user machines.
|
|
14
|
+
- binary ABSENT → nothing changes: the wheel stays pure ``py3-none-any`` and
|
|
15
|
+
ships without the binary (`urun compat` then resolves via its override/PATH
|
|
16
|
+
lanes or fails loud at runtime).
|
|
17
|
+
|
|
18
|
+
The platform component is derived explicitly, never a bare ``linux_<arch>``:
|
|
19
|
+
|
|
20
|
+
- Linux → ``manylinux_<major>_<minor>_<arch>`` from the GLIBC symbol versions
|
|
21
|
+
the VENDORED BINARY ITSELF actually references (``objdump -T``), never from
|
|
22
|
+
``platform.libc_ver()`` (the build machine's installed glibc). PyPI rejects
|
|
23
|
+
bare ``linux_*`` uploads outright, and in the isolated build env
|
|
24
|
+
``packaging.tags.platform_tags()`` can yield bare ``linux_x86_64`` first —
|
|
25
|
+
so the tag is constructed, not inferred.
|
|
26
|
+
|
|
27
|
+
INCIDENT (2026-08-25): tagging by the build machine's installed glibc
|
|
28
|
+
(``platform.libc_ver()`` on the ``ubuntu-24.04`` release runner → glibc
|
|
29
|
+
2.39) produced wheels tagged ``manylinux_2_39_x86_64`` even though the
|
|
30
|
+
actual bun-compiled binary's highest referenced symbol is ``GLIBC_2.17``
|
|
31
|
+
(confirmed via ``objdump -T``) — a decade-wide, entirely incidental gap
|
|
32
|
+
between "what the build runner happened to have installed" and "what the
|
|
33
|
+
binary actually needs". ``manylinux_2_39`` is only installable on glibc
|
|
34
|
+
≥2.39 (Ubuntu 24.04+, roughly 2024 onward), so pip/uv silently rejected the
|
|
35
|
+
platform wheel on every older-but-still-current distro (Ubuntu 20.04/22.04,
|
|
36
|
+
Debian 11/12, RHEL 8/9, ...) and fell back to the binary-less
|
|
37
|
+
``py3-none-any`` wheel with ZERO signal at install time — `uv tool install
|
|
38
|
+
urun-cli` "succeeded" and `urun compat` failed at runtime claiming the
|
|
39
|
+
binary "is not installed". Reading the binary's OWN symbol requirements is
|
|
40
|
+
the only floor that isn't a lie in either direction.
|
|
41
|
+
- everything else (macOS) → the most specific ``packaging.tags`` platform tag
|
|
42
|
+
(e.g. ``macosx_15_0_arm64``).
|
|
43
|
+
|
|
44
|
+
The release workflow builds one wheel per platform with the binary vendored
|
|
45
|
+
(``scripts/vendor_openai_proxy.py --from-npm``) plus one pure wheel + sdist
|
|
46
|
+
without it, and verifies each with ``scripts/verify_wheel.py`` — a
|
|
47
|
+
``py3-none-any`` wheel containing the binary fails the release.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
from __future__ import annotations
|
|
51
|
+
|
|
52
|
+
import os
|
|
53
|
+
import re
|
|
54
|
+
import subprocess
|
|
55
|
+
import sysconfig
|
|
56
|
+
from pathlib import Path
|
|
57
|
+
|
|
58
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
59
|
+
|
|
60
|
+
_GLIBC_VERSION_RE = re.compile(r"\bGLIBC_(\d+)\.(\d+)(?:\.\d+)?\b")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def parse_required_glibc_versions(objdump_dynsym_output: str) -> set[tuple[int, int]]:
|
|
64
|
+
"""``{(major, minor), ...}`` GLIBC symbol versions referenced in ``objdump
|
|
65
|
+
-T`` text — pure string parsing, no filesystem/subprocess access."""
|
|
66
|
+
return {
|
|
67
|
+
(int(m.group(1)), int(m.group(2)))
|
|
68
|
+
for m in _GLIBC_VERSION_RE.finditer(objdump_dynsym_output)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def required_glibc_symbol_versions(binary: Path) -> set[tuple[int, int]]:
|
|
73
|
+
"""The GLIBC_x.y versions ``binary``'s own dynamic symbols reference.
|
|
74
|
+
|
|
75
|
+
Reads the binary directly instead of trusting the BUILD machine's
|
|
76
|
+
installed glibc (``platform.libc_ver()``) — a build machine can have a
|
|
77
|
+
far newer glibc than anything the compiled binary actually links
|
|
78
|
+
against, and tagging by the build machine rather than the binary's real
|
|
79
|
+
floor silently locks the platform wheel out of most real-world Linux
|
|
80
|
+
installs (see the module docstring's INCIDENT)."""
|
|
81
|
+
try:
|
|
82
|
+
result = subprocess.run(
|
|
83
|
+
["objdump", "-T", str(binary)], capture_output=True, text=True, check=False
|
|
84
|
+
)
|
|
85
|
+
except FileNotFoundError as exc:
|
|
86
|
+
raise RuntimeError(
|
|
87
|
+
"objdump (binutils) is not on PATH — required to read the vendored "
|
|
88
|
+
"binary's real glibc floor; refusing to guess one"
|
|
89
|
+
) from exc
|
|
90
|
+
if result.returncode != 0:
|
|
91
|
+
raise RuntimeError(
|
|
92
|
+
f"objdump -T {binary} failed (rc={result.returncode}): {result.stderr.strip()!r} — "
|
|
93
|
+
"cannot verify the binary's real glibc floor; refusing to guess one"
|
|
94
|
+
)
|
|
95
|
+
return parse_required_glibc_versions(result.stdout)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def manylinux_tag(normalized_platform: str, glibc_versions: set[tuple[int, int]]) -> str:
|
|
99
|
+
"""``manylinux_<major>_<minor>_<arch>`` from the binary's OWN required
|
|
100
|
+
GLIBC_x.y symbol versions — loud when none were found (statically linked
|
|
101
|
+
or unparseable; mislabeling in either direction would be a lie)."""
|
|
102
|
+
if not glibc_versions:
|
|
103
|
+
raise RuntimeError(
|
|
104
|
+
"the vendored binary declares no GLIBC_x.y symbol version requirements "
|
|
105
|
+
"(statically linked, or objdump output did not parse) — refusing to guess "
|
|
106
|
+
"a manylinux floor"
|
|
107
|
+
)
|
|
108
|
+
major, minor = max(glibc_versions)
|
|
109
|
+
arch = normalized_platform.removeprefix("linux_")
|
|
110
|
+
if not arch:
|
|
111
|
+
raise RuntimeError(
|
|
112
|
+
f"cannot derive a manylinux tag: no architecture in platform {normalized_platform!r}"
|
|
113
|
+
)
|
|
114
|
+
return f"manylinux_{major}_{minor}_{arch}"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def wheel_platform_tag(binary: Path) -> str:
|
|
118
|
+
"""The platform component for a wheel carrying ``binary`` on THIS machine."""
|
|
119
|
+
normalized = sysconfig.get_platform().replace("-", "_").replace(".", "_")
|
|
120
|
+
if normalized.startswith("linux_"):
|
|
121
|
+
return manylinux_tag(normalized, required_glibc_symbol_versions(binary))
|
|
122
|
+
# macOS (and anything else): packaging's most specific tag, e.g.
|
|
123
|
+
# macosx_15_0_arm64. packaging is a hatchling dependency, always present.
|
|
124
|
+
from packaging.tags import platform_tags
|
|
125
|
+
|
|
126
|
+
tag = next(iter(platform_tags()))
|
|
127
|
+
if tag.startswith("linux_"): # belt & braces: never a bare linux tag
|
|
128
|
+
raise RuntimeError(f"refusing bare {tag!r} — PyPI rejects it")
|
|
129
|
+
return tag
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class VendoredBinaryBuildHook(BuildHookInterface):
|
|
133
|
+
PLUGIN_NAME = "custom"
|
|
134
|
+
|
|
135
|
+
def initialize(self, version: str, build_data: dict) -> None:
|
|
136
|
+
binary = os.path.join(self.root, "src", "urun", "_bin", "urun-openai")
|
|
137
|
+
if not os.path.isfile(binary):
|
|
138
|
+
return # pure wheel, no binary — the honest py3-none-any case
|
|
139
|
+
if not os.access(binary, os.X_OK):
|
|
140
|
+
raise RuntimeError(
|
|
141
|
+
f"vendored binary {binary} exists but is not executable — "
|
|
142
|
+
"re-run scripts/vendor_openai_proxy.py instead of shipping a broken wheel"
|
|
143
|
+
)
|
|
144
|
+
build_data["pure_python"] = False
|
|
145
|
+
build_data["tag"] = f"py3-none-{wheel_platform_tag(Path(binary))}"
|
|
@@ -10,7 +10,17 @@ build-backend = "hatchling.build"
|
|
|
10
10
|
|
|
11
11
|
[project]
|
|
12
12
|
name = "urun-cli"
|
|
13
|
-
|
|
13
|
+
# Cut the paused-function recovery fixes merged after v0.6.0.
|
|
14
|
+
#
|
|
15
|
+
# WHY THIS IS EDITED BY HAND. [tool.semantic_release] below is fully
|
|
16
|
+
# configured -- conventional commit parser, version_toml pointing here, tag
|
|
17
|
+
# format, changelog templates -- but NOTHING invokes it: `grep -rn
|
|
18
|
+
# semantic.release .github/workflows/` matches nothing. release.yaml only
|
|
19
|
+
# READS this value and skips publishing when the matching tag already exists,
|
|
20
|
+
# so every merge remains on the already-published version until this value is
|
|
21
|
+
# advanced. Wiring semantic-release into CI remains separate work; this patch
|
|
22
|
+
# bump is the minimal release unblock for the three post-v0.6.0 fixes.
|
|
23
|
+
version = "0.6.1"
|
|
14
24
|
description = "End-user CLI for deploying apps to urun"
|
|
15
25
|
readme = "README.md"
|
|
16
26
|
requires-python = ">=3.11"
|
|
@@ -28,6 +38,7 @@ classifiers = [
|
|
|
28
38
|
"Programming Language :: Python :: 3.12",
|
|
29
39
|
"Topic :: Software Development :: Build Tools",
|
|
30
40
|
]
|
|
41
|
+
dependencies = []
|
|
31
42
|
|
|
32
43
|
[project.urls]
|
|
33
44
|
Homepage = "https://urun.sh"
|
|
@@ -191,7 +191,7 @@ class ApiClient:
|
|
|
191
191
|
|
|
192
192
|
The server filters out slices with no provisioned GPU units, so the
|
|
193
193
|
listing reflects what is actively running for the org rather than
|
|
194
|
-
the full deployment catalogue (which is ``urun list
|
|
194
|
+
the full deployment catalogue (which is ``urun app list``).
|
|
195
195
|
|
|
196
196
|
``limit`` is passed through as a query param; this method does not
|
|
197
197
|
impose a client-side maximum.
|
|
@@ -517,12 +517,6 @@ class ApiClient:
|
|
|
517
517
|
def list_git_installations(self) -> dict[str, Any]:
|
|
518
518
|
return self._get("/cli/git-installations")
|
|
519
519
|
|
|
520
|
-
def list_marketplace_apps(self, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
521
|
-
return self._get("/cli/marketplace-apps", params)
|
|
522
|
-
|
|
523
|
-
def get_marketplace_app(self, slug: str) -> dict[str, Any]:
|
|
524
|
-
return self._get(f"/cli/marketplace-apps/{urllib.parse.quote(slug, safe='')}")
|
|
525
|
-
|
|
526
520
|
def app_status(self, app: str, environment: str | None = None) -> dict[str, Any]:
|
|
527
521
|
"""Fetch the detailed lifecycle status for a single app.
|
|
528
522
|
|
|
@@ -613,8 +607,25 @@ class ApiClient:
|
|
|
613
607
|
body: dict[str, Any] | None = {"environment": environment} if environment else None
|
|
614
608
|
return self._json("POST", f"/app/{urllib.parse.quote(app, safe='')}/activate", body)
|
|
615
609
|
|
|
610
|
+
def set_function_paused(
|
|
611
|
+
self,
|
|
612
|
+
app: str,
|
|
613
|
+
function_name: str,
|
|
614
|
+
paused: bool,
|
|
615
|
+
environment: str | None = None,
|
|
616
|
+
) -> dict[str, Any]:
|
|
617
|
+
"""Pause or resume one function of an app.
|
|
618
|
+
|
|
619
|
+
Hits ``POST /app/<slug>/pause`` with the function name and explicit
|
|
620
|
+
pause state. The org is derived from the API key.
|
|
621
|
+
"""
|
|
622
|
+
body: dict[str, Any] = {"paused": paused, "function_name": function_name}
|
|
623
|
+
if environment:
|
|
624
|
+
body["environment"] = environment
|
|
625
|
+
return self._json("POST", f"/app/{urllib.parse.quote(app, safe='')}/pause", body)
|
|
626
|
+
|
|
616
627
|
def retire_app(self, app: str, environment: str | None = None) -> dict[str, Any]:
|
|
617
|
-
"""Retire an app through the CLI edge route (backs ``urun delete
|
|
628
|
+
"""Retire an app through the CLI edge route (backs ``urun app delete``).
|
|
618
629
|
|
|
619
630
|
Hits ``DELETE /cli/apps/<slug>`` which calls the org-scoped
|
|
620
631
|
``urun_stage2_retire_app`` lifecycle RPC: the deployment is driven to
|
|
@@ -1106,7 +1117,7 @@ def poll_until_done(
|
|
|
1106
1117
|
"The control plane kept answering, so this is not a poll failure: it "
|
|
1107
1118
|
f"reported '{last_state}' for the whole {timeout:.0f}s budget. If the app "
|
|
1108
1119
|
"is in fact already serving, the build-status document is wedged "
|
|
1109
|
-
"server-side — check `urun logs
|
|
1120
|
+
"server-side — check `urun build logs` for the real build outcome."
|
|
1110
1121
|
)
|
|
1111
1122
|
time.sleep(_poll_sleep_interval(time.time() - poll_started, interval))
|
|
1112
1123
|
|
|
@@ -1143,7 +1154,7 @@ def _poll_streak_error(
|
|
|
1143
1154
|
f"GET /deployment-status/{manifest_hash}: {describe_error(exc)}. "
|
|
1144
1155
|
f"Failing now rather than re-polling a broken endpoint for the rest of the "
|
|
1145
1156
|
f"wait budget; {staleness}. The build itself may still be running "
|
|
1146
|
-
f"server-side — check `urun logs
|
|
1157
|
+
f"server-side — check `urun build logs` for the real outcome."
|
|
1147
1158
|
)
|
|
1148
1159
|
|
|
1149
1160
|
|