openzoo 0.50.49 → 0.50.50
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/cursorbackend.js +3 -1
- package/lib/grokcli.js +6 -6
- package/lib/ozSpendChip.js +122 -12
- package/package.json +1 -1
package/lib/cursorbackend.js
CHANGED
|
@@ -1299,7 +1299,9 @@ export function restoreAgentWakeups(log = () => {}) {
|
|
|
1299
1299
|
const ids = Object.keys(map);
|
|
1300
1300
|
const now = Date.now();
|
|
1301
1301
|
ids.forEach((id, i) => {
|
|
1302
|
-
|
|
1302
|
+
// Do not fire during Grok Bot boot. 10 parallel zoo turns + CDP on the
|
|
1303
|
+
// spinner page left the window on a white disc. First tick is +90s.
|
|
1304
|
+
map[id].nextAt = now + 90_000 + i * 4000;
|
|
1303
1305
|
});
|
|
1304
1306
|
if (ids.length) persistWakeups(map);
|
|
1305
1307
|
for (const id of ids) armWakeup(map[id]);
|
package/lib/grokcli.js
CHANGED
|
@@ -110,7 +110,7 @@ const GROK_BOT_BIN = `${APP}/Contents/MacOS/Grok Bot`;
|
|
|
110
110
|
/** pids whose command is the Grok Bot main binary (not grep itself). */
|
|
111
111
|
export function grokBotPids(run = execSync) {
|
|
112
112
|
try {
|
|
113
|
-
return run(`pgrep -f ${JSON.stringify(GROK_BOT_BIN)}`, { encoding: 'utf8' })
|
|
113
|
+
return run(`pgrep -f ${JSON.stringify(GROK_BOT_BIN)}`, { encoding: 'utf8', shell: true })
|
|
114
114
|
.trim().split('\n').map((s) => s.trim()).filter(Boolean);
|
|
115
115
|
} catch {
|
|
116
116
|
return [];
|
|
@@ -296,7 +296,7 @@ export async function runBot(argv = []) {
|
|
|
296
296
|
await new Promise((r) => setTimeout(r, 1500));
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
|
|
299
|
+
const launchGrokBot = () => {
|
|
300
300
|
console.error('openzoo: launching Grok Bot');
|
|
301
301
|
console.error(` CURSOR_API_BASE_URL=${url}`);
|
|
302
302
|
spawn(bin, grokBotChromiumArgs(), {
|
|
@@ -315,14 +315,14 @@ export async function runBot(argv = []) {
|
|
|
315
315
|
SAND_HOST_GATEWAY_NETWORK_TOKEN: 'openzoo',
|
|
316
316
|
},
|
|
317
317
|
}).unref();
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
|
|
318
|
+
};
|
|
319
|
+
if (plan.spawn) launchGrokBot();
|
|
320
|
+
else console.error('openzoo: Grok Bot already hijacked — not spawning another copy');
|
|
321
321
|
|
|
322
322
|
injectSpendChipInBackground({
|
|
323
323
|
port: GROKBOT_CDP_PORT,
|
|
324
324
|
log: (m) => console.error(m),
|
|
325
|
-
delayMs: plan.spawn ?
|
|
325
|
+
delayMs: plan.spawn ? 8000 : 2000,
|
|
326
326
|
});
|
|
327
327
|
|
|
328
328
|
console.error('openzoo: leave this running. ctrl-c stops the backend.');
|
package/lib/ozSpendChip.js
CHANGED
|
@@ -7,9 +7,27 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import net from 'node:net';
|
|
9
9
|
import crypto from 'node:crypto';
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import os from 'node:os';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { spendChipLabel } from './spendProof.js';
|
|
10
14
|
|
|
11
15
|
export const GROKBOT_CDP_PORT = Number(process.env.OZ_GROKBOT_CDP_PORT || 9444);
|
|
12
16
|
|
|
17
|
+
/** Session totals for a floating pill when the open canvas has no footer. */
|
|
18
|
+
export function sessionSpendLabel(home = os.homedir()) {
|
|
19
|
+
try {
|
|
20
|
+
const s = JSON.parse(fs.readFileSync(path.join(home, '.openzoo', 'session.json'), 'utf8'));
|
|
21
|
+
const spent = Number(s.spentUsd || s.spendUsd || 0);
|
|
22
|
+
const would = Number(s.directUsd || 0);
|
|
23
|
+
const saved = Number(s.savedUsd != null ? s.savedUsd : Math.max(0, would - spent));
|
|
24
|
+
if (!(spent > 0.00005)) return '';
|
|
25
|
+
return spendChipLabel({ spent, would, saved, pct: would > 0 ? (100 * saved) / would : 0 });
|
|
26
|
+
} catch {
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
13
31
|
export function grokBotChromiumArgs(port = GROKBOT_CDP_PORT) {
|
|
14
32
|
return [
|
|
15
33
|
'--ignore-certificate-errors',
|
|
@@ -133,9 +151,12 @@ export function spendOnlyText(t) {
|
|
|
133
151
|
}
|
|
134
152
|
|
|
135
153
|
function ozEnsureSpendCss() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
154
|
+
let s = document.getElementById('oz-spend-css');
|
|
155
|
+
if (!s) {
|
|
156
|
+
s = document.createElement('style');
|
|
157
|
+
s.id = 'oz-spend-css';
|
|
158
|
+
(document.head || document.documentElement).appendChild(s);
|
|
159
|
+
}
|
|
139
160
|
s.textContent = [
|
|
140
161
|
'.oz-spend{margin:.55rem 0 0;font-size:12px;color:inherit;opacity:.82;max-width:36em}',
|
|
141
162
|
'.oz-spend>summary{cursor:help;list-style:none;display:inline-flex;align-items:center;gap:.35rem;',
|
|
@@ -144,8 +165,9 @@ function ozEnsureSpendCss() {
|
|
|
144
165
|
'.oz-spend>summary::-webkit-details-marker{display:none}',
|
|
145
166
|
'.oz-spend-body{white-space:pre-wrap;margin:.55rem 0 0;font-size:11px;line-height:1.45;opacity:.88;overflow-wrap:anywhere}',
|
|
146
167
|
'[data-oz-spend-hide]{display:none!important}',
|
|
168
|
+
'button[aria-label="Start voice input"],button[aria-label*="voice input" i],',
|
|
169
|
+
'button[aria-label*="steminvoer" i],button[aria-label^="Microphone"]{display:none!important}',
|
|
147
170
|
].join('');
|
|
148
|
-
(document.head || document.documentElement).appendChild(s);
|
|
149
171
|
}
|
|
150
172
|
|
|
151
173
|
function ozSpendHost(el) {
|
|
@@ -292,6 +314,52 @@ function ozCollapseSpend() {
|
|
|
292
314
|
ozAttachSpendChip(host, split);
|
|
293
315
|
}
|
|
294
316
|
ozHideSpendLeftovers();
|
|
317
|
+
ozEnsureFloatSpend();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function ozEnsureFloatSpend() {
|
|
321
|
+
const label = String(window.__OZ_SESSION_SPEND__ || '').trim();
|
|
322
|
+
const msgPills = document.querySelectorAll('.oz-spend:not(#oz-spend-float)').length;
|
|
323
|
+
let el = document.getElementById('oz-spend-float');
|
|
324
|
+
if (!label || msgPills) {
|
|
325
|
+
if (el) el.remove();
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
ozEnsureSpendCss();
|
|
329
|
+
if (!el) {
|
|
330
|
+
el = document.createElement('details');
|
|
331
|
+
el.id = 'oz-spend-float';
|
|
332
|
+
el.className = 'oz-spend';
|
|
333
|
+
const sum = document.createElement('summary');
|
|
334
|
+
const body = document.createElement('div');
|
|
335
|
+
body.className = 'oz-spend-body';
|
|
336
|
+
body.textContent = 'session spend (this openzoo bot)';
|
|
337
|
+
el.appendChild(sum);
|
|
338
|
+
el.appendChild(body);
|
|
339
|
+
document.body.appendChild(el);
|
|
340
|
+
}
|
|
341
|
+
ozPlaceFloat(el);
|
|
342
|
+
const sum = el.querySelector('summary');
|
|
343
|
+
if (sum) sum.textContent = 'ⓘ ' + label;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function ozPlaceFloat(el) {
|
|
347
|
+
if (!el) return;
|
|
348
|
+
const ta = document.querySelector('textarea, [contenteditable="true"]');
|
|
349
|
+
const box = ta && ta.getBoundingClientRect();
|
|
350
|
+
el.style.position = 'fixed';
|
|
351
|
+
el.style.right = 'auto';
|
|
352
|
+
el.style.zIndex = '2147483646';
|
|
353
|
+
el.style.opacity = '0.95';
|
|
354
|
+
if (box && box.width > 80 && box.top > 48) {
|
|
355
|
+
el.style.left = Math.round(box.left) + 'px';
|
|
356
|
+
el.style.top = Math.round(Math.max(8, box.top - 56)) + 'px';
|
|
357
|
+
el.style.bottom = 'auto';
|
|
358
|
+
} else {
|
|
359
|
+
el.style.left = '96px';
|
|
360
|
+
el.style.bottom = '72px';
|
|
361
|
+
el.style.top = 'auto';
|
|
362
|
+
}
|
|
295
363
|
}
|
|
296
364
|
|
|
297
365
|
function ozWatchSpend() {
|
|
@@ -305,14 +373,27 @@ function ozWatchSpend() {
|
|
|
305
373
|
else document.addEventListener('DOMContentLoaded', start);
|
|
306
374
|
} catch { /* */ }
|
|
307
375
|
setInterval(run, 1500);
|
|
376
|
+
try { window.addEventListener('resize', run); } catch (e) {}
|
|
308
377
|
}
|
|
309
378
|
|
|
310
379
|
export function spendChipSource() {
|
|
311
380
|
return [
|
|
312
381
|
'(function ozSpendChip(){',
|
|
313
382
|
"'use strict';",
|
|
314
|
-
'if (window.__OZ_SPEND_CHIP__ ===
|
|
315
|
-
'
|
|
383
|
+
'if (window.__OZ_SPEND_CHIP__ === 10) {',
|
|
384
|
+
' const el = document.getElementById("oz-spend-float");',
|
|
385
|
+
' const ta = document.querySelector("textarea, [contenteditable=\\"true\\"]");',
|
|
386
|
+
' const box = ta && ta.getBoundingClientRect();',
|
|
387
|
+
' if (el && box && box.width > 80) {',
|
|
388
|
+
' el.style.position = "fixed";',
|
|
389
|
+
' el.style.left = Math.round(box.left) + "px";',
|
|
390
|
+
' el.style.top = Math.round(Math.max(8, box.top - 56)) + "px";',
|
|
391
|
+
' el.style.right = "auto";',
|
|
392
|
+
' el.style.bottom = "auto";',
|
|
393
|
+
' }',
|
|
394
|
+
' return;',
|
|
395
|
+
'}',
|
|
396
|
+
'window.__OZ_SPEND_CHIP__ = 10;',
|
|
316
397
|
chipUsd.toString(),
|
|
317
398
|
labelFromSpendBody.toString(),
|
|
318
399
|
spendLinesOnly.toString(),
|
|
@@ -327,6 +408,8 @@ export function spendChipSource() {
|
|
|
327
408
|
ozPreviousMessageCard.toString(),
|
|
328
409
|
ozAttachSpendChip.toString(),
|
|
329
410
|
ozCollapseSpend.toString(),
|
|
411
|
+
ozEnsureFloatSpend.toString(),
|
|
412
|
+
ozPlaceFloat.toString(),
|
|
330
413
|
ozWatchSpend.toString(),
|
|
331
414
|
'ozWatchSpend();',
|
|
332
415
|
'})();',
|
|
@@ -511,12 +594,24 @@ export async function listCdpPages(port, fetchImpl = fetch) {
|
|
|
511
594
|
return [];
|
|
512
595
|
}
|
|
513
596
|
|
|
514
|
-
async function injectTarget(target, source, connect) {
|
|
597
|
+
async function injectTarget(target, source, connect, { waitForUi = false } = {}) {
|
|
515
598
|
const session = await connect(target.webSocketDebuggerUrl);
|
|
516
599
|
try {
|
|
517
600
|
await session.send('Page.enable').catch(() => {});
|
|
518
601
|
await session.send('Runtime.enable').catch(() => {});
|
|
519
602
|
await session.send('Page.addScriptToEvaluateOnNewDocument', { source }).catch(() => {});
|
|
603
|
+
if (waitForUi) {
|
|
604
|
+
for (let i = 0; i < 32; i += 1) {
|
|
605
|
+
try {
|
|
606
|
+
const r = await session.send('Runtime.evaluate', {
|
|
607
|
+
expression: '!!document.querySelector(\'[class*="sand-"], textarea, [contenteditable="true"]\')',
|
|
608
|
+
returnByValue: true,
|
|
609
|
+
});
|
|
610
|
+
if (r?.result?.value) break;
|
|
611
|
+
} catch { /* still booting */ }
|
|
612
|
+
await new Promise((ok) => setTimeout(ok, 250));
|
|
613
|
+
}
|
|
614
|
+
}
|
|
520
615
|
await session.send('Runtime.evaluate', { expression: source, awaitPromise: false });
|
|
521
616
|
} finally {
|
|
522
617
|
session.close();
|
|
@@ -531,6 +626,7 @@ export async function injectSpendChip({
|
|
|
531
626
|
connect = cdpSession,
|
|
532
627
|
tries = 40,
|
|
533
628
|
delayMs = 400,
|
|
629
|
+
waitForUi = false,
|
|
534
630
|
} = {}) {
|
|
535
631
|
let targets = [];
|
|
536
632
|
for (let i = 0; i < Math.max(1, tries); i += 1) {
|
|
@@ -542,10 +638,12 @@ export async function injectSpendChip({
|
|
|
542
638
|
log(`openzoo: spend chip CDP :${port} has no pages yet`);
|
|
543
639
|
return { ok: false, injected: 0 };
|
|
544
640
|
}
|
|
641
|
+
const label = sessionSpendLabel();
|
|
642
|
+
const src = `window.__OZ_SESSION_SPEND__=${JSON.stringify(label)};\n${source}`;
|
|
545
643
|
let injected = 0;
|
|
546
644
|
for (const t of targets) {
|
|
547
645
|
try {
|
|
548
|
-
await injectTarget(t,
|
|
646
|
+
await injectTarget(t, src, connect, { waitForUi });
|
|
549
647
|
injected += 1;
|
|
550
648
|
} catch (e) {
|
|
551
649
|
log(`openzoo: spend chip inject ${e.message}`);
|
|
@@ -555,11 +653,23 @@ export async function injectSpendChip({
|
|
|
555
653
|
return { ok: injected > 0, injected };
|
|
556
654
|
}
|
|
557
655
|
|
|
558
|
-
/**
|
|
656
|
+
/** One CDP attach, then drop the debugger. A loop here pauses the renderer
|
|
657
|
+
* so the composer accepts a keystroke and then dies. Reloads pick the chip
|
|
658
|
+
* up via Page.addScriptToEvaluateOnNewDocument from that single inject. */
|
|
559
659
|
export function injectSpendChipInBackground(opts = {}) {
|
|
560
660
|
const log = opts.log || ((m) => console.error(m));
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
661
|
+
const wait = Math.max(0, Number(opts.delayMs) || 400);
|
|
662
|
+
setTimeout(() => {
|
|
663
|
+
injectSpendChip({
|
|
664
|
+
tries: 24,
|
|
665
|
+
delayMs: 400,
|
|
666
|
+
waitForUi: true,
|
|
667
|
+
...opts,
|
|
668
|
+
log,
|
|
669
|
+
connect: (ws) => cdpSession(ws, { timeoutMs: 2500 }),
|
|
670
|
+
}).catch((e) => {
|
|
671
|
+
log(`openzoo: spend chip inject failed ${e.message}`);
|
|
672
|
+
});
|
|
673
|
+
}, wait);
|
|
564
674
|
}
|
|
565
675
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.50",
|
|
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",
|