openzoo 0.48.0 → 0.48.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/lib/boxes.js +22 -6
- package/lib/grokui.mjs +13 -2
- package/package.json +1 -1
package/lib/boxes.js
CHANGED
|
@@ -36,8 +36,15 @@ const CPU_FLAVORS = ['cpu3c', 'cpu3g', 'cpu5c'];
|
|
|
36
36
|
// on musl they fail to build because the entrypoint has no toolchain, which is
|
|
37
37
|
// why alpine boxes sat at 404 forever. Debian-slim runs the shim as published,
|
|
38
38
|
// and its apt has a real sshd.
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
// Everything the box runs is ALREADY IN THE IMAGE: the shim, its node_modules,
|
|
40
|
+
// grokui, and sshd. Boxes used to apt-get and `npx openzoo` at boot, which put
|
|
41
|
+
// a package fetch on the critical path from RunPod egress IPs — and those get
|
|
42
|
+
// rate limited. A 429 from raw.githubusercontent arrives as a FILE whose
|
|
43
|
+
// contents are the text "429: Too Many Requests", so node ran it and failed in
|
|
44
|
+
// a way that read as an app bug rather than a download bug.
|
|
45
|
+
// Still glibc, never musl: @solana's native deps don't build on the box.
|
|
46
|
+
const BOX_IMAGE = process.env.OPENZOO_BOX_IMAGE || 'jrsdunn123/openzoo-box:latest';
|
|
47
|
+
const BOX_PORTS = ['8402/http', '4173/http', '1337/http', '6080/http', '1340/http', '6081/http', '22/tcp'];
|
|
41
48
|
const TTL_MAX_HOURS = 90 * 24;
|
|
42
49
|
|
|
43
50
|
/**
|
|
@@ -50,18 +57,27 @@ const TTL_MAX_HOURS = 90 * 24;
|
|
|
50
57
|
* host keys, and run sshd in the foreground of the background. Passwordless
|
|
51
58
|
* root login is NOT enabled — key-only.
|
|
52
59
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
60
|
+
* NOTHING IS FETCHED AT BOOT. sshd, the shim and grokui are baked into
|
|
61
|
+
* BOX_IMAGE by box.Dockerfile; this only copies /opt into the volume RunPod
|
|
62
|
+
* mounts over /workspace and starts things. readyBox() still polls /v1/models
|
|
63
|
+
* rather than assuming a timing.
|
|
55
64
|
*/
|
|
56
65
|
const ENTRYPOINT = [
|
|
57
66
|
'bash', '-lc',
|
|
58
67
|
'set +e; mkdir -p /workspace /root/.openzoo /var/log/openzoo /run/sshd /root/.ssh; '
|
|
59
68
|
+ 'if [ -n "$OPENZOO_WALLET_JSON" ]; then printf %s "$OPENZOO_WALLET_JSON" > /root/.openzoo/wallet.json; chmod 600 /root/.openzoo/wallet.json; fi; '
|
|
60
|
-
+ 'export DEBIAN_FRONTEND=noninteractive; apt-get update >/dev/null 2>&1; apt-get install -y --no-install-recommends openssh-server git ca-certificates >/dev/null 2>&1; '
|
|
61
69
|
// RunPod hands the operator pubkey in one of these — accept whichever is set
|
|
62
70
|
+ 'for K in "$PUBLIC_KEY" "$SSH_PUBLIC_KEY"; do [ -n "$K" ] && echo "$K" >> /root/.ssh/authorized_keys; done; chmod 600 /root/.ssh/authorized_keys 2>/dev/null; '
|
|
63
71
|
+ 'ssh-keygen -A >/dev/null 2>&1; sed -i "s/^#\\?PermitRootLogin.*/PermitRootLogin prohibit-password/" /etc/ssh/sshd_config 2>/dev/null; /usr/sbin/sshd -e >/var/log/openzoo/sshd.log 2>&1 & '
|
|
64
|
-
|
|
72
|
+
// RUN FROM /opt, never from /workspace. Staging the app onto the volume and
|
|
73
|
+
// gating on `[ ! -f .../bin/openzoo.js ]` is a trap: one interrupted copy
|
|
74
|
+
// leaves that file behind, every later boot skips the copy, and the box
|
|
75
|
+
// crash-loops on a half-copied node_modules forever (seen in production as
|
|
76
|
+
// "Cannot find module .../viem/accounts" every 15s, which also cost the pod
|
|
77
|
+
// its HTTP port mappings). The app is read-only at runtime; mutable state
|
|
78
|
+
// lives in /root/.openzoo.
|
|
79
|
+
+ 'until OPENZOO_BIND=0.0.0.0 node /opt/openzoo/bin/openzoo.js >> /var/log/openzoo/proxy.log 2>&1; do echo "proxy exited, restarting" >> /var/log/openzoo/proxy.log; sleep 2; done & '
|
|
80
|
+
+ 'until OZ_GROKUI_BIND=0.0.0.0 OZ_GROKUI_PORT=4173 node /opt/grokui/grokui.mjs >> /var/log/openzoo/grokui.log 2>&1; do echo "grokui exited, restarting" >> /var/log/openzoo/grokui.log; sleep 2; done & '
|
|
65
81
|
// the capture agent answers the ports Grok Bot expects a Cursor sandbox on,
|
|
66
82
|
// logging the protocol we do not yet speak (see lib/podagent.mjs)
|
|
67
83
|
+ 'if [ -n "$OZ_PODAGENT_B64" ]; then printf %s "$OZ_PODAGENT_B64" | base64 -d > /opt/podagent.mjs; node /opt/podagent.mjs > /var/log/openzoo/agent.log 2>&1 & fi; '
|
package/lib/grokui.mjs
CHANGED
|
@@ -14,6 +14,12 @@ import path from 'node:path';
|
|
|
14
14
|
import { brain, brainStream, PROXY } from './podagent.mjs';
|
|
15
15
|
|
|
16
16
|
const PORT = Number(process.env.OZ_GROKUI_PORT || 4173);
|
|
17
|
+
// BIND HOST. Default 127.0.0.1 so the desktop app never exposes a shell-capable
|
|
18
|
+
// UI to the LAN. A container MUST override it: binding the container's loopback
|
|
19
|
+
// makes `docker run -p 4173:4173` refuse the connection, because the published
|
|
20
|
+
// port forwards to the container's external interface, which nothing is on.
|
|
21
|
+
// Mirrors OPENZOO_BIND in lib/proxy.js — same reasoning, same default.
|
|
22
|
+
const BIND = process.env.OZ_GROKUI_BIND || process.env.OPENZOO_BIND || '127.0.0.1';
|
|
17
23
|
const STORE_DIR = path.join(homedir(), '.openzoo');
|
|
18
24
|
const STORE_FILE = path.join(STORE_DIR, 'grokui-threads.json');
|
|
19
25
|
|
|
@@ -368,7 +374,12 @@ function parseRun(reply) {
|
|
|
368
374
|
// several such calls were dropped. Same failure as the old /^RUN:/ anchor,
|
|
369
375
|
// different shape: a silently discarded directive reads to the model as a
|
|
370
376
|
// tool that does nothing, and it fabricates rather than reporting failure.
|
|
371
|
-
|
|
377
|
+
// The separator is NOT always an ASCII pipe. DeepSeek's real special tokens
|
|
378
|
+
// use U+FF5C FULLWIDTH VERTICAL LINE (|) — matching only `|` parsed the
|
|
379
|
+
// pretty-printed form in tests while missing what the model actually emits,
|
|
380
|
+
// which is exactly how this survived one round of "fixed".
|
|
381
|
+
const SEP = '[||\\s]*';
|
|
382
|
+
const dsml = new RegExp(`<${SEP}DSML[^>]*\\bparameter\\b[^>]*name="command"[^>]*>([\\s\\S]*?)<\\/${SEP}DSML`, 'i').exec(reply);
|
|
372
383
|
if (dsml) return sanitizeRunCommand(dsml[1]);
|
|
373
384
|
|
|
374
385
|
const m = /^[ \t>*-]*RUN:[ \t]*([\s\S]+)/m.exec(reply);
|
|
@@ -1514,4 +1525,4 @@ const server = http.createServer((req, res) => {
|
|
|
1514
1525
|
res.end(APP_HTML);
|
|
1515
1526
|
});
|
|
1516
1527
|
|
|
1517
|
-
server.listen(PORT,
|
|
1528
|
+
server.listen(PORT, BIND, () => console.log(`[grokui] http://${BIND === '0.0.0.0' ? 'localhost' : BIND}:${PORT}`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.48.
|
|
3
|
+
"version": "0.48.2",
|
|
4
4
|
"description": "Local x402-paying proxy + MCP server for openzoo.fun — point any OpenAI-compatible harness (Cursor, Claude Code, aider, SDKs) at localhost and it pays per call from a local burner wallet. Solana and Base rails live; Robinhood experimental.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|