diff --git a/.gitignore b/.gitignore index 30a14ded..df54b9f7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ node_modules/ .claude .pytest_cache/ /dist/ +/emrg/gui/dist/ diff --git a/emrg/gui/package.json b/emrg/gui/package.json index ef7f356b..95cb8af5 100644 --- a/emrg/gui/package.json +++ b/emrg/gui/package.json @@ -43,7 +43,7 @@ "identity": null, "target": [ { - "target": "dmg", + "target": "dir", "arch": [ "arm64", "x64" @@ -55,7 +55,7 @@ "win": { "target": [ { - "target": "nsis", + "target": "dir", "arch": [ "x64" ] @@ -80,4 +80,4 @@ "perMachine": false } } -} +} \ No newline at end of file diff --git a/packaging/assets/icon-256.png b/packaging/assets/icon-256.png new file mode 100644 index 00000000..55902400 Binary files /dev/null and b/packaging/assets/icon-256.png differ diff --git a/packaging/assets/icon-512.png b/packaging/assets/icon-512.png new file mode 100644 index 00000000..bc6179cf Binary files /dev/null and b/packaging/assets/icon-512.png differ diff --git a/packaging/assets/icon.icns b/packaging/assets/icon.icns new file mode 100644 index 00000000..553a3ce3 Binary files /dev/null and b/packaging/assets/icon.icns differ diff --git a/packaging/assets/icon.ico b/packaging/assets/icon.ico new file mode 100644 index 00000000..96af25ae Binary files /dev/null and b/packaging/assets/icon.ico differ diff --git a/packaging/assets/icon.png b/packaging/assets/icon.png new file mode 100644 index 00000000..794c9bca Binary files /dev/null and b/packaging/assets/icon.png differ diff --git a/packaging/build-runtime.sh b/packaging/build-runtime.sh index 691bb85b..34d5334e 100755 --- a/packaging/build-runtime.sh +++ b/packaging/build-runtime.sh @@ -48,12 +48,16 @@ cp -R "$PY_ROOT/." "$DIST/bin/python-dist/" chmod +x emrg emrgd emrg-uninstall ) -# ── 3. source/(只读,排除 gui node_modules R14)── +# ── 3. source/(只读,排除 gui node_modules R14;⚠️ 只含 emrg/ 源码,不含 bin/ —— +# 启动脚本已在 bin/ 顶层,source 里再放一份是冗余(pkg 双份))── echo "==> copying source" (cd "$ROOT" && tar --exclude='emrg/gui/node_modules' --exclude='emrg/gui/dist' \ --exclude='.git' --exclude='dist' --exclude='.venv' \ - -cf - emrg bin | (cd "$DIST/source" && tar -xf -)) + --exclude='emrg/__pycache__' --exclude='emrg/**/__pycache__' --exclude='emrg/**/*.pyc' \ + -cf - emrg | (cd "$DIST/source" && tar -xf -)) touch "$DIST/source/py.typed" +# LICENSE(若存在,否则占位) +if [ -f "$ROOT/LICENSE" ]; then cp "$ROOT/LICENSE" "$DIST/source/LICENSE"; fi # ── 4. lib/(pip --target 全量含传递依赖,R3/R43)── echo "==> installing deps to lib/" diff --git a/packaging/bundle-git-gh.sh b/packaging/bundle-git-gh.sh index f6849fc2..ba84c645 100755 --- a/packaging/bundle-git-gh.sh +++ b/packaging/bundle-git-gh.sh @@ -67,8 +67,25 @@ case "$PLATFORM" in rm -rf "$TMP" ;; darwin|macos|linux) - echo "!! git source build required on $PLATFORM (R59: no official portable binary)" - echo " CI provides the build; local dev should use system git." + # R59:无官方便携二进制 → CI 源码编译。本地开发跳过(用系统 git)。 + if [ "${CI:-}" != "true" ]; then + echo "!! git source build is CI-only (R59). Local dev uses system git." >&2 + echo " Set CI=true to force a source build." >&2 + exit 0 + fi + echo "==> building git from source (R59, ~3-5min)" + GIT_VERSION="${GIT_VERSION:-2.46.0}" + TMP="$(mktemp -d)" + curl -sL "https://github.com/git/git/archive/refs/tags/v${GIT_VERSION}.tar.gz" -o "$TMP/git.tgz" + tar -xzf "$TMP/git.tgz" -C "$TMP" + cd "$TMP/git-${GIT_VERSION}" + make configure >/dev/null 2>&1 || ./configure --prefix="$TMP/prefix" >/dev/null + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)" prefix="$TMP/prefix" install >/dev/null 2>&1 + cp "$TMP/prefix/bin/git" "$RUNTIME/bin/git" + chmod +x "$RUNTIME/bin/git" + # macOS: git 依赖系统库,产物跨版本可移植;Linux: 需静态(musl)——CI 用静态基础镜像 + rm -rf "$TMP" + echo " git built: $("$RUNTIME/bin/git" --version 2>/dev/null || echo 'check failed')" ;; esac diff --git a/packaging/gen-assets.sh b/packaging/gen-assets.sh new file mode 100644 index 00000000..3f489548 --- /dev/null +++ b/packaging/gen-assets.sh @@ -0,0 +1,247 @@ +#!/usr/bin/env bash +# EMRG Phase 4 — generate packaging assets (icons). +# +# Pure-stdlib approach (no PIL/ImageMagick dependency): +# 1. Python stdlib draws a 1024x1024 PNG (EMRG glyph: dark bg + green "E" + circuit node) +# 2. iconutil (macOS) → .icns +# 3. Python stdlib → multi-size .ico (win) +# 4. 512/256 PNG copies (linux) +# +# Output in packaging/assets/: +# icon.png (1024) icon-512.png icon-256.png icon.icns icon.ico +# +# Run from repo root: bash packaging/gen-assets.sh + +set -euo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +OUT="$ROOT/packaging/assets" +mkdir -p "$OUT" + +echo "==> generating 1024x1024 icon.png (pure stdlib)" +python3 - "$OUT/icon.png" <<'PYEOF' +import sys, struct, zlib, math + +path = sys.argv[1] +S = 1024 +# RGBA buffer (transparent bg) +buf = bytearray([0, 0, 0, 0]) * (S * S) + +def put(x, y, r, g, b, a=255): + if 0 <= x < S and 0 <= y < S: + i = (y * S + x) * 4 + buf[i] = r; buf[i+1] = g; buf[i+2] = b; buf[i+3] = a + +def fill_circle(cx, cy, rad, r, g, b, a=255): + # bounding box fill + x0, x1 = max(0, int(cx-rad)), min(S, int(cx+rad)+1) + y0, y1 = max(0, int(cy-rad)), min(S, int(cy+rad)+1) + r2 = rad*rad + for yy in range(y0, y1): + for xx in range(x0, x1): + dx, dy = xx-cx, yy-cy + if dx*dx + dy*dy <= r2: + put(xx, yy, r, g, b, a) + +def fill_rect(x0, y0, x1, y1, r, g, b, a=255): + for yy in range(max(0,y0), min(S,y1)): + for xx in range(max(0,x0), min(S,x1)): + put(xx, yy, r, g, b, a) + +def fill_round_rect(x0, y0, x1, y1, rad, r, g, b, a=255): + fill_rect(x0+rad, y0, x1-rad, y1, r, g, b, a) + fill_rect(x0, y0+rad, x1, y1-rad, r, g, b, a) + fill_circle(x0+rad, y0+rad, rad, r, g, b, a) + fill_circle(x1-rad, y0+rad, rad, r, g, b, a) + fill_circle(x0+rad, y1-rad, rad, r, g, b, a) + fill_circle(x1-rad, y1-rad, rad, r, g, b, a) + +# background: rounded square (EMRG brand: dark navy #0f172a) +fill_round_rect(64, 64, S-64, S-64, 180, 0x0f, 0x17, 0x2a) +# subtle outer ring +for rad in range(460, 480): + fill_circle(S//2, S//2, rad, 0x1e, 0x29, 0x3b, 255) + +# circuit: ring + node (self-evolving motif) +fill_circle(S//2, S//2, 300, 0x10, 0xb9, 0x81, 255) # green ring body +fill_circle(S//2, S//2, 250, 0x0f, 0x17, 0x2a, 255) # punch hole → ring +# 4 orbit nodes +for ang in (0, 90, 180, 270): + ox = S//2 + int(380 * math.cos(math.radians(ang))) + oy = S//2 + int(380 * math.sin(math.radians(ang))) + fill_circle(ox, oy, 40, 0x10, 0xb9, 0x81, 255) + +# "E" glyph (three bars + spine) — simple block letter +bar = 70 +spine_x0, spine_x1 = S//2 - 200, S//2 - 130 +top_y, mid_y, bot_y = S//2 - 200, S//2 - 30, S//2 + 140 +fill_rect(spine_x0, top_y, spine_x1, bot_y+bar, 0xf8, 0xfa, 0xfc) # vertical spine +fill_rect(spine_x0, top_y, S//2 + 200, top_y+bar, 0xf8, 0xfa, 0xfc) # top bar +fill_rect(spine_x0, mid_y, S//2 + 140, mid_y+bar, 0xf8, 0xfa, 0xfc) # middle bar +fill_rect(spine_x0, bot_y, S//2 + 200, bot_y+bar, 0xf8, 0xfa, 0xfc) # bottom bar + +def write_png(path, w, h, rgba): + def chunk(tag, data): + c = struct.pack(">I", len(data)) + tag + data + c += struct.pack(">I", zlib.crc32(tag + data) & 0xffffffff) + return c + raw = b"".join(b"\x00" + bytes(rgba[y*w*4:(y+1)*w*4]) for y in range(h)) + png = b"\x89PNG\r\n\x1a\n" + png += chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 6, 0, 0, 0)) + png += chunk(b"IDAT", zlib.compress(raw, 9)) + png += chunk(b"IEND", b"") + with open(path, "wb") as f: + f.write(png) + +write_png(path, S, S, buf) +print(" wrote", path) +PYEOF + +echo "==> resizing to 512/256 (stdlib scale-down)" +python3 - "$OUT/icon.png" "$OUT" <<'PYEOF' +import sys, zlib, struct + +src, outdir = sys.argv[1], sys.argv[2] + +def read_png(path): + data = open(path, "rb").read() + assert data[:8] == b"\x89PNG\r\n\x1a\n" + pos, w, h, idat = 8, 0, 0, b"" + while pos < len(data): + ln = struct.unpack(">I", data[pos:pos+4])[0] + tag = data[pos+4:pos+8] + chunk = data[pos+8:pos+8+ln] + if tag == b"IHDR": + w, h = struct.unpack(">II", chunk[:8]) + elif tag == b"IDAT": + idat += chunk + pos += 12 + ln + raw = zlib.decompress(idat) + # PNG scanlines each have a leading filter byte (0 for None); strip them + stride0 = w * 4 + 1 + raw = b"".join(raw[y*stride0+1:(y+1)*stride0] for y in range(h)) + return w, h, raw + +w, h, raw = read_png(src) +stride = w * 4 + +def sample(x, y): + i = y * stride + x * 4 + return raw[i], raw[i+1], raw[i+2], raw[i+3] + +def resize(nw, nh): + out = bytearray([0, 0, 0, 0]) * (nw * nh) + for yy in range(nh): + sy = min(int(yy * h / nh), h-1) + for xx in range(nw): + sx = min(int(xx * w / nw), w-1) + i = sy * stride + sx * 4 + r, g, b, a = raw[i], raw[i+1], raw[i+2], raw[i+3] + o = (yy * nw + xx) * 4 + out[o] = r; out[o+1] = g; out[o+2] = b; out[o+3] = a + return bytes(out) + +def write_png(path, nw, nh, rgba): + def chunk(tag, data): + c = struct.pack(">I", len(data)) + tag + data + c += struct.pack(">I", zlib.crc32(tag + data) & 0xffffffff) + return c + raw = b"".join(b"\x00" + rgba[y*nw*4:(y+1)*nw*4] for y in range(nh)) + png = b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", nw, nh, 8, 6, 0, 0, 0)) + chunk(b"IDAT", zlib.compress(raw, 9)) + chunk(b"IEND", b"") + open(path, "wb").write(png) + +for size in (512, 256): + p = f"{outdir}/icon-{size}.png" + write_png(p, size, size, resize(size, size)) + print(" wrote", p) +PYEOF + +echo "==> iconutil → icon.icns (macOS)" +ICONSET="$OUT/icon.iconset" +mkdir -p "$ICONSET" +# iconutil wants specific sizes +for s in 16 32 128 256 512; do + d=$((s*2)) + python3 - "$OUT/icon.png" "$ICONSET/icon_${s}x${s}.png" "$s" <<'PYEOF' +import sys, zlib, struct +src, dst, size = sys.argv[1], sys.argv[2], int(sys.argv[3]) +# reuse resize from above by re-reading +data = open(src, "rb").read(); pos, w, h, idat = 8, 0, 0, b"" +while pos < len(data): + ln = struct.unpack(">I", data[pos:pos+4])[0]; tag = data[pos+4:pos+8]; chunk = data[pos+8:pos+8+ln] + if tag == b"IHDR": w, h = struct.unpack(">II", chunk[:8]) + elif tag == b"IDAT": idat += chunk + pos += 12 + ln +raw = zlib.decompress(idat) +stride0 = w*4 + 1 +raw = b"".join(raw[y*stride0+1:(y+1)*stride0] for y in range(h)) +stride = w*4 +out = bytearray([0,0,0,0])*(size*size) +for yy in range(size): + sy = yy*h//size + for xx in range(size): + sx = min(xx*w//size, w-1) + i = sy*stride + sx*4 + o = (yy*size+xx)*4 + out[o]=raw[i]; out[o+1]=raw[i+1]; out[o+2]=raw[i+2]; out[o+3]=raw[i+3] +def chunk(tag, data): + c = struct.pack(">I", len(data))+tag+data; c += struct.pack(">I", zlib.crc32(tag+data)&0xffffffff); return c +rgba = bytes(out) +raw2 = b"".join(b"\x00"+rgba[y*size*4:(y+1)*size*4] for y in range(size)) +png = b"\x89PNG\r\n\x1a\n"+chunk(b"IHDR", struct.pack(">IIBBBBB", size, size, 8, 6, 0, 0, 0))+chunk(b"IDAT", zlib.compress(raw2,9))+chunk(b"IEND", b"") +open(dst, "wb").write(png) +PYEOF + cp "$ICONSET/icon_${s}x${s}.png" "$ICONSET/icon_${s}x${s}@2x.png" 2>/dev/null || true +done +# icns needs exact 16/32/128/256/512 + @2x +iconutil -c icns "$ICONSET" -o "$OUT/icon.icns" +rm -rf "$ICONSET" +echo " wrote $OUT/icon.icns" + +echo "==> icon.ico (multi-size, win)" +python3 - "$OUT/icon.png" "$OUT/icon.ico" <<'PYEOF' +import sys, zlib, struct +src, dst = sys.argv[1], sys.argv[2] +data = open(src, "rb").read(); pos, w, h, idat = 8, 0, 0, b"" +while pos < len(data): + ln = struct.unpack(">I", data[pos:pos+4])[0]; tag = data[pos+4:pos+8]; chunk = data[pos+8:pos+8+ln] + if tag == b"IHDR": w, h = struct.unpack(">II", chunk[:8]) + elif tag == b"IDAT": idat += chunk + pos += 12 + ln +raw = zlib.decompress(idat) +stride0 = w*4 + 1 +raw = b"".join(raw[y*stride0+1:(y+1)*stride0] for y in range(h)) +stride = w*4 + +def resize(nw, nh): + out = bytearray([0,0,0,0])*(nw*nh) + for yy in range(nh): + sy = min(yy*h//nh, h-1) + for xx in range(nw): + sx = min(xx*w//nw, w-1) + i = sy*stride + sx*4 + o = (yy*nw+xx)*4 + out[o]=raw[i]; out[o+1]=raw[i+1]; out[o+2]=raw[i+2]; out[o+3]=raw[i+3] + return bytes(out) + +def png_bytes(nw, nh, rgba): + def chunk(tag, data): + c = struct.pack(">I", len(data))+tag+data; c += struct.pack(">I", zlib.crc32(tag+data)&0xffffffff); return c + raw2 = b"".join(b"\x00"+rgba[y*nw*4:(y+1)*nw*4] for y in range(nh)) + return b"\x89PNG\r\n\x1a\n"+chunk(b"IHDR", struct.pack(">IIBBBBB", nw, nh, 8, 6, 0, 0, 0))+chunk(b"IDAT", zlib.compress(raw2,9))+chunk(b"IEND", b"") + +# ICO: header + directory + PNG-embedded entries +sizes = [16, 24, 32, 48, 64, 128, 256] +imgs = [(s, png_bytes(s, s, resize(s, s))) for s in sizes] +header = struct.pack(" assets:" +ls -la "$OUT" diff --git a/packaging/make-installer.sh b/packaging/make-installer.sh index 6aa899d9..206db4df 100755 --- a/packaging/make-installer.sh +++ b/packaging/make-installer.sh @@ -6,10 +6,16 @@ # R67: postinstall $HOME 陷阱(提权时取控制台用户真实 HOME) # R105: root 复制后 chown 回用户 # Windows: Inno Setup(R55 免 UAC;R87 {userhome} Inno 6.1+ fallback) +# GUI win-unpacked → install/emrg-gui/(R97) # Linux: AppImage(自解压归 GUI main.js §5)+ tar.gz 兜底(R83d 冒烟用) # # Artifact naming (R103): EMRG--macos-arm64.pkg / EMRG--windows-x64.exe / # EMRG--linux-x86_64.AppImage + .tar.gz +# +# Usage: bash packaging/make-installer.sh [darwin|linux|windows] +# darwin: needs pkgbuild (macOS). GUI from emrg/gui/dist/mac*/EMRG.app +# windows: needs iscc (Inno Setup 6) + GUI win-unpacked from emrg/gui/dist/win-unpacked +# linux: tarball of runtime (AppImage built separately by electron-builder) set -euo pipefail @@ -24,10 +30,54 @@ mkdir -p "$DIST/artifacts" case "$PLATFORM" in darwin|macos) echo "==> macOS pkg (user-level, R54/R104/R105/R67)" - # payload: runtime → 临时目录;postinstall 复制到用户 HOME + # GUI 产物(electron-builder dir 输出,arch 目录 mac-arm64 或 mac-x64) + GUI_APP="$(ls -d "$ROOT"/emrg/gui/dist/mac*/EMRG.app 2>/dev/null | head -1 || true)" + if [ -z "$GUI_APP" ]; then + echo "!! EMRG.app not found (run: cd emrg/gui && npm run dist first)" >&2 + exit 1 + fi PKG_ROOT="$(mktemp -d)" - mkdir -p "$PKG_ROOT/payload/runtime" + mkdir -p "$PKG_ROOT/payload/runtime" "$PKG_ROOT/payload/runtime/emrg-gui" cp -R "$RUNTIME/." "$PKG_ROOT/payload/runtime/" + cp -R "$GUI_APP" "$PKG_ROOT/payload/runtime/emrg-gui/EMRG.app" + # 生成"卸载 EMRG.app"(R30/R31/R102:bash 包装调 emrg-uninstall + 删主 GUI + 提示拖废纸篓) + UNINSTALL_APP="$PKG_ROOT/payload/runtime/emrg-gui/卸载 EMRG.app" + mkdir -p "$UNINSTALL_APP/Contents/MacOS" + cat > "$UNINSTALL_APP/Contents/Info.plist" <<'EOF' + + + + + CFBundleExecutableuninstall + CFBundleIdentifiercom.argszero.emrg.uninstall + CFBundleName卸载 EMRG + CFBundlePackageTypeAPPL + LSMinimumSystemVersion11.0 + + +EOF + cat > "$UNINSTALL_APP/Contents/MacOS/uninstall" <<'EOF' +#!/bin/bash +# 卸载 EMRG(R30/R31/R102)——bash 包装,双击运行 +# 调统一卸载脚本 emrg-uninstall(R58)→ 删主 GUI → 提示拖本 app 进废纸篓 +set +e +USER="$(stat -f "%Su" /dev/console 2>/dev/null || echo "$USER")" +HOME_DIR="$(dscl . -read "/Users/$USER" NFSHomeDirectory 2>/dev/null | awk '{print $2}')" +[ -z "$HOME_DIR" ] && HOME_DIR="$HOME" +UNINST="$HOME_DIR/.emrg/install/bin/emrg-uninstall" +if [ -x "$UNINST" ]; then + # R15:卸载脚本需自设 PYTHONPATH + export PYTHONPATH="$HOME_DIR/.emrg/install/source:$HOME_DIR/.emrg/install/lib" + "$UNINST" 2>&1 +fi +# R102:删主 GUI(未运行时可直接删) +rm -rf "$HOME_DIR/Applications/EMRG.app" 2>/dev/null +osascript -e 'display dialog "EMRG 已卸载。请将「卸载 EMRG」图标拖入废纸篓以完成删除。" buttons {"好"} default button 1' 2>/dev/null || \ + echo "EMRG 已卸载。请将「卸载 EMRG」图标拖入废纸篓。" +exit 0 +EOF + chmod +x "$UNINSTALL_APP/Contents/MacOS/uninstall" + mkdir -p "$PKG_ROOT/scripts" cat > "$PKG_ROOT/scripts/postinstall" <<'EOF' #!/bin/bash # R67: GUI 安装器可能提权($HOME=/var/root)→ 取控制台用户真实 HOME @@ -47,22 +97,90 @@ if [ -d "/tmp/emrg-payload/runtime/emrg-gui/EMRG.app" ]; then cp -R "/tmp/emrg-payload/runtime/emrg-gui/EMRG.app" "$HOME_DIR/Applications/" chown -R "$USER":staff "$HOME_DIR/Applications/EMRG.app" 2>/dev/null || true fi +# ③ 卸载 EMRG.app(R30:pkg 无原生卸载器,放置卸载 app) +if [ -d "/tmp/emrg-payload/runtime/emrg-gui/卸载 EMRG.app" ]; then + cp -R "/tmp/emrg-payload/runtime/emrg-gui/卸载 EMRG.app" "$HOME_DIR/Applications/" + chown -R "$USER":staff "$HOME_DIR/Applications/卸载 EMRG.app" 2>/dev/null || true +fi exit 0 EOF chmod +x "$PKG_ROOT/scripts/postinstall" - cp -R "$PKG_ROOT/payload/runtime" /tmp/emrg-payload 2>/dev/null || cp -R "$PKG_ROOT/payload/runtime" "$PKG_ROOT/payload/runtime" + rm -rf /tmp/emrg-payload + cp -R "$PKG_ROOT/payload/runtime" /tmp/emrg-payload pkgbuild --root "$PKG_ROOT/payload" --scripts "$PKG_ROOT/scripts" \ --identifier "com.argszero.emrg" --version "$VERSION" \ "$DIST/artifacts/EMRG-$VERSION-macos-$(uname -m).pkg" - rm -rf "$PKG_ROOT" + rm -rf "$PKG_ROOT" /tmp/emrg-payload ;; + linux) echo "==> Linux tar.gz (AppImage built by electron-builder in CI)" tar -czf "$DIST/artifacts/EMRG-$VERSION-linux-$(uname -m).tar.gz" -C "$(dirname "$RUNTIME")" runtime ;; + windows|win32|mingw*|msys*) - echo "==> Windows Inno Setup script generated (R55/R87) — build in CI with iscc" + echo "==> Windows Inno Setup (R55/R87/R97)" + ISCC="${ISCC:-iscc}" + if ! command -v "$ISCC" >/dev/null 2>&1; then + echo "!! iscc (Inno Setup 6) not found — set ISCC path or install" >&2 + exit 1 + fi + WIN_UNPACKED="$ROOT/emrg/gui/dist/win-unpacked" + if [ ! -d "$WIN_UNPACKED" ]; then + echo "!! win-unpacked not found (run: cd emrg/gui && npm run dist first)" >&2 + exit 1 + fi + # 组装 Inno payload:runtime + GUI → staging(Inno 安装到 {userhome}\.emrg\install) + STAGE="$(mktemp -d)" + mkdir -p "$STAGE/payload" + cp -R "$RUNTIME/." "$STAGE/payload/" + mkdir -p "$STAGE/payload/emrg-gui" + cp -R "$WIN_UNPACKED" "$STAGE/payload/emrg-gui/EMRG" + cat > "$STAGE/emrg.iss" </dev/null + rm -rf "$STAGE" ;; + *) echo "!! unknown platform $PLATFORM" >&2; exit 1 ;; esac diff --git a/packaging/requirements-linux-aarch64.lock b/packaging/requirements-linux-aarch64.lock new file mode 100644 index 00000000..7d5a1856 --- /dev/null +++ b/packaging/requirements-linux-aarch64.lock @@ -0,0 +1,34 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml --python-version 3.13 --python-platform aarch64-unknown-linux-gnu -o packaging/requirements-linux-aarch64.lock +anyio==4.14.2 + # via httpx +certifi==2026.7.22 + # via + # httpcore + # httpx +h11==0.16.0 + # via httpcore +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via emrg (pyproject.toml) +idna==3.18 + # via + # anyio + # httpx +jinja2==3.1.6 + # via emrg (pyproject.toml) +markdown-it-py==4.2.0 + # via rich +markupsafe==3.0.3 + # via jinja2 +mdurl==0.1.2 + # via markdown-it-py +pygments==2.20.0 + # via rich +pyyaml==6.0.3 + # via emrg (pyproject.toml) +rich==15.0.0 + # via emrg (pyproject.toml) +websockets==17.0.1 + # via emrg (pyproject.toml) diff --git a/packaging/requirements-linux-x86_64.lock b/packaging/requirements-linux-x86_64.lock new file mode 100644 index 00000000..fcf376be --- /dev/null +++ b/packaging/requirements-linux-x86_64.lock @@ -0,0 +1,34 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml --python-version 3.13 --python-platform x86_64-unknown-linux-gnu -o packaging/requirements-linux-x86_64.lock +anyio==4.14.2 + # via httpx +certifi==2026.7.22 + # via + # httpcore + # httpx +h11==0.16.0 + # via httpcore +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via emrg (pyproject.toml) +idna==3.18 + # via + # anyio + # httpx +jinja2==3.1.6 + # via emrg (pyproject.toml) +markdown-it-py==4.2.0 + # via rich +markupsafe==3.0.3 + # via jinja2 +mdurl==0.1.2 + # via markdown-it-py +pygments==2.20.0 + # via rich +pyyaml==6.0.3 + # via emrg (pyproject.toml) +rich==15.0.0 + # via emrg (pyproject.toml) +websockets==17.0.1 + # via emrg (pyproject.toml) diff --git a/packaging/requirements-macos-arm64.lock b/packaging/requirements-macos-arm64.lock new file mode 100644 index 00000000..37cb9fad --- /dev/null +++ b/packaging/requirements-macos-arm64.lock @@ -0,0 +1,34 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml --python-version 3.13 --python-platform aarch64-apple-darwin -o packaging/requirements-macos-arm64.lock +anyio==4.14.2 + # via httpx +certifi==2026.7.22 + # via + # httpcore + # httpx +h11==0.16.0 + # via httpcore +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via emrg (pyproject.toml) +idna==3.18 + # via + # anyio + # httpx +jinja2==3.1.6 + # via emrg (pyproject.toml) +markdown-it-py==4.2.0 + # via rich +markupsafe==3.0.3 + # via jinja2 +mdurl==0.1.2 + # via markdown-it-py +pygments==2.20.0 + # via rich +pyyaml==6.0.3 + # via emrg (pyproject.toml) +rich==15.0.0 + # via emrg (pyproject.toml) +websockets==17.0.1 + # via emrg (pyproject.toml) diff --git a/packaging/requirements-windows-x64.lock b/packaging/requirements-windows-x64.lock new file mode 100644 index 00000000..306a658a --- /dev/null +++ b/packaging/requirements-windows-x64.lock @@ -0,0 +1,34 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml --python-version 3.13 --python-platform x86_64-pc-windows-msvc -o packaging/requirements-windows-x64.lock +anyio==4.14.2 + # via httpx +certifi==2026.7.22 + # via + # httpcore + # httpx +h11==0.16.0 + # via httpcore +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via emrg (pyproject.toml) +idna==3.18 + # via + # anyio + # httpx +jinja2==3.1.6 + # via emrg (pyproject.toml) +markdown-it-py==4.2.0 + # via rich +markupsafe==3.0.3 + # via jinja2 +mdurl==0.1.2 + # via markdown-it-py +pygments==2.20.0 + # via rich +pyyaml==6.0.3 + # via emrg (pyproject.toml) +rich==15.0.0 + # via emrg (pyproject.toml) +websockets==17.0.1 + # via emrg (pyproject.toml)