ruvector 0.2.6 → 0.2.8

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/cli.js CHANGED
@@ -115,6 +115,76 @@ function loadGnn() {
115
115
  }
116
116
  }
117
117
 
118
+ // ── Proxy-aware fetch wrapper ───────────────────────────────────────────────
119
+ // Detects HTTP_PROXY / HTTPS_PROXY / ALL_PROXY env vars and routes traffic
120
+ // through the proxy when configured. Falls back to native fetch() when no
121
+ // proxy is set or the target matches NO_PROXY.
122
+ let _proxyDispatcherSet = false;
123
+
124
+ function getProxyUrl(targetUrl) {
125
+ const NO_PROXY = process.env.NO_PROXY || process.env.no_proxy || '';
126
+ if (NO_PROXY === '*') return null;
127
+ if (NO_PROXY) {
128
+ try {
129
+ const host = new URL(targetUrl).hostname.toLowerCase();
130
+ const patterns = NO_PROXY.split(',').map(p => p.trim().toLowerCase());
131
+ for (const p of patterns) {
132
+ if (!p) continue;
133
+ if (host === p || host.endsWith(p.startsWith('.') ? p : '.' + p)) return null;
134
+ }
135
+ } catch {}
136
+ }
137
+ return process.env.HTTPS_PROXY || process.env.https_proxy
138
+ || process.env.HTTP_PROXY || process.env.http_proxy
139
+ || process.env.ALL_PROXY || process.env.all_proxy
140
+ || null;
141
+ }
142
+
143
+ async function proxyFetch(url, opts) {
144
+ const target = typeof url === 'string' ? url : url.toString();
145
+ const proxy = getProxyUrl(target);
146
+ if (!proxy) return fetch(url, opts);
147
+
148
+ // Try undici ProxyAgent (bundled in Node 18+)
149
+ if (!_proxyDispatcherSet) {
150
+ try {
151
+ const undici = require('undici');
152
+ if (undici.ProxyAgent && undici.setGlobalDispatcher) {
153
+ undici.setGlobalDispatcher(new undici.ProxyAgent(proxy));
154
+ _proxyDispatcherSet = true;
155
+ }
156
+ } catch {}
157
+ }
158
+ if (_proxyDispatcherSet) return fetch(url, opts);
159
+
160
+ // Fallback: shell out to curl (which natively respects proxy env vars)
161
+ const { execFileSync } = require('child_process');
162
+ const args = ['-sS', '-L', '--max-time', '30'];
163
+ if (opts && opts.method) { args.push('-X', opts.method); }
164
+ if (opts && opts.headers) {
165
+ for (const [k, v] of Object.entries(opts.headers)) {
166
+ args.push('-H', `${k}: ${v}`);
167
+ }
168
+ }
169
+ if (opts && opts.body) { args.push('-d', typeof opts.body === 'string' ? opts.body : JSON.stringify(opts.body)); }
170
+ args.push(target);
171
+ try {
172
+ const stdout = execFileSync('curl', args, { encoding: 'utf8', timeout: 35000 });
173
+ const body = stdout.trim();
174
+ return {
175
+ ok: true,
176
+ status: 200,
177
+ statusText: 'OK',
178
+ text: async () => body,
179
+ json: async () => JSON.parse(body),
180
+ headers: new Map(),
181
+ };
182
+ } catch (e) {
183
+ const msg = e.stderr ? e.stderr.toString().trim() : e.message;
184
+ throw new Error(`Proxy curl failed: ${msg}`);
185
+ }
186
+ }
187
+
118
188
  // Lazy load Attention (optional - loaded on first use, not at startup)
119
189
  let _attentionModule = undefined;
120
190
  let DotProductAttention, MultiHeadAttention, HyperbolicAttention, FlashAttention, LinearAttention, MoEAttention;
@@ -7250,7 +7320,7 @@ async function getRvfManifest(opts = {}) {
7250
7320
 
7251
7321
  // Try GCS
7252
7322
  try {
7253
- const resp = await fetch(GCS_MANIFEST_URL);
7323
+ const resp = await proxyFetch(GCS_MANIFEST_URL, { signal: AbortSignal.timeout(15000) });
7254
7324
  if (resp.ok) {
7255
7325
  const manifest = await resp.json();
7256
7326
  fs.mkdirSync(cacheDir, { recursive: true });
@@ -7877,11 +7947,12 @@ async function brainFetch(config, endpoint, opts = {}) {
7877
7947
  const fetchOpts = { headers: brainHeaders(config), signal: AbortSignal.timeout(30000) };
7878
7948
  if (opts.method) fetchOpts.method = opts.method;
7879
7949
  if (opts.body) { fetchOpts.method = opts.method || 'POST'; fetchOpts.body = JSON.stringify(opts.body); }
7880
- const resp = await fetch(url.toString(), fetchOpts);
7950
+ const resp = await proxyFetch(url.toString(), fetchOpts);
7881
7951
  if (!resp.ok) {
7882
7952
  const errText = await resp.text().catch(() => resp.statusText);
7883
7953
  throw new Error(`${resp.status} ${errText}`);
7884
7954
  }
7955
+ if (resp.status === 204 || resp.headers.get('content-length') === '0') return {};
7885
7956
  return resp.json();
7886
7957
  }
7887
7958
 
@@ -7927,10 +7998,12 @@ brainCmd.command('share <title>')
7927
7998
  .option('--code <snippet>', 'Code snippet')
7928
7999
  .option('--url <url>', 'Brain server URL')
7929
8000
  .option('--key <key>', 'Pi key')
8001
+ .option('--json', 'Output as JSON')
7930
8002
  .action(async (title, opts) => {
7931
8003
  const config = getBrainConfig(opts);
7932
8004
  try {
7933
8005
  const result = await brainFetch(config, '/v1/memories', { body: { title, content: opts.content || title, category: opts.category, tags: opts.tags ? opts.tags.split(',').map(t => t.trim()) : [], code_snippet: opts.code } });
8006
+ if (opts.json || !process.stdout.isTTY) { console.log(JSON.stringify(result, null, 2)); return; }
7934
8007
  console.log(chalk.green(`Shared: ${result.id || 'OK'}`));
7935
8008
  } catch (e) { console.error(chalk.red(`Error: ${e.message}`)); process.exit(1); }
7936
8009
  });
@@ -7957,10 +8030,12 @@ brainCmd.command('vote <id> <direction>')
7957
8030
  .description('Quality vote on a memory (up or down)')
7958
8031
  .option('--url <url>', 'Brain server URL')
7959
8032
  .option('--key <key>', 'Pi key')
8033
+ .option('--json', 'Output as JSON')
7960
8034
  .action(async (id, direction, opts) => {
7961
8035
  const config = getBrainConfig(opts);
7962
8036
  try {
7963
- await brainFetch(config, `/v1/memories/${id}/vote`, { body: { direction } });
8037
+ const result = await brainFetch(config, `/v1/memories/${id}/vote`, { body: { direction } });
8038
+ if (opts.json || !process.stdout.isTTY) { console.log(JSON.stringify(result, null, 2)); return; }
7964
8039
  console.log(chalk.green(`Voted ${direction} on ${id}`));
7965
8040
  } catch (e) { console.error(chalk.red(`Error: ${e.message}`)); process.exit(1); }
7966
8041
  });
@@ -7972,14 +8047,21 @@ brainCmd.command('list')
7972
8047
  .option('--url <url>', 'Brain server URL')
7973
8048
  .option('--key <key>', 'Pi key')
7974
8049
  .option('--json', 'Output as JSON')
8050
+ .option('--offset <n>', 'Skip first N results (pagination)', '0')
8051
+ .option('--sort <field>', 'Sort by: updated_at, quality, votes', 'updated_at')
8052
+ .option('--tags <tags>', 'Filter by tags (comma-separated)')
7975
8053
  .action(async (opts) => {
7976
8054
  const config = getBrainConfig(opts);
7977
8055
  try {
7978
- const results = await brainFetch(config, '/v1/memories/list', { params: { category: opts.category, limit: opts.limit } });
7979
- if (opts.json || !process.stdout.isTTY) { console.log(JSON.stringify(results, null, 2)); return; }
8056
+ const data = await brainFetch(config, '/v1/memories/list', { params: { category: opts.category, limit: opts.limit, offset: opts.offset, sort: opts.sort, tags: opts.tags } });
8057
+ if (opts.json || !process.stdout.isTTY) { console.log(JSON.stringify(data, null, 2)); return; }
7980
8058
  console.log(chalk.bold.cyan('\nShared Brain Memories\n'));
7981
- if (!results.length) { console.log(chalk.dim(' No memories found.\n')); return; }
7982
- results.forEach((r, i) => {
8059
+ const memories = Array.isArray(data) ? data : data.memories || [];
8060
+ if (data.total_count !== undefined) {
8061
+ console.log(chalk.dim(` Showing ${memories.length} of ${data.total_count} (offset ${data.offset || 0})\n`));
8062
+ }
8063
+ if (!memories.length) { console.log(chalk.dim(' No memories found.\n')); return; }
8064
+ memories.forEach((r, i) => {
7983
8065
  console.log(` ${chalk.yellow(i + 1 + '.')} ${chalk.bold(r.title || r.id)} ${chalk.dim(`[${r.category || 'unknown'}]`)}`);
7984
8066
  });
7985
8067
  console.log();
@@ -7990,10 +8072,12 @@ brainCmd.command('delete <id>')
7990
8072
  .description('Delete your own contribution')
7991
8073
  .option('--url <url>', 'Brain server URL')
7992
8074
  .option('--key <key>', 'Pi key')
8075
+ .option('--json', 'Output as JSON')
7993
8076
  .action(async (id, opts) => {
7994
8077
  const config = getBrainConfig(opts);
7995
8078
  try {
7996
- await brainFetch(config, `/v1/memories/${id}`, { method: 'DELETE' });
8079
+ const result = await brainFetch(config, `/v1/memories/${id}`, { method: 'DELETE' });
8080
+ if (opts.json || !process.stdout.isTTY) { console.log(JSON.stringify(result, null, 2)); return; }
7997
8081
  console.log(chalk.green(`Deleted: ${id}`));
7998
8082
  } catch (e) { console.error(chalk.red(`Error: ${e.message}`)); process.exit(1); }
7999
8083
  });
@@ -8088,10 +8172,12 @@ brainCmd.command('sync [direction]')
8088
8172
  .description('Synchronize LoRA weights (pull, push, or both)')
8089
8173
  .option('--url <url>', 'Brain server URL')
8090
8174
  .option('--key <key>', 'Pi key')
8175
+ .option('--json', 'Output as JSON')
8091
8176
  .action(async (direction, opts) => {
8092
8177
  const config = getBrainConfig(opts);
8093
8178
  try {
8094
8179
  const result = await brainFetch(config, '/v1/lora/latest', { params: { direction: direction || 'both' } });
8180
+ if (opts.json || !process.stdout.isTTY) { console.log(JSON.stringify(result, null, 2)); return; }
8095
8181
  console.log(chalk.green(`Sync ${direction || 'both'}: ${result.status || 'OK'}`));
8096
8182
  } catch (e) { console.error(chalk.red(`Error: ${e.message}`)); process.exit(1); }
8097
8183
  });
@@ -8191,7 +8277,7 @@ async function fetchBrainEndpoint(config, endpoint) {
8191
8277
  const url = (config.url || 'https://pi.ruv.io') + endpoint;
8192
8278
  const headers = {};
8193
8279
  if (config.key) headers['Authorization'] = `Bearer ${config.key}`;
8194
- const resp = await fetch(url, { headers });
8280
+ const resp = await proxyFetch(url, { headers, signal: AbortSignal.timeout(30000) });
8195
8281
  if (!resp.ok) throw new Error(`${resp.status} ${resp.statusText}`);
8196
8282
  return resp.json();
8197
8283
  }
@@ -8420,7 +8506,7 @@ midstreamCmd.command('benchmark')
8420
8506
 
8421
8507
  async function timeRequest(url, label) {
8422
8508
  const start = performance.now();
8423
- const resp = await fetch(url, { headers });
8509
+ const resp = await proxyFetch(url, { headers, signal: AbortSignal.timeout(30000) });
8424
8510
  const elapsed = performance.now() - start;
8425
8511
  return { label, status: resp.status, elapsed };
8426
8512
  }
@@ -8490,7 +8576,7 @@ edgeCmd.command('status')
8490
8576
  .option('--json', 'Output as JSON')
8491
8577
  .action(async (opts) => {
8492
8578
  try {
8493
- const resp = await fetch(`${EDGE_GENESIS}/status`);
8579
+ const resp = await proxyFetch(`${EDGE_GENESIS}/status`, { signal: AbortSignal.timeout(30000) });
8494
8580
  const data = await resp.json();
8495
8581
  if (opts.json || !process.stdout.isTTY) { console.log(JSON.stringify(data, null, 2)); return; }
8496
8582
  console.log(chalk.bold.cyan('\nEdge Network Status\n'));
@@ -8506,10 +8592,11 @@ edgeCmd.command('join')
8506
8592
  const piKey = process.env.PI;
8507
8593
  if (!piKey) { console.error(chalk.red('Set PI environment variable first. Run: npx ruvector identity generate')); process.exit(1); }
8508
8594
  try {
8509
- const resp = await fetch(`${EDGE_GENESIS}/join`, {
8595
+ const resp = await proxyFetch(`${EDGE_GENESIS}/join`, {
8510
8596
  method: 'POST',
8511
8597
  headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${piKey}` },
8512
- body: JSON.stringify({ contribution: parseFloat(opts.contribution), pi_key: piKey })
8598
+ body: JSON.stringify({ contribution: parseFloat(opts.contribution), pi_key: piKey }),
8599
+ signal: AbortSignal.timeout(30000)
8513
8600
  });
8514
8601
  const data = await resp.json();
8515
8602
  console.log(chalk.green(`Joined edge network: ${data.node_id || 'OK'}`));
@@ -8524,7 +8611,7 @@ edgeCmd.command('balance')
8524
8611
  if (!piKey) { console.error(chalk.red('Set PI environment variable first.')); process.exit(1); }
8525
8612
  try {
8526
8613
  const pseudonym = require('crypto').createHash('shake256', { outputLength: 16 }).update(piKey).digest('hex');
8527
- const resp = await fetch(`${EDGE_GENESIS}/balance/${pseudonym}`, { headers: { 'Authorization': `Bearer ${piKey}` } });
8614
+ const resp = await proxyFetch(`${EDGE_GENESIS}/balance/${pseudonym}`, { headers: { 'Authorization': `Bearer ${piKey}` }, signal: AbortSignal.timeout(30000) });
8528
8615
  if (!resp.ok) { console.error(chalk.red(`Edge network returned ${resp.status} ${resp.statusText}`)); process.exit(1); }
8529
8616
  const data = await resp.json();
8530
8617
  if (opts.json || !process.stdout.isTTY) { console.log(JSON.stringify(data, null, 2)); return; }
@@ -8540,7 +8627,7 @@ edgeCmd.command('tasks')
8540
8627
  .option('--json', 'Output as JSON')
8541
8628
  .action(async (opts) => {
8542
8629
  try {
8543
- const resp = await fetch(`${EDGE_GENESIS}/tasks?limit=${opts.limit}`);
8630
+ const resp = await proxyFetch(`${EDGE_GENESIS}/tasks?limit=${opts.limit}`, { signal: AbortSignal.timeout(30000) });
8544
8631
  const data = await resp.json();
8545
8632
  if (opts.json || !process.stdout.isTTY) { console.log(JSON.stringify(data, null, 2)); return; }
8546
8633
  console.log(chalk.bold.cyan('\nEdge Compute Tasks\n'));
package/bin/mcp-server.js CHANGED
@@ -95,6 +95,71 @@ function sanitizeNumericArg(arg, defaultVal) {
95
95
  return Number.isFinite(n) && n > 0 ? n : (defaultVal || 0);
96
96
  }
97
97
 
98
+ // ── Proxy-aware fetch wrapper ───────────────────────────────────────────────
99
+ let _proxyDispatcherSet = false;
100
+
101
+ function getProxyUrl(targetUrl) {
102
+ const NO_PROXY = process.env.NO_PROXY || process.env.no_proxy || '';
103
+ if (NO_PROXY === '*') return null;
104
+ if (NO_PROXY) {
105
+ try {
106
+ const host = new URL(targetUrl).hostname.toLowerCase();
107
+ const patterns = NO_PROXY.split(',').map(p => p.trim().toLowerCase());
108
+ for (const p of patterns) {
109
+ if (!p) continue;
110
+ if (host === p || host.endsWith(p.startsWith('.') ? p : '.' + p)) return null;
111
+ }
112
+ } catch {}
113
+ }
114
+ return process.env.HTTPS_PROXY || process.env.https_proxy
115
+ || process.env.HTTP_PROXY || process.env.http_proxy
116
+ || process.env.ALL_PROXY || process.env.all_proxy
117
+ || null;
118
+ }
119
+
120
+ async function proxyFetch(url, opts) {
121
+ const target = typeof url === 'string' ? url : url.toString();
122
+ const proxy = getProxyUrl(target);
123
+ if (!proxy) return fetch(url, opts);
124
+
125
+ if (!_proxyDispatcherSet) {
126
+ try {
127
+ const undici = require('undici');
128
+ if (undici.ProxyAgent && undici.setGlobalDispatcher) {
129
+ undici.setGlobalDispatcher(new undici.ProxyAgent(proxy));
130
+ _proxyDispatcherSet = true;
131
+ }
132
+ } catch {}
133
+ }
134
+ if (_proxyDispatcherSet) return fetch(url, opts);
135
+
136
+ const { execFileSync } = require('child_process');
137
+ const args = ['-sS', '-L', '--max-time', '30'];
138
+ if (opts && opts.method) { args.push('-X', opts.method); }
139
+ if (opts && opts.headers) {
140
+ for (const [k, v] of Object.entries(opts.headers)) {
141
+ args.push('-H', `${k}: ${v}`);
142
+ }
143
+ }
144
+ if (opts && opts.body) { args.push('-d', typeof opts.body === 'string' ? opts.body : JSON.stringify(opts.body)); }
145
+ args.push(target);
146
+ try {
147
+ const stdout = execFileSync('curl', args, { encoding: 'utf8', timeout: 35000 });
148
+ const body = stdout.trim();
149
+ return {
150
+ ok: true,
151
+ status: 200,
152
+ statusText: 'OK',
153
+ text: async () => body,
154
+ json: async () => JSON.parse(body),
155
+ headers: new Map(),
156
+ };
157
+ } catch (e) {
158
+ const msg = e.stderr ? e.stderr.toString().trim() : e.message;
159
+ throw new Error(`Proxy curl failed: ${msg}`);
160
+ }
161
+ }
162
+
98
163
  // Try to load the full IntelligenceEngine
99
164
  let IntelligenceEngine = null;
100
165
  let engineAvailable = false;
@@ -363,7 +428,7 @@ class Intelligence {
363
428
  const server = new Server(
364
429
  {
365
430
  name: 'ruvector',
366
- version: '0.2.6',
431
+ version: '0.2.8',
367
432
  },
368
433
  {
369
434
  capabilities: {
@@ -3122,7 +3187,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3122
3187
  // Fetch from GCS if no fresh cache
3123
3188
  if (!manifest) {
3124
3189
  try {
3125
- const resp = await fetch(GCS_MANIFEST);
3190
+ const resp = await proxyFetch(GCS_MANIFEST, { signal: AbortSignal.timeout(15000) });
3126
3191
  if (resp.ok) {
3127
3192
  manifest = await resp.json();
3128
3193
  try {
@@ -3320,6 +3385,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3320
3385
  const p = new URLSearchParams();
3321
3386
  if (args.category) p.set('category', args.category);
3322
3387
  p.set('limit', String(args.limit || 20));
3388
+ if (args.offset) p.set('offset', String(args.offset));
3389
+ if (args.sort) p.set('sort', args.sort);
3390
+ if (args.tags) p.set('tags', args.tags);
3323
3391
  url = `${brainUrl}/v1/memories/list?${p}`;
3324
3392
  break;
3325
3393
  }
@@ -3350,7 +3418,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3350
3418
  }
3351
3419
  case 'sync': url = `${brainUrl}/v1/lora/latest`; break;
3352
3420
  }
3353
- const resp = await fetch(url, fetchOpts);
3421
+ const resp = await proxyFetch(url, fetchOpts);
3354
3422
  if (!resp.ok) {
3355
3423
  const errText = await resp.text().catch(() => resp.statusText);
3356
3424
  return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
@@ -3384,7 +3452,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3384
3452
  brain_flags: '/v1/status',
3385
3453
  };
3386
3454
  const endpoint = endpointMap[name];
3387
- const resp = await fetch(`${brainUrl}${endpoint}`, { headers: hdrs });
3455
+ const resp = await proxyFetch(`${brainUrl}${endpoint}`, { headers: hdrs, signal: AbortSignal.timeout(30000) });
3388
3456
  if (!resp.ok) {
3389
3457
  const errText = await resp.text().catch(() => resp.statusText);
3390
3458
  return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
@@ -3428,7 +3496,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3428
3496
  const hdrs = { 'Content-Type': 'application/json' };
3429
3497
  if (brainKey) hdrs['Authorization'] = `Bearer ${brainKey}`;
3430
3498
 
3431
- const resp = await fetch(`${brainUrl}/v1/midstream`, { headers: hdrs });
3499
+ const resp = await proxyFetch(`${brainUrl}/v1/midstream`, { headers: hdrs, signal: AbortSignal.timeout(30000) });
3432
3500
  if (!resp.ok) {
3433
3501
  const errText = await resp.text().catch(() => resp.statusText);
3434
3502
  return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
@@ -3458,7 +3526,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3458
3526
 
3459
3527
  async function timeFetch(url) {
3460
3528
  const start = performance.now();
3461
- const resp = await fetch(url, { headers: hdrs });
3529
+ const resp = await proxyFetch(url, { headers: hdrs });
3462
3530
  return { status: resp.status, elapsed: performance.now() - start };
3463
3531
  }
3464
3532
 
@@ -3511,7 +3579,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3511
3579
  if (brainKey) hdrs['Authorization'] = `Bearer ${brainKey}`;
3512
3580
  const limit = Math.min(Math.max(parseInt(args.limit) || 10, 1), 100);
3513
3581
  const q = encodeURIComponent(args.query);
3514
- const resp = await fetch(`${brainUrl}/v1/memories/search?q=${q}&limit=${limit}`, { headers: hdrs });
3582
+ const resp = await proxyFetch(`${brainUrl}/v1/memories/search?q=${q}&limit=${limit}`, { headers: hdrs, signal: AbortSignal.timeout(30000) });
3515
3583
  if (!resp.ok) {
3516
3584
  const errText = await resp.text().catch(() => resp.statusText);
3517
3585
  return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
@@ -3531,8 +3599,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3531
3599
  if (brainKey) hdrs['Authorization'] = `Bearer ${brainKey}`;
3532
3600
 
3533
3601
  const [healthResp, midResp] = await Promise.all([
3534
- fetch(`${brainUrl}/v1/health`, { headers: hdrs }).then(r => r.json()).catch(e => ({ error: e.message })),
3535
- fetch(`${brainUrl}/v1/midstream`, { headers: hdrs }).then(r => r.json()).catch(e => ({ error: e.message })),
3602
+ proxyFetch(`${brainUrl}/v1/health`, { headers: hdrs, signal: AbortSignal.timeout(15000) }).then(r => r.json()).catch(e => ({ error: e.message })),
3603
+ proxyFetch(`${brainUrl}/v1/midstream`, { headers: hdrs, signal: AbortSignal.timeout(15000) }).then(r => r.json()).catch(e => ({ error: e.message })),
3536
3604
  ]);
3537
3605
 
3538
3606
  return { content: [{ type: 'text', text: JSON.stringify({
@@ -3560,7 +3628,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3560
3628
  case 'balance': { const ps = process.env.PI ? require('crypto').createHash('shake256', { outputLength: 16 }).update(process.env.PI).digest('hex') : 'anonymous'; endpoint = `/balance/${ps}`; break; }
3561
3629
  case 'tasks': endpoint = `/tasks?limit=${args.limit || 20}`; break;
3562
3630
  }
3563
- const resp = await fetch(`${genesisUrl}${endpoint}`, {
3631
+ const resp = await proxyFetch(`${genesisUrl}${endpoint}`, {
3564
3632
  method,
3565
3633
  headers: { 'Content-Type': 'application/json', ...(process.env.PI ? { 'Authorization': `Bearer ${process.env.PI}` } : {}) },
3566
3634
  ...(body ? { body } : {})
@@ -3831,7 +3899,7 @@ async function main() {
3831
3899
  transport: 'sse',
3832
3900
  sessions: sessions.size,
3833
3901
  tools: 91,
3834
- version: '0.2.6'
3902
+ version: '0.2.8'
3835
3903
  }));
3836
3904
 
3837
3905
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ruvector",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "High-performance vector database for Node.js with automatic native/WASM fallback",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",