agentglow 0.2.0 → 0.2.2
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.
- package/README.md +17 -0
- package/cli/agentglow.mjs +177 -0
- package/cli/lib/net.mjs +73 -0
- package/cli/lib/server.mjs +128 -0
- package/cli/lib/settings.mjs +192 -0
- package/cli/lib/uv.mjs +139 -0
- package/dist/chunks/{KitScene-BuFtYuhc.js → KitScene-C3SZiKL5.js} +1101 -1045
- package/dist/chunks/{index-DO9SAG-u.js → index--dwzdFRh.js} +1 -1
- package/dist/chunks/{index-DCmhxN8v.js → index-B2PGx_wt.js} +37 -37
- package/dist/chunks/{index-HyfZ0ePz.js → index-BZOG_CQS.js} +110 -110
- package/dist/chunks/{index-Bo5HRf-O.js → index-BfGluv59.js} +69 -69
- package/dist/chunks/{index-tonipLb2.js → index-Bm4te7Ug.js} +1 -1
- package/dist/chunks/{index-e6egU2Q6.js → index-Bqv_wy49.js} +1 -1
- package/dist/chunks/{index-ZT88hgW-.js → index-Bsmr7FwH.js} +1 -1
- package/dist/chunks/{index-BPyTLdiF.js → index-Bw31uayO.js} +33 -33
- package/dist/chunks/{index-Dn6oRasS.js → index-C4F16M9q.js} +117 -117
- package/dist/chunks/{index-jLXx_Wgk.js → index-CRRHsMqy.js} +15 -15
- package/dist/chunks/{index-Cyv7bII1.js → index-CS8eZTr_.js} +1 -1
- package/dist/chunks/{index-D733n3Hf.js → index-CdzGoWrn.js} +1 -1
- package/dist/chunks/{index-XMOz-HBf.js → index-CvDEulcq.js} +1 -1
- package/dist/chunks/{index-D0UvupqM.js → index-DXBfdHew.js} +1 -1
- package/dist/chunks/{index-C42Ihyo1.js → index-DdCs_ye9.js} +222 -222
- package/dist/chunks/{index-C5YqtHnC.js → index-_KrED-np.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/types/world.d.ts +10 -0
- package/package.json +12 -2
package/cli/lib/uv.mjs
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Find (or fetch) uv, the runner that starts the Python `agentglow` server without a Python install.
|
|
2
|
+
// Order: uvx on PATH -> uv on PATH -> cached uv -> download the pinned standalone uv from GitHub (sha256-verified).
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { download } from "./net.mjs";
|
|
9
|
+
|
|
10
|
+
export const UV_VERSION = "0.12.21";
|
|
11
|
+
|
|
12
|
+
/** Release asset for a platform, or null when uv publishes none. `libc` is "gnu" | "musl" (Linux only). */
|
|
13
|
+
export function uvAsset(platform = process.platform, arch = process.arch, libc = detectLibc()) {
|
|
14
|
+
const cpu = { x64: "x86_64", arm64: "aarch64" }[arch];
|
|
15
|
+
if (!cpu) return null;
|
|
16
|
+
if (platform === "darwin") return { name: `uv-${cpu}-apple-darwin`, ext: ".tar.gz" };
|
|
17
|
+
if (platform === "linux") return { name: `uv-${cpu}-unknown-linux-${libc === "musl" ? "musl" : "gnu"}`, ext: ".tar.gz" };
|
|
18
|
+
if (platform === "win32") return { name: `uv-${cpu}-pc-windows-msvc`, ext: ".zip" };
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function uvAssetUrl(asset, version = UV_VERSION) {
|
|
23
|
+
return `https://github.com/astral-sh/uv/releases/download/${version}/${asset.name}${asset.ext}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function detectLibc() {
|
|
27
|
+
if (process.platform !== "linux") return null;
|
|
28
|
+
try {
|
|
29
|
+
const r = process.report?.getReport?.();
|
|
30
|
+
if (r?.header?.glibcVersionRuntime) return "gnu";
|
|
31
|
+
} catch { /* ignore */ }
|
|
32
|
+
try { if (fs.readdirSync("/lib").some((f) => f.startsWith("ld-musl-"))) return "musl"; } catch { /* ignore */ }
|
|
33
|
+
return "gnu";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Per-user cache dir (AGENTGLOW_CACHE_DIR overrides). */
|
|
37
|
+
export function cacheDir(env = process.env, platform = process.platform, home = os.homedir()) {
|
|
38
|
+
if (env.AGENTGLOW_CACHE_DIR) return env.AGENTGLOW_CACHE_DIR;
|
|
39
|
+
if (platform === "darwin") return path.join(home, "Library", "Caches", "agentglow");
|
|
40
|
+
if (platform === "win32") return path.join(env.LOCALAPPDATA || path.join(home, "AppData", "Local"), "agentglow", "Cache");
|
|
41
|
+
return path.join(env.XDG_CACHE_HOME || path.join(home, ".cache"), "agentglow");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const exe = (name) => (process.platform === "win32" ? `${name}.exe` : name);
|
|
45
|
+
|
|
46
|
+
/** First executable `name` on PATH (honours PATHEXT on Windows), or null. */
|
|
47
|
+
export function which(name, env = process.env) {
|
|
48
|
+
const exts = process.platform === "win32" ? (env.PATHEXT || ".EXE;.CMD;.BAT").split(";") : [""];
|
|
49
|
+
for (const dir of (env.PATH || env.Path || "").split(path.delimiter)) {
|
|
50
|
+
if (!dir) continue;
|
|
51
|
+
for (const ext of exts) {
|
|
52
|
+
const p = path.join(dir, name + ext.toLowerCase());
|
|
53
|
+
const P = path.join(dir, name + ext);
|
|
54
|
+
for (const c of new Set([P, p])) {
|
|
55
|
+
try {
|
|
56
|
+
const st = fs.statSync(c);
|
|
57
|
+
if (st.isFile() && (process.platform === "win32" || st.mode & 0o111)) return c;
|
|
58
|
+
} catch { /* next */ }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function cachedUvPath(dir = cacheDir()) {
|
|
66
|
+
return path.join(dir, "uv", UV_VERSION, exe("uv"));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function sha256(file) {
|
|
70
|
+
return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function findFile(dir, name) {
|
|
74
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
75
|
+
const p = path.join(dir, e.name);
|
|
76
|
+
if (e.isFile() && e.name === name) return p;
|
|
77
|
+
if (e.isDirectory()) { const f = findFile(p, name); if (f) return f; }
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function extract(archive, dest) {
|
|
83
|
+
// bsdtar/GNU tar on macOS/Linux; tar.exe (bsdtar, reads zip) on Windows 10+, else PowerShell
|
|
84
|
+
const r = spawnSync("tar", archive.endsWith(".zip") ? ["-xf", archive, "-C", dest] : ["-xzf", archive, "-C", dest], { stdio: "ignore" });
|
|
85
|
+
if (r.status === 0) return;
|
|
86
|
+
if (process.platform === "win32") {
|
|
87
|
+
const ps = spawnSync("powershell.exe", ["-NoProfile", "-Command",
|
|
88
|
+
`Expand-Archive -Force -LiteralPath '${archive}' -DestinationPath '${dest}'`], { stdio: "ignore" });
|
|
89
|
+
if (ps.status === 0) return;
|
|
90
|
+
}
|
|
91
|
+
throw new Error(`could not extract ${archive} (is \`tar\` installed?)`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Download + verify + extract the pinned uv into the cache. Returns its path. */
|
|
95
|
+
export async function downloadUv(dir = cacheDir(), log = () => {}) {
|
|
96
|
+
const asset = uvAsset();
|
|
97
|
+
if (!asset) throw new Error(`no prebuilt uv for ${process.platform}/${process.arch}; install uv: https://docs.astral.sh/uv/`);
|
|
98
|
+
const url = uvAssetUrl(asset);
|
|
99
|
+
const target = cachedUvPath(dir);
|
|
100
|
+
const work = fs.mkdtempSync(path.join(os.tmpdir(), "agentglow-uv-"));
|
|
101
|
+
try {
|
|
102
|
+
log(`Downloading uv ${UV_VERSION} (${asset.name}) ...`);
|
|
103
|
+
const archive = path.join(work, asset.name + asset.ext);
|
|
104
|
+
await download(url, archive);
|
|
105
|
+
const shaFile = path.join(work, "sha256");
|
|
106
|
+
await download(url + ".sha256", shaFile);
|
|
107
|
+
const want = fs.readFileSync(shaFile, "utf8").trim().split(/\s+/)[0].toLowerCase();
|
|
108
|
+
const got = sha256(archive);
|
|
109
|
+
if (!/^[0-9a-f]{64}$/.test(want) || want !== got) throw new Error(`uv checksum mismatch for ${asset.name}: ${got} != ${want}`);
|
|
110
|
+
const out = path.join(work, "x");
|
|
111
|
+
fs.mkdirSync(out);
|
|
112
|
+
extract(archive, out);
|
|
113
|
+
const bin = findFile(out, exe("uv"));
|
|
114
|
+
if (!bin) throw new Error(`uv binary not found in ${asset.name}${asset.ext}`);
|
|
115
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
116
|
+
fs.copyFileSync(bin, target + ".tmp");
|
|
117
|
+
fs.chmodSync(target + ".tmp", 0o755);
|
|
118
|
+
fs.renameSync(target + ".tmp", target);
|
|
119
|
+
return target;
|
|
120
|
+
} finally {
|
|
121
|
+
fs.rmSync(work, { recursive: true, force: true });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The command prefix that runs a PyPI tool: ["uvx"] or [uv, "tool", "run"].
|
|
127
|
+
* Returns { cmd, args, source } where source is "uvx" | "uv" | "cache" | "download".
|
|
128
|
+
*/
|
|
129
|
+
export async function findRunner({ env = process.env, log = () => {} } = {}) {
|
|
130
|
+
const uvx = which("uvx", env);
|
|
131
|
+
if (uvx) return { cmd: uvx, args: [], source: "uvx" };
|
|
132
|
+
const uv = which("uv", env);
|
|
133
|
+
if (uv) return { cmd: uv, args: ["tool", "run"], source: "uv" };
|
|
134
|
+
const dir = cacheDir(env);
|
|
135
|
+
const cached = cachedUvPath(dir);
|
|
136
|
+
if (fs.existsSync(cached)) return { cmd: cached, args: ["tool", "run"], source: "cache" };
|
|
137
|
+
const got = await downloadUv(dir, log);
|
|
138
|
+
return { cmd: got, args: ["tool", "run"], source: "download" };
|
|
139
|
+
}
|