openzoo 0.50.19 → 0.50.21
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/bin/openzoo.js +7 -0
- package/lib/cursorapi.js +78 -3
- package/lib/cursorbackend.js +1180 -58
- package/lib/grokcli.js +106 -0
- package/package.json +1 -1
package/lib/grokcli.js
CHANGED
|
@@ -98,6 +98,112 @@ ${body}
|
|
|
98
98
|
`;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* `openzoo bot` — Grok Bot.app on the zoo, no sudo, no /etc/hosts.
|
|
103
|
+
*
|
|
104
|
+
* CURSOR_API_BASE_URL (and SAND_BACKEND_URL) are what the Electron MAIN
|
|
105
|
+
* process actually reads. Chromium --host-resolver-rules do not. Measured:
|
|
106
|
+
* a bare `127.0.0.1:443` is HTTP and logs ERR_SSL_HTTP_REQUEST; the URL
|
|
107
|
+
* must be https://127.0.0.1:8443. The TLS warning on launch is Node
|
|
108
|
+
* complaining about NODE_TLS_REJECT_UNAUTHORIZED=0 — expected, the cert
|
|
109
|
+
* is ours and self-signed.
|
|
110
|
+
*
|
|
111
|
+
* We bind 8443 ourselves (unprivileged). :443 is the old root takeover and
|
|
112
|
+
* stubs oauth if it is the unpatched npx copy — do not point the app there.
|
|
113
|
+
*/
|
|
114
|
+
export async function runBot(argv = []) {
|
|
115
|
+
const port = 8443;
|
|
116
|
+
const url = `https://127.0.0.1:${port}`;
|
|
117
|
+
const bin = `${APP}/Contents/MacOS/Grok Bot`;
|
|
118
|
+
if (!existsSync(bin)) {
|
|
119
|
+
console.error('openzoo: Grok Bot.app not found at', APP);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const proxyBase = `http://localhost:${config.port}/v1`;
|
|
124
|
+
let up = false;
|
|
125
|
+
try { up = (await fetch(`${proxyBase}/models`, { signal: AbortSignal.timeout(2000) })).ok; } catch { up = false; }
|
|
126
|
+
if (!up) {
|
|
127
|
+
console.error('openzoo: starting proxy on', proxyBase);
|
|
128
|
+
const { startProxy } = await import('./proxy.js');
|
|
129
|
+
await startProxy({ silent: true, autoTunnel: process.env.OPENZOO_NO_TUNNEL === '1' ? false : true });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
process.env.OPENZOO_BYOK = '1';
|
|
133
|
+
const sniff = argv.includes('--sniff') || argv.includes('--passthru');
|
|
134
|
+
if (sniff) {
|
|
135
|
+
// REAL pod, we only sit in the middle. EnsureSandBox is rewritten so
|
|
136
|
+
// /api/sendPrompt and getAgentTranscriptTail land here, then we proxy
|
|
137
|
+
// them to cursorvm and dump the live JSON. That is the comparison
|
|
138
|
+
// surface — hijack guesses have been wrong twice.
|
|
139
|
+
delete process.env.OZ_HIJACK_POD;
|
|
140
|
+
process.env.OPENZOO_PASSTHRU = '1';
|
|
141
|
+
process.env.OPENZOO_SNIFF = '1';
|
|
142
|
+
process.env.OZ_SNIFF_SELF = url;
|
|
143
|
+
} else {
|
|
144
|
+
// Do NOT hand Grok Bot a real cursorvm pod — inference then never leaves
|
|
145
|
+
// Anysphere (measured: EnsureSandBox -> REAL api2, then StreamUnifiedChat
|
|
146
|
+
// never arrives). Point the sandbox URLs at THIS aiserver; StreamUnifiedChat
|
|
147
|
+
// is answered from :8402 (x402).
|
|
148
|
+
process.env.OZ_HIJACK_POD = JSON.stringify({
|
|
149
|
+
region: 'local',
|
|
150
|
+
accountId: 'openzoo',
|
|
151
|
+
podId: 'openzoo-local',
|
|
152
|
+
token: 'openzoo',
|
|
153
|
+
agent: url,
|
|
154
|
+
vnc: url,
|
|
155
|
+
p1340: url,
|
|
156
|
+
p6081: url,
|
|
157
|
+
});
|
|
158
|
+
process.env.OZ_SNIFF_SELF = url;
|
|
159
|
+
}
|
|
160
|
+
const { startCursorBackend } = await import('./cursorbackend.js');
|
|
161
|
+
const models = [
|
|
162
|
+
'gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-4.1', 'gpt-4.1-mini', 'gpt-3.5-turbo',
|
|
163
|
+
].map((n) => ({ name: n, label: n }));
|
|
164
|
+
const log = (m) => console.error(' backend:', m);
|
|
165
|
+
try {
|
|
166
|
+
startCursorBackend({ port, models, log });
|
|
167
|
+
} catch (e) {
|
|
168
|
+
console.error('openzoo: 8443 already bound — reusing it (', e.message, ')');
|
|
169
|
+
}
|
|
170
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
171
|
+
console.error(`openzoo: aiserver on ${url}`);
|
|
172
|
+
console.error(' oauth + /sand-box creds -> real api2');
|
|
173
|
+
if (sniff) {
|
|
174
|
+
console.error(' SNIFF: real EnsureSandBox, /api/* proxied, dump ~/.openzoo/grokbot-sniff.jsonl');
|
|
175
|
+
console.error(' send a message in Grok Bot — it should paint for real');
|
|
176
|
+
} else {
|
|
177
|
+
console.error(' EnsureSandBox HIJACKED here; StreamUnifiedChat -> :8402 (x402)');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
try { execSync('osascript -e \'tell application "Grok Bot" to quit\'', { stdio: 'ignore' }); } catch { /* ok */ }
|
|
181
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
182
|
+
|
|
183
|
+
console.error('openzoo: launching Grok Bot');
|
|
184
|
+
console.error(` CURSOR_API_BASE_URL=${url}`);
|
|
185
|
+
spawn(bin, ['--ignore-certificate-errors'], {
|
|
186
|
+
stdio: 'ignore',
|
|
187
|
+
detached: true,
|
|
188
|
+
env: {
|
|
189
|
+
...process.env,
|
|
190
|
+
NODE_TLS_REJECT_UNAUTHORIZED: '0',
|
|
191
|
+
CURSOR_API_BASE_URL: url,
|
|
192
|
+
SAND_BACKEND_URL: url,
|
|
193
|
+
// Helper daemon (local-exec-daemon/main.cjs) uses Node fetch, not Chromium.
|
|
194
|
+
// Without these it dials the cached cursorvm 1337 URL / dies on our
|
|
195
|
+
// self-signed cert and GET /local-exec/requests never arrives.
|
|
196
|
+
SAND_HOST_GATEWAY_URL: url,
|
|
197
|
+
SAND_HOST_GATEWAY_TOKEN: 'openzoo',
|
|
198
|
+
SAND_HOST_GATEWAY_NETWORK_TOKEN: 'openzoo',
|
|
199
|
+
},
|
|
200
|
+
}).unref();
|
|
201
|
+
|
|
202
|
+
console.error('openzoo: leave this running. ctrl-c stops the backend.');
|
|
203
|
+
if (argv.includes('--once')) return;
|
|
204
|
+
await new Promise(() => {});
|
|
205
|
+
}
|
|
206
|
+
|
|
101
207
|
export async function setupGrokBot(argv = []) {
|
|
102
208
|
const base = `http://localhost:${config.port}/v1`;
|
|
103
209
|
const launch = !argv.includes('--no-launch');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.21",
|
|
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",
|