vektor-slipstream 1.4.4 → 2.0.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.
Files changed (56) hide show
  1. package/README.md +67 -306
  2. package/package.json +14 -146
  3. package/CHANGELOG.md +0 -139
  4. package/LICENSE +0 -33
  5. package/TENETS.md +0 -189
  6. package/audn-log.js +0 -143
  7. package/axon.js +0 -389
  8. package/boot-patch.js +0 -33
  9. package/boot-screen.html +0 -210
  10. package/briefing.js +0 -150
  11. package/cerebellum.js +0 -439
  12. package/cloak-behaviour.js +0 -596
  13. package/cloak-captcha.js +0 -541
  14. package/cloak-core.js +0 -499
  15. package/cloak-identity.js +0 -484
  16. package/cloak-index.js +0 -261
  17. package/cloak-llms.js +0 -163
  18. package/cloak-pattern-store.js +0 -471
  19. package/cloak-recorder-auto.js +0 -297
  20. package/cloak-recorder-snippet.js +0 -119
  21. package/cloak-turbo-quant.js +0 -357
  22. package/cloak-warmup.js +0 -240
  23. package/cortex.js +0 -221
  24. package/detect-hardware.js +0 -181
  25. package/entity-resolver.js +0 -298
  26. package/errors.js +0 -66
  27. package/examples/example-claude-mcp.js +0 -220
  28. package/examples/example-langchain-researcher.js +0 -82
  29. package/examples/example-openai-assistant.js +0 -84
  30. package/examples/examples-README.md +0 -161
  31. package/export-import.js +0 -221
  32. package/forget.js +0 -148
  33. package/inspect.js +0 -199
  34. package/mistral/README-mistral.md +0 -123
  35. package/mistral/mistral-bridge.js +0 -218
  36. package/mistral/mistral-setup.js +0 -220
  37. package/mistral/vektor-tool-manifest.json +0 -41
  38. package/models/model_quantized.onnx +0 -0
  39. package/models/vocab.json +0 -1
  40. package/namespace.js +0 -186
  41. package/pin.js +0 -91
  42. package/slipstream-core-extended.js +0 -134
  43. package/slipstream-core.js +0 -1
  44. package/slipstream-db.js +0 -140
  45. package/slipstream-embedder.js +0 -338
  46. package/sovereign.js +0 -142
  47. package/token.js +0 -322
  48. package/types/index.d.ts +0 -269
  49. package/vektor-banner-loader.js +0 -109
  50. package/vektor-cli.js +0 -259
  51. package/vektor-licence-prompt.js +0 -128
  52. package/vektor-licence.js +0 -192
  53. package/vektor-setup.js +0 -270
  54. package/vektor-slipstream.dxt +0 -0
  55. package/vektor-tui.js +0 -373
  56. package/visualize.js +0 -235
package/cloak-captcha.js DELETED
@@ -1,541 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * cloak-captcha.js
5
- * Automated CAPTCHA detection and solving pipeline for Cloak.
6
- *
7
- * Supports:
8
- * - hCaptcha → screenshot → vision model → token injection
9
- * - reCAPTCHA v2 → 2captcha/CapSolver API fallback
10
- * - reCAPTCHA v3 → session warmup strategy (score-based, no challenge)
11
- * - Cloudflare Turnstile → fingerprint consistency pass
12
- * - Audio CAPTCHA → Whisper transcription
13
- *
14
- * Usage:
15
- * const { detectCaptcha, solveCaptcha, injectCaptchaSolution } = require('./cloak-captcha');
16
- * const detected = await detectCaptcha(page);
17
- * if (detected) {
18
- * const token = await solveCaptcha(page, detected, { visionApiKey, provider });
19
- * await injectCaptchaSolution(page, detected, token);
20
- * }
21
- */
22
-
23
- const https = require('https');
24
- const fs = require('fs');
25
- const path = require('path');
26
- const os = require('os');
27
-
28
- // ── Detection ─────────────────────────────────────────────────────────────────
29
-
30
- const CAPTCHA_SIGNATURES = {
31
- hcaptcha: [
32
- 'hcaptcha.com/1/api.js',
33
- 'data-hcaptcha-widget-id',
34
- 'h-captcha',
35
- 'hcaptcha-challenge',
36
- ],
37
- recaptcha_v2: [
38
- 'google.com/recaptcha/api.js',
39
- 'g-recaptcha',
40
- 'data-sitekey',
41
- 'recaptcha-checkbox',
42
- ],
43
- recaptcha_v3: [
44
- 'google.com/recaptcha/api.js?render=',
45
- 'grecaptcha.execute',
46
- ],
47
- turnstile: [
48
- 'challenges.cloudflare.com',
49
- 'cf-turnstile',
50
- 'data-cf-turnstile',
51
- ],
52
- audio: [
53
- 'audio-challenge',
54
- 'captcha-audio',
55
- 'rc-audiochallenge',
56
- ],
57
- };
58
-
59
- /**
60
- * Detect CAPTCHA type on a Playwright page.
61
- * Returns { type, sitekey, element } or null.
62
- */
63
- async function detectCaptcha(page) {
64
- const html = await page.content().catch(() => '');
65
-
66
- for (const [type, sigs] of Object.entries(CAPTCHA_SIGNATURES)) {
67
- for (const sig of sigs) {
68
- if (html.includes(sig)) {
69
- // Extract sitekey if available
70
- let sitekey = null;
71
- const skMatch = html.match(/data-sitekey=["']([^"']+)["']/);
72
- if (skMatch) sitekey = skMatch[1];
73
-
74
- // Check if actually visible (not just in source)
75
- const visible = await _isCaptchaVisible(page, type);
76
- if (!visible && type !== 'recaptcha_v3') continue; // v3 is invisible by design
77
-
78
- return { type, sitekey, visible };
79
- }
80
- }
81
- }
82
- return null;
83
- }
84
-
85
- async function _isCaptchaVisible(page, type) {
86
- const selectors = {
87
- hcaptcha: 'iframe[src*="hcaptcha"]',
88
- recaptcha_v2: 'iframe[src*="recaptcha"]',
89
- recaptcha_v3: 'script[src*="recaptcha"]',
90
- turnstile: 'iframe[src*="challenges.cloudflare"]',
91
- audio: '.rc-audiochallenge',
92
- };
93
- const sel = selectors[type];
94
- if (!sel) return false;
95
- try {
96
- const el = await page.$(sel);
97
- return !!el;
98
- } catch { return false; }
99
- }
100
-
101
- // ── Solving ───────────────────────────────────────────────────────────────────
102
-
103
- /**
104
- * Solve a detected CAPTCHA. Returns token string or null.
105
- *
106
- * opts:
107
- * provider: 'claude' | 'openai' | '2captcha' | 'capsolver' (default: 'claude')
108
- * visionApiKey: API key for vision provider
109
- * solverApiKey: API key for 2captcha/capsolver
110
- * anthropicKey: Anthropic API key (for provider='claude')
111
- */
112
- async function solveCaptcha(page, detected, opts = {}) {
113
- const provider = opts.provider || 'claude';
114
-
115
- switch (detected.type) {
116
- case 'hcaptcha':
117
- return _solveHcaptcha(page, { ...opts, provider });
118
-
119
- case 'recaptcha_v2':
120
- return _solveRecaptchaV2(page, detected, opts);
121
-
122
- case 'recaptcha_v3':
123
- // v3 is score-based — no token to solve, just warm the session
124
- return _warmRecaptchaV3Session(page, opts);
125
-
126
- case 'turnstile':
127
- // Turnstile needs consistent fingerprint — return advisory
128
- return { advisory: 'turnstile', message: 'Use persistent cloak_passport fingerprint for Turnstile.' };
129
-
130
- case 'audio':
131
- return _solveAudioCaptcha(page, opts);
132
-
133
- default:
134
- return null;
135
- }
136
- }
137
-
138
- // ── hCaptcha — screenshot + vision model ─────────────────────────────────────
139
-
140
- async function _solveHcaptcha(page, opts) {
141
- // Switch to image challenge if audio is showing
142
- try {
143
- const audioBtn = await page.$('.h-captcha-audio-btn, [aria-label="Get an audio challenge"]');
144
- if (audioBtn) {
145
- const visualBtn = await page.$('[aria-label="Get a visual challenge"]');
146
- if (visualBtn) await visualBtn.click();
147
- await page.waitForTimeout(800);
148
- }
149
- } catch { /* ignore */ }
150
-
151
- // Find the hCaptcha iframe
152
- const frame = await _getHcaptchaFrame(page);
153
- if (!frame) return null;
154
-
155
- // Get challenge prompt text
156
- let prompt = 'unknown challenge';
157
- try {
158
- const promptEl = await frame.$('.prompt-text, [class*="prompt"]');
159
- if (promptEl) prompt = await promptEl.innerText();
160
- } catch { /* ignore */ }
161
-
162
- // Screenshot the challenge grid
163
- const screenshotPath = path.join(os.tmpdir(), `hcaptcha-${Date.now()}.png`);
164
- try {
165
- const challengeEl = await frame.$('.task-grid, .challenge-container, .display-language');
166
- if (challengeEl) {
167
- await challengeEl.screenshot({ path: screenshotPath });
168
- } else {
169
- // Full frame screenshot
170
- await frame.locator('body').screenshot({ path: screenshotPath });
171
- }
172
- } catch (e) {
173
- // Full page screenshot fallback
174
- await page.screenshot({ path: screenshotPath });
175
- }
176
-
177
- // Send to vision model
178
- const imageData = fs.readFileSync(screenshotPath).toString('base64');
179
- let selections = null;
180
-
181
- try {
182
- if (opts.provider === 'claude' || !opts.provider) {
183
- selections = await _visionSolveWithClaude(imageData, prompt, opts.anthropicKey);
184
- } else if (opts.provider === 'openai') {
185
- selections = await _visionSolveWithOpenAI(imageData, prompt, opts.visionApiKey);
186
- }
187
- } finally {
188
- fs.unlink(screenshotPath, () => {});
189
- }
190
-
191
- if (!selections) return null;
192
-
193
- // Click the correct tiles
194
- await _clickHcaptchaTiles(frame, selections);
195
-
196
- // Click verify
197
- try {
198
- const verifyBtn = await frame.$('#checkbox, .button-submit, [data-cy="submit"]');
199
- if (verifyBtn) {
200
- await verifyBtn.click();
201
- await page.waitForTimeout(1500);
202
- }
203
- } catch { /* ignore */ }
204
-
205
- // Extract response token
206
- return _extractHcaptchaToken(page);
207
- }
208
-
209
- async function _visionSolveWithClaude(imageData, prompt, apiKey) {
210
- const key = apiKey || process.env.ANTHROPIC_API_KEY;
211
- if (!key) throw new Error('No Anthropic API key for CAPTCHA vision solver');
212
-
213
- const body = JSON.stringify({
214
- model: 'claude-haiku-4-5-20251001',
215
- max_tokens: 256,
216
- messages: [{
217
- role: 'user',
218
- content: [
219
- {
220
- type: 'image',
221
- source: { type: 'base64', media_type: 'image/png', data: imageData },
222
- },
223
- {
224
- type: 'text',
225
- text: `This is an hCaptcha image challenge. The task is: "${prompt}".
226
- The grid shows numbered tiles (1-9 in a 3x3 grid, left to right, top to bottom).
227
- Reply ONLY with a JSON array of tile numbers that match the task, e.g.: [1,4,7]
228
- If no tiles match, reply: []`,
229
- },
230
- ],
231
- }],
232
- });
233
-
234
- const response = await _httpsPost('api.anthropic.com', '/v1/messages', body, {
235
- 'x-api-key': key,
236
- 'anthropic-version': '2023-06-01',
237
- });
238
-
239
- const text = response?.content?.[0]?.text || '[]';
240
- const match = text.match(/\[[\d,\s]*\]/);
241
- return match ? JSON.parse(match[0]) : [];
242
- }
243
-
244
- async function _visionSolveWithOpenAI(imageData, prompt, apiKey) {
245
- const key = apiKey || process.env.OPENAI_API_KEY;
246
- if (!key) throw new Error('No OpenAI API key for CAPTCHA vision solver');
247
-
248
- const body = JSON.stringify({
249
- model: 'gpt-4o',
250
- max_tokens: 100,
251
- messages: [{
252
- role: 'user',
253
- content: [
254
- { type: 'image_url', image_url: { url: `data:image/png;base64,${imageData}` } },
255
- { type: 'text', text: `hCaptcha task: "${prompt}". Reply ONLY with JSON array of matching tile numbers 1-9. e.g. [2,5]` },
256
- ],
257
- }],
258
- });
259
-
260
- const response = await _httpsPost('api.openai.com', '/v1/chat/completions', body, {
261
- 'Authorization': `Bearer ${key}`,
262
- });
263
-
264
- const text = response?.choices?.[0]?.message?.content || '[]';
265
- const match = text.match(/\[[\d,\s]*\]/);
266
- return match ? JSON.parse(match[0]) : [];
267
- }
268
-
269
- async function _getHcaptchaFrame(page) {
270
- for (const frame of page.frames()) {
271
- const url = frame.url();
272
- if (url.includes('hcaptcha.com') && url.includes('challenge')) return frame;
273
- }
274
- return null;
275
- }
276
-
277
- async function _clickHcaptchaTiles(frame, tileNumbers) {
278
- if (!tileNumbers || !tileNumbers.length) return;
279
- const tiles = await frame.$$('.task-image, .challenge-image, [class*="image"]');
280
- for (const n of tileNumbers) {
281
- const tile = tiles[n - 1];
282
- if (tile) {
283
- await tile.click();
284
- await frame.waitForTimeout(200 + Math.random() * 300); // human-like delay
285
- }
286
- }
287
- }
288
-
289
- async function _extractHcaptchaToken(page) {
290
- try {
291
- const token = await page.evaluate(() => {
292
- const el = document.querySelector('[name="h-captcha-response"], textarea[id*="captcha"]');
293
- return el ? el.value : null;
294
- });
295
- return token || null;
296
- } catch { return null; }
297
- }
298
-
299
- // ── reCAPTCHA v2 — 2captcha/CapSolver API ────────────────────────────────────
300
-
301
- async function _solveRecaptchaV2(page, detected, opts) {
302
- if (!opts.solverApiKey) {
303
- return { advisory: 'recaptcha_v2', message: 'Provide solverApiKey (2captcha/capsolver) for reCAPTCHA v2.' };
304
- }
305
- // Submit to 2captcha
306
- const submitBody = new URLSearchParams({
307
- key: opts.solverApiKey,
308
- method: 'userrecaptcha',
309
- googlekey: detected.sitekey || '',
310
- pageurl: page.url(),
311
- json: '1',
312
- });
313
-
314
- const submitted = await _httpsPost('2captcha.com', '/in.php', submitBody.toString(), {
315
- 'Content-Type': 'application/x-www-form-urlencoded',
316
- });
317
-
318
- if (!submitted?.request) return null;
319
- const taskId = submitted.request;
320
-
321
- // Poll for result (max 120s)
322
- for (let i = 0; i < 24; i++) {
323
- await _sleep(5000);
324
- const result = await _httpsGet(`https://2captcha.com/res.php?key=${opts.solverApiKey}&action=get&id=${taskId}&json=1`);
325
- if (result?.status === 1) return result.request;
326
- if (result?.request === 'ERROR_CAPTCHA_UNSOLVABLE') return null;
327
- }
328
- return null;
329
- }
330
-
331
- // ── reCAPTCHA v3 — Session warmup ────────────────────────────────────────────
332
-
333
- /**
334
- * Warm up a reCAPTCHA v3 session by simulating human-like browsing.
335
- * Visit the homepage, scroll, hover, then navigate to target.
336
- * This builds a 0.7+ trust score before hitting the protected page.
337
- */
338
- async function _warmRecaptchaV3Session(page, opts) {
339
- const currentUrl = page.url();
340
- let origin;
341
- try { origin = new URL(currentUrl).origin; } catch { return null; }
342
-
343
- // Simulate human browsing — visit homepage first
344
- try {
345
- await page.goto(origin, { waitUntil: 'domcontentloaded', timeout: 10000 });
346
- await _humanScroll(page);
347
- await _humanMouseMovement(page);
348
- await _sleep(1000 + Math.random() * 2000);
349
-
350
- // Visit a secondary page if possible (builds session history)
351
- const links = await page.$$eval('a[href]', els =>
352
- els
353
- .map(el => el.href)
354
- .filter(h => h.startsWith(window.location.origin) && !h.includes('#'))
355
- .slice(0, 5)
356
- );
357
- if (links.length > 1) {
358
- await page.goto(links[1], { waitUntil: 'domcontentloaded', timeout: 10000 });
359
- await _humanScroll(page);
360
- await _sleep(800 + Math.random() * 1200);
361
- }
362
-
363
- // Return to original URL
364
- await page.goto(currentUrl, { waitUntil: 'domcontentloaded', timeout: 15000 });
365
- return { warmed: true, message: 'reCAPTCHA v3 session warmed — score should be 0.7+' };
366
- } catch (e) {
367
- return { warmed: false, message: e.message };
368
- }
369
- }
370
-
371
- // ── Audio CAPTCHA — Whisper ───────────────────────────────────────────────────
372
-
373
- async function _solveAudioCaptcha(page, opts) {
374
- const openaiKey = opts.visionApiKey || process.env.OPENAI_API_KEY;
375
- if (!openaiKey) {
376
- return { advisory: 'audio_captcha', message: 'Provide visionApiKey (OpenAI) for audio CAPTCHA solving.' };
377
- }
378
-
379
- // Find audio challenge element and get audio URL
380
- let audioUrl = null;
381
- try {
382
- audioUrl = await page.evaluate(() => {
383
- const el = document.querySelector('.rc-audiochallenge-tdownload-link, audio source, [data-audio-src]');
384
- return el ? (el.href || el.src || el.dataset.audioSrc) : null;
385
- });
386
- } catch { /* ignore */ }
387
-
388
- if (!audioUrl) return null;
389
-
390
- // Download audio file
391
- const audioPath = path.join(os.tmpdir(), `captcha-audio-${Date.now()}.mp3`);
392
- await _downloadFile(audioUrl, audioPath);
393
-
394
- // Transcribe with Whisper
395
- try {
396
- const FormData = require('form-data');
397
- const form = new FormData();
398
- form.append('file', fs.createReadStream(audioPath));
399
- form.append('model', 'whisper-1');
400
- form.append('language', 'en');
401
-
402
- const result = await _httpsPostForm('api.openai.com', '/v1/audio/transcriptions', form, {
403
- 'Authorization': `Bearer ${openaiKey}`,
404
- });
405
-
406
- const text = result?.text?.toLowerCase().replace(/[^a-z0-9\s]/g, '').trim();
407
- return text || null;
408
- } finally {
409
- fs.unlink(audioPath, () => {});
410
- }
411
- }
412
-
413
- // ── Token injection ───────────────────────────────────────────────────────────
414
-
415
- /**
416
- * Inject a solved CAPTCHA token back into the page.
417
- */
418
- async function injectCaptchaSolution(page, detected, token) {
419
- if (!token || typeof token !== 'string') return false;
420
-
421
- try {
422
- await page.evaluate(({ type, token }) => {
423
- if (type === 'hcaptcha') {
424
- const el = document.querySelector('[name="h-captcha-response"]');
425
- if (el) { el.value = token; el.dispatchEvent(new Event('change')); }
426
- } else if (type === 'recaptcha_v2') {
427
- const el = document.querySelector('[name="g-recaptcha-response"]');
428
- if (el) { el.value = token; el.dispatchEvent(new Event('change')); }
429
- // Also try the callback
430
- if (window.___grecaptcha_cfg) {
431
- const clients = window.___grecaptcha_cfg.clients;
432
- for (const k in clients) {
433
- const callback = clients[k]?.['']?.callback;
434
- if (typeof callback === 'function') { callback(token); break; }
435
- }
436
- }
437
- }
438
- }, { type: detected.type, token });
439
- return true;
440
- } catch { return false; }
441
- }
442
-
443
- // ── Human behaviour simulation helpers ───────────────────────────────────────
444
-
445
- async function _humanScroll(page) {
446
- await page.evaluate(async () => {
447
- const total = document.body.scrollHeight;
448
- let pos = 0;
449
- while (pos < total * 0.6) {
450
- const step = 80 + Math.random() * 120;
451
- pos = Math.min(pos + step, total);
452
- window.scrollTo({ top: pos, behavior: 'smooth' });
453
- await new Promise(r => setTimeout(r, 80 + Math.random() * 120));
454
- }
455
- });
456
- }
457
-
458
- async function _humanMouseMovement(page) {
459
- const vp = page.viewportSize() || { width: 1280, height: 720 };
460
- for (let i = 0; i < 5; i++) {
461
- const x = 100 + Math.random() * (vp.width - 200);
462
- const y = 100 + Math.random() * (vp.height - 200);
463
- await page.mouse.move(x, y, { steps: 5 + Math.floor(Math.random() * 10) });
464
- await _sleep(200 + Math.random() * 400);
465
- }
466
- }
467
-
468
- // ── HTTP helpers ──────────────────────────────────────────────────────────────
469
-
470
- function _httpsPost(host, path, body, extraHeaders = {}) {
471
- return new Promise((resolve, reject) => {
472
- const isString = typeof body === 'string';
473
- const buf = Buffer.from(body);
474
- const opts = {
475
- hostname: host,
476
- path,
477
- method: 'POST',
478
- headers: {
479
- 'Content-Type': isString && body.startsWith('{') ? 'application/json' : 'application/x-www-form-urlencoded',
480
- 'Content-Length': buf.length,
481
- ...extraHeaders,
482
- },
483
- };
484
- const req = https.request(opts, res => {
485
- let data = '';
486
- res.setEncoding('utf8');
487
- res.on('data', c => data += c);
488
- res.on('end', () => {
489
- try { resolve(JSON.parse(data)); } catch { resolve(data); }
490
- });
491
- });
492
- req.on('error', reject);
493
- req.setTimeout(30000, () => { req.destroy(); reject(new Error('timeout')); });
494
- req.write(buf);
495
- req.end();
496
- });
497
- }
498
-
499
- function _httpsGet(url) {
500
- return new Promise((resolve, reject) => {
501
- https.get(url, res => {
502
- let data = '';
503
- res.setEncoding('utf8');
504
- res.on('data', c => data += c);
505
- res.on('end', () => { try { resolve(JSON.parse(data)); } catch { resolve(data); } });
506
- }).on('error', reject);
507
- });
508
- }
509
-
510
- async function _httpsPostForm(host, path, form, extraHeaders = {}) {
511
- return new Promise((resolve, reject) => {
512
- const opts = {
513
- hostname: host,
514
- path,
515
- method: 'POST',
516
- headers: { ...form.getHeaders(), ...extraHeaders },
517
- };
518
- const req = https.request(opts, res => {
519
- let data = '';
520
- res.setEncoding('utf8');
521
- res.on('data', c => data += c);
522
- res.on('end', () => { try { resolve(JSON.parse(data)); } catch { resolve(data); } });
523
- });
524
- req.on('error', reject);
525
- form.pipe(req);
526
- });
527
- }
528
-
529
- function _downloadFile(url, dest) {
530
- return new Promise((resolve, reject) => {
531
- const file = fs.createWriteStream(dest);
532
- https.get(url, res => {
533
- res.pipe(file);
534
- file.on('finish', () => file.close(resolve));
535
- }).on('error', e => { fs.unlink(dest, () => {}); reject(e); });
536
- });
537
- }
538
-
539
- function _sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
540
-
541
- module.exports = { detectCaptcha, solveCaptcha, injectCaptchaSolution };