openzoo 0.26.0 → 0.28.0

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/proxy.js CHANGED
@@ -268,6 +268,12 @@ async function maybeCacheCorpus(req, bodyBuf, log) {
268
268
  export async function startProxy({ silent = false, requireToken = null, sessionMaxUsd = null, autoTunnel = false } = {}) {
269
269
  const client = new PayClient();
270
270
  const log = silent ? () => {} : (...a) => console.log(...a);
271
+ // ALWAYS-ON. `silent: true` is used by the editor path to keep startup tidy,
272
+ // but it also swallowed the per-request lines and the payment receipts — so the
273
+ // terminal sat blank and there was no way to tell a working setup from an editor
274
+ // quietly answering from its own backend. Traffic and receipts are the whole
275
+ // point of watching this window; they are never silenced.
276
+ const say = (...a) => console.log(...a);
271
277
  let sessionSpent = 0;
272
278
  let tunnelSpent = 0;
273
279
  // Live balance refresh state — the real implementation is assigned in the
@@ -472,7 +478,10 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
472
478
  // carries a model field, not just chat/completions, so /completions,
473
479
  // /responses and future shapes all work. Never silent.
474
480
  let wantsStream = false;
475
- if ((req.url || '').includes('/chat/completions') && req.method === 'POST') servedRequests += 1;
481
+ if ((req.url || '').includes('/chat/completions') && req.method === 'POST') {
482
+ servedRequests += 1;
483
+ say(`\n<- request #${servedRequests} from ${(req.headers['user-agent'] || 'unknown').slice(0, 40)}`);
484
+ }
476
485
  if (rewritablePath(req.method, req.url)) {
477
486
  const rw = await maybeRewriteModel(bodyBuf);
478
487
  if (rw) {
@@ -581,9 +590,9 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
581
590
  }
582
591
  const line = receipt.ok ? receipt.line : `paid retry -> HTTP ${receipt.status}`;
583
592
  // Wherever a running total is the thing to watch, it rides the receipt.
584
- if (requireToken) log(`${line} · session $${sessionSpent.toFixed(6)}`);
585
- else if (viaTunnel) log(`${line} · public-url session $${tunnelSpent.toFixed(6)}`);
586
- else log(line);
593
+ if (requireToken) say(`${line} · session $${sessionSpent.toFixed(6)}`);
594
+ else if (viaTunnel) say(`${line} · public-url session $${tunnelSpent.toFixed(6)}`);
595
+ else say(line);
587
596
  scheduleRefresh(4000); // settlement lands on-chain in a few seconds
588
597
  }
589
598
  // Chat completions come back as one JSON object (settle-before-serve).
package/lib/setup.js CHANGED
@@ -420,30 +420,30 @@ export async function setupEditor(which, target) {
420
420
  // route its own inference takes. Blackholing it in the hosts file is what
421
421
  // leaves the configured base URL as the only way out. System-wide and
422
422
  // needs a password, so it is opt-in and reversible.
423
- // THE BACKEND BLOCK IS NOW OPT-INit was doing more harm than good.
423
+ // THE BACKEND BLOCK IS REQUIRED FOR ROUTING measured, not assumed.
424
424
  //
425
- // Blackholing api2.cursor.sh stopped the editor re-syncing its model list over
426
- // ours, which was real. But that same host serves the editor's OWN catalog and
427
- // auth, so blocking it means the picker cannot populatethe symptom is a
428
- // picker showing only "Auto" and every named model "unavailable". It also
429
- // re-applied itself on every run, so a user who removed the line by hand got it
430
- // straight back and could not tell why.
431
- // Routing does not need it: the editor honours the custom base URL on its own.
432
- if (target0 === 'cursor' && process.argv.includes('--block-backend')) {
425
+ // With api2.cursor.sh reachable the editor answers from its OWN backend and the
426
+ // custom base URL is never used: servedRequests stayed 0 through a whole session.
427
+ // With it blackholed, requests arrive and settletwo Solana payments at
428
+ // 10:38:27Z and 10:38:30Z on the same machine, same config, block on.
429
+ //
430
+ // The cost is that this host also serves the editor's own model catalog, so its
431
+ // picker cannot self-populate. That is fine BECAUSE WE WRITE THE MODELS
432
+ // OURSELVES (availableAPIKeyModels + availableDefaultModels2 above) — the picker
433
+ // is ours, not theirs. If our write fails, the picker collapses to "Auto", and
434
+ // that is the symptom to chase, not the block.
435
+ //
436
+ // --no-block opts out for anyone who would rather keep the vendor catalog.
437
+ if (target0 === 'cursor' && !process.argv.includes('--no-block')) {
433
438
  const { blockBackend, isBlocked } = await import('./hosts.js');
434
439
  const r = blockBackend();
435
- if (r.already) console.log('backend: already blocked (npx openzoo unblock to restore)');
436
- else console.log(`backend: ${isBlocked() ? 'blocked -> 127.0.0.1' : 'NOT blocked'}`);
437
- } else if (target0 === 'cursor') {
438
- const { isBlocked } = await import('./hosts.js');
439
- if (isBlocked()) {
440
- console.log('backend: BLOCKED in /etc/hosts from an earlier run.');
441
- console.log(' That stops the editor loading its own model catalog — if the picker');
442
- console.log(' shows only "Auto", this is why. Undo with: npx openzoo unblock');
443
- }
440
+ if (r.already) console.log('backend: already blocked (required for routing; npx openzoo unblock to undo)');
441
+ else if (isBlocked()) console.log('backend: blocked -> 127.0.0.1 (this is what forces the editor onto the zoo)');
442
+ else console.log('backend: NOT blocked — the editor will keep using its own backend and\n nothing will reach the zoo. Re-run and enter your password.');
444
443
  }
445
444
 
446
445
 
446
+
447
447
  // 3. LAUNCH with that env. Editor resolved platform-agnostically; Cursor
448
448
  // wins when both are installed.
449
449
  // Open the directory you ran this from, or the one you named. The earlier
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openzoo",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
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",