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.
- package/README.md +67 -306
- package/package.json +14 -146
- package/CHANGELOG.md +0 -139
- package/LICENSE +0 -33
- package/TENETS.md +0 -189
- package/audn-log.js +0 -143
- package/axon.js +0 -389
- package/boot-patch.js +0 -33
- package/boot-screen.html +0 -210
- package/briefing.js +0 -150
- package/cerebellum.js +0 -439
- package/cloak-behaviour.js +0 -596
- package/cloak-captcha.js +0 -541
- package/cloak-core.js +0 -499
- package/cloak-identity.js +0 -484
- package/cloak-index.js +0 -261
- package/cloak-llms.js +0 -163
- package/cloak-pattern-store.js +0 -471
- package/cloak-recorder-auto.js +0 -297
- package/cloak-recorder-snippet.js +0 -119
- package/cloak-turbo-quant.js +0 -357
- package/cloak-warmup.js +0 -240
- package/cortex.js +0 -221
- package/detect-hardware.js +0 -181
- package/entity-resolver.js +0 -298
- package/errors.js +0 -66
- package/examples/example-claude-mcp.js +0 -220
- package/examples/example-langchain-researcher.js +0 -82
- package/examples/example-openai-assistant.js +0 -84
- package/examples/examples-README.md +0 -161
- package/export-import.js +0 -221
- package/forget.js +0 -148
- package/inspect.js +0 -199
- package/mistral/README-mistral.md +0 -123
- package/mistral/mistral-bridge.js +0 -218
- package/mistral/mistral-setup.js +0 -220
- package/mistral/vektor-tool-manifest.json +0 -41
- package/models/model_quantized.onnx +0 -0
- package/models/vocab.json +0 -1
- package/namespace.js +0 -186
- package/pin.js +0 -91
- package/slipstream-core-extended.js +0 -134
- package/slipstream-core.js +0 -1
- package/slipstream-db.js +0 -140
- package/slipstream-embedder.js +0 -338
- package/sovereign.js +0 -142
- package/token.js +0 -322
- package/types/index.d.ts +0 -269
- package/vektor-banner-loader.js +0 -109
- package/vektor-cli.js +0 -259
- package/vektor-licence-prompt.js +0 -128
- package/vektor-licence.js +0 -192
- package/vektor-setup.js +0 -270
- package/vektor-slipstream.dxt +0 -0
- package/vektor-tui.js +0 -373
- package/visualize.js +0 -235
package/vektor-cli.js
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vektor-cli.js (v1.5.x patch)
|
|
3
|
-
* VEKTOR Slipstream
|
|
4
|
-
* CLI router — drop-in replacement for the v1.4.x router.
|
|
5
|
-
*
|
|
6
|
-
* New commands added in v1.5.x:
|
|
7
|
-
* npx vektor agent --tools full tool suite
|
|
8
|
-
* npx vektor watch filesystem watcher
|
|
9
|
-
* npx vektor sync P2P memory sync
|
|
10
|
-
* npx vektor swarm multi-agent coordination
|
|
11
|
-
*
|
|
12
|
-
* All existing v1.4.x commands (chat, remember, ask, agent) are preserved.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
'use strict';
|
|
16
|
-
|
|
17
|
-
const path = require('path');
|
|
18
|
-
|
|
19
|
-
// ─── Command registry ─────────────────────────────────────────────────────────
|
|
20
|
-
|
|
21
|
-
const COMMANDS = {
|
|
22
|
-
// ── v1.4.x (existing) ──────────────────────────────────────────────────
|
|
23
|
-
chat: () => require('./vektor-cli-chat.js').runChat,
|
|
24
|
-
remember: () => require('./vektor-cli-chat.js').runRemember,
|
|
25
|
-
ask: () => require('./vektor-cli-chat.js').runAsk,
|
|
26
|
-
|
|
27
|
-
// ── v1.5.x (new) ───────────────────────────────────────────────────────
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* npx vektor agent [goal] [--tools web,fs,code] [--continue]
|
|
31
|
-
* Autonomous agent with web search, file system, code execution.
|
|
32
|
-
*/
|
|
33
|
-
agent: () => async (argv) => {
|
|
34
|
-
const { default: runAgent, main } = (() => {
|
|
35
|
-
try { return require('./vektor-agent.js'); } catch { return require('../vektor-agent.js'); }
|
|
36
|
-
})();
|
|
37
|
-
// Delegate to vektor-agent CLI main — it reads process.argv
|
|
38
|
-
await main?.() ?? runAgent({
|
|
39
|
-
goal: argv.filter(a => !a.startsWith('-')).join(' '),
|
|
40
|
-
tools: ['web', 'fs', 'code', 'memory'],
|
|
41
|
-
provider: process.env.VEKTOR_PROVIDER || 'ollama',
|
|
42
|
-
});
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* npx vektor watch [path] [--ext js,ts] [--no-llm]
|
|
47
|
-
* Filesystem watcher — auto-stores change summaries into MAGMA.
|
|
48
|
-
*/
|
|
49
|
-
watch: () => async (_argv) => {
|
|
50
|
-
const { startWatch, parseArgs } = (() => {
|
|
51
|
-
try { return require('./vektor-watch.js'); } catch { return require('../vektor-watch.js'); }
|
|
52
|
-
})();
|
|
53
|
-
const opts = parseArgs(process.argv);
|
|
54
|
-
await startWatch(opts);
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* npx vektor sync --host [--pin X]
|
|
59
|
-
* npx vektor sync --connect <ip> [--pin X]
|
|
60
|
-
* Encrypted P2P memory sync between machines.
|
|
61
|
-
*/
|
|
62
|
-
sync: () => async (_argv) => {
|
|
63
|
-
const { main } = (() => {
|
|
64
|
-
try { return require('./vektor-sync.js'); } catch { return require('../vektor-sync.js'); }
|
|
65
|
-
})();
|
|
66
|
-
await main?.();
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* npx vektor swarm "goal" [--agents 3] [--roles r1,r2,r3]
|
|
71
|
-
* Multi-agent swarm coordination.
|
|
72
|
-
*/
|
|
73
|
-
swarm: () => async (_argv) => {
|
|
74
|
-
const { main } = (() => {
|
|
75
|
-
try { return require('./vektor-swarm.js'); } catch { return require('../vektor-swarm.js'); }
|
|
76
|
-
})();
|
|
77
|
-
await main?.();
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
// ── Utility ────────────────────────────────────────────────────────────
|
|
81
|
-
|
|
82
|
-
providers: () => async (_argv) => {
|
|
83
|
-
await checkProviders();
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
version: () => async (_argv) => {
|
|
87
|
-
const pkg = safeRequirePackageJson();
|
|
88
|
-
console.log(`VEKTOR Slipstream v${pkg.version || '1.5.0'}`);
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
help: () => async (_argv) => {
|
|
92
|
-
printHelp();
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// ─── Provider checker ─────────────────────────────────────────────────────────
|
|
97
|
-
|
|
98
|
-
async function checkProviders() {
|
|
99
|
-
const C = { green: '\x1b[32m', red: '\x1b[31m', dim: '\x1b[2m', reset: '\x1b[0m', bold: '\x1b[1m' };
|
|
100
|
-
console.log(`\n${C.bold}VEKTOR Provider Status${C.reset}\n`);
|
|
101
|
-
|
|
102
|
-
const checks = [
|
|
103
|
-
{ name: 'Claude (Anthropic)', key: 'ANTHROPIC_API_KEY', test: () => testClaude() },
|
|
104
|
-
{ name: 'OpenAI', key: 'OPENAI_API_KEY', test: () => testOpenAI() },
|
|
105
|
-
{ name: 'Groq', key: 'GROQ_API_KEY', test: () => testGroq() },
|
|
106
|
-
{ name: 'Google Gemini', key: 'GEMINI_API_KEY', test: () => testGemini() },
|
|
107
|
-
{ name: 'Ollama (local)', key: null, test: () => testOllama() },
|
|
108
|
-
];
|
|
109
|
-
|
|
110
|
-
for (const check of checks) {
|
|
111
|
-
const hasKey = check.key ? !!process.env[check.key] : true;
|
|
112
|
-
if (!hasKey) {
|
|
113
|
-
console.log(` ${C.red}✗${C.reset} ${check.name} ${C.dim}(${check.key} not set)${C.reset}`);
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
process.stdout.write(` ⏳ ${check.name}…`);
|
|
117
|
-
try {
|
|
118
|
-
const model = await check.test();
|
|
119
|
-
process.stdout.write(`\r ${C.green}✓${C.reset} ${check.name} ${C.dim}${model}${C.reset}\n`);
|
|
120
|
-
} catch (err) {
|
|
121
|
-
process.stdout.write(`\r ${C.red}✗${C.reset} ${check.name} ${C.dim}${err.message}${C.reset}\n`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
console.log('');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async function testClaude() {
|
|
128
|
-
const res = await fetchTimeout('https://api.anthropic.com/v1/models', {
|
|
129
|
-
headers: { 'x-api-key': process.env.ANTHROPIC_API_KEY, 'anthropic-version': '2023-06-01' },
|
|
130
|
-
}, 5000);
|
|
131
|
-
const j = await res.json();
|
|
132
|
-
const m = j.data?.[0]?.id || 'connected';
|
|
133
|
-
return m;
|
|
134
|
-
}
|
|
135
|
-
async function testOpenAI() {
|
|
136
|
-
const res = await fetchTimeout('https://api.openai.com/v1/models', {
|
|
137
|
-
headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
|
|
138
|
-
}, 5000);
|
|
139
|
-
const j = await res.json();
|
|
140
|
-
return j.data?.[0]?.id || 'connected';
|
|
141
|
-
}
|
|
142
|
-
async function testGroq() {
|
|
143
|
-
const res = await fetchTimeout('https://api.groq.com/openai/v1/models', {
|
|
144
|
-
headers: { Authorization: `Bearer ${process.env.GROQ_API_KEY}` },
|
|
145
|
-
}, 5000);
|
|
146
|
-
const j = await res.json();
|
|
147
|
-
return j.data?.[0]?.id || 'connected';
|
|
148
|
-
}
|
|
149
|
-
async function testGemini() {
|
|
150
|
-
const res = await fetchTimeout(`https://generativelanguage.googleapis.com/v1beta/models?key=${process.env.GEMINI_API_KEY}`, {}, 5000);
|
|
151
|
-
const j = await res.json();
|
|
152
|
-
return j.models?.[0]?.name || 'connected';
|
|
153
|
-
}
|
|
154
|
-
async function testOllama() {
|
|
155
|
-
const res = await fetchTimeout('http://localhost:11434/api/tags', {}, 3000);
|
|
156
|
-
const j = await res.json();
|
|
157
|
-
const models = j.models?.map(m => m.name) || [];
|
|
158
|
-
if (!models.length) throw new Error('No models installed. Run: ollama pull qwen3');
|
|
159
|
-
return models.join(', ');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function fetchTimeout(url, opts, ms) {
|
|
163
|
-
const ctrl = new AbortController();
|
|
164
|
-
const t = setTimeout(() => ctrl.abort(), ms);
|
|
165
|
-
return fetch(url, { ...opts, signal: ctrl.signal }).finally(() => clearTimeout(t));
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ─── Help ─────────────────────────────────────────────────────────────────────
|
|
169
|
-
|
|
170
|
-
function printHelp() {
|
|
171
|
-
const C = { bold: '\x1b[1m', dim: '\x1b[2m', cyan: '\x1b[36m', green: '\x1b[32m', reset: '\x1b[0m' };
|
|
172
|
-
console.log(`
|
|
173
|
-
${C.bold}VEKTOR Slipstream CLI${C.reset}
|
|
174
|
-
|
|
175
|
-
${C.bold}Memory:${C.reset}
|
|
176
|
-
${C.cyan}npx vektor remember${C.reset} "text" Store a fact into MAGMA
|
|
177
|
-
${C.cyan}npx vektor ask${C.reset} "question" Recall + LLM answer
|
|
178
|
-
${C.cyan}npx vektor chat${C.reset} Interactive persistent-memory chat
|
|
179
|
-
|
|
180
|
-
${C.bold}Agent (v1.5):${C.reset}
|
|
181
|
-
${C.cyan}npx vektor agent${C.reset} "goal" Basic autonomous agent
|
|
182
|
-
${C.cyan}npx vektor agent${C.reset} "goal" ${C.dim}--tools${C.reset} Full tool suite (web+fs+code)
|
|
183
|
-
${C.cyan}npx vektor agent${C.reset} "goal" ${C.dim}--continue${C.reset} Resume last session
|
|
184
|
-
${C.cyan}npx vektor agent${C.reset} "goal" ${C.dim}--tools web,fs,code${C.reset}
|
|
185
|
-
|
|
186
|
-
${C.bold}Watch (v1.5):${C.reset}
|
|
187
|
-
${C.cyan}npx vektor watch${C.reset} [path] Watch filesystem, auto-store changes
|
|
188
|
-
${C.cyan}npx vektor watch${C.reset} src/ ${C.dim}--ext ts,tsx${C.reset}
|
|
189
|
-
${C.cyan}npx vektor watch${C.reset} ${C.dim}--no-llm${C.reset} Heuristic summaries only
|
|
190
|
-
|
|
191
|
-
${C.bold}Sync (v1.5):${C.reset}
|
|
192
|
-
${C.cyan}npx vektor sync${C.reset} --host Listen for incoming sync
|
|
193
|
-
${C.cyan}npx vektor sync${C.reset} --connect <ip> Sync with host machine
|
|
194
|
-
${C.cyan}npx vektor sync${C.reset} --host ${C.dim}--pin 123456${C.reset}
|
|
195
|
-
|
|
196
|
-
${C.bold}Swarm (v1.5):${C.reset}
|
|
197
|
-
${C.cyan}npx vektor swarm${C.reset} "goal" Multi-agent coordination
|
|
198
|
-
${C.cyan}npx vektor swarm${C.reset} "goal" ${C.dim}--agents 4${C.reset}
|
|
199
|
-
${C.cyan}npx vektor swarm${C.reset} "goal" ${C.dim}--roles researcher,coder,reviewer${C.reset}
|
|
200
|
-
|
|
201
|
-
${C.bold}Utilities:${C.reset}
|
|
202
|
-
${C.cyan}npx vektor providers${C.reset} Test all API key connections
|
|
203
|
-
${C.cyan}npx vektor version${C.reset} Show version
|
|
204
|
-
${C.cyan}npx vektor help${C.reset} Show this help
|
|
205
|
-
|
|
206
|
-
${C.bold}Providers:${C.reset} ${C.dim}--provider claude|openai|groq|gemini|ollama${C.reset}
|
|
207
|
-
`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
211
|
-
|
|
212
|
-
function safeRequirePackageJson() {
|
|
213
|
-
const candidates = [
|
|
214
|
-
path.join(__dirname, 'package.json'),
|
|
215
|
-
path.join(__dirname, '..', 'package.json'),
|
|
216
|
-
];
|
|
217
|
-
for (const c of candidates) {
|
|
218
|
-
try { return require(c); } catch { /* skip */ }
|
|
219
|
-
}
|
|
220
|
-
return {};
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// ─── CLI dispatcher ───────────────────────────────────────────────────────────
|
|
224
|
-
|
|
225
|
-
async function main() {
|
|
226
|
-
const argv = process.argv.slice(2);
|
|
227
|
-
const cmd = argv[0];
|
|
228
|
-
|
|
229
|
-
if (!cmd || cmd === '--help' || cmd === '-h') {
|
|
230
|
-
printHelp();
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
if (cmd === '--version' || cmd === '-v') {
|
|
234
|
-
const pkg = safeRequirePackageJson();
|
|
235
|
-
console.log(`v${pkg.version || '1.5.0'}`);
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const factory = COMMANDS[cmd];
|
|
240
|
-
if (!factory) {
|
|
241
|
-
console.error(`Unknown command: ${cmd}\nRun 'npx vektor help' for usage.`);
|
|
242
|
-
process.exit(1);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
const handler = factory();
|
|
247
|
-
await handler(argv.slice(1));
|
|
248
|
-
} catch (err) {
|
|
249
|
-
console.error(`Error in '${cmd}': ${err.message}`);
|
|
250
|
-
if (process.env.DEBUG) console.error(err);
|
|
251
|
-
process.exit(1);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (require.main === module) {
|
|
256
|
-
main();
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
module.exports = { COMMANDS, main };
|
package/vektor-licence-prompt.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
/**
|
|
3
|
-
* vektor-licence-prompt.js — fixed for MCP mode (stderr exit, no stdout corruption)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const os = require('os');
|
|
9
|
-
const readline = require('readline');
|
|
10
|
-
|
|
11
|
-
const CACHE_DIR = path.join(os.homedir(), '.vektor');
|
|
12
|
-
const CACHE_FILE = path.join(CACHE_DIR, 'licence.json');
|
|
13
|
-
const PURCHASE_URL = 'https://vektormemory.com/product#pricing';
|
|
14
|
-
|
|
15
|
-
function _getCachedKey() {
|
|
16
|
-
try {
|
|
17
|
-
if (!fs.existsSync(CACHE_FILE)) return null;
|
|
18
|
-
const cache = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8'));
|
|
19
|
-
for (const entry of Object.values(cache)) {
|
|
20
|
-
if (entry?.licence_key && entry?.valid === true) return entry.licence_key;
|
|
21
|
-
}
|
|
22
|
-
return null;
|
|
23
|
-
} catch (_) { return null; }
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function _saveCachedKey(licenceKey) {
|
|
27
|
-
try {
|
|
28
|
-
if (!fs.existsSync(CACHE_DIR)) fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
29
|
-
let cache = {};
|
|
30
|
-
if (fs.existsSync(CACHE_FILE)) {
|
|
31
|
-
try { cache = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8')); } catch (_) {}
|
|
32
|
-
}
|
|
33
|
-
cache['_prompt_key'] = { licence_key: licenceKey, valid: true, saved_at: Date.now() };
|
|
34
|
-
fs.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
35
|
-
} catch (_) {}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function _prompt(question) {
|
|
39
|
-
return new Promise((resolve) => {
|
|
40
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
41
|
-
rl.question(question, (answer) => { rl.close(); resolve(answer.trim()); });
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function _printLicenceBanner() {
|
|
46
|
-
console.log('');
|
|
47
|
-
console.log(' ╔══════════════════════════════════════════════════════╗');
|
|
48
|
-
console.log(' ║ VEKTOR SLIPSTREAM — LICENCE REQUIRED ║');
|
|
49
|
-
console.log(' ╚══════════════════════════════════════════════════════╝');
|
|
50
|
-
console.log('');
|
|
51
|
-
console.log(' A licence key is required to use Vektor Slipstream.');
|
|
52
|
-
console.log(' Your key was emailed to you after purchase on Polar.');
|
|
53
|
-
console.log('');
|
|
54
|
-
console.log(' Purchase at: ' + PURCHASE_URL);
|
|
55
|
-
console.log('');
|
|
56
|
-
console.log(' Tip: Set VEKTOR_LICENCE_KEY env var to skip this prompt.');
|
|
57
|
-
console.log(' e.g. VEKTOR_LICENCE_KEY=YOUR-KEY node your-agent.js');
|
|
58
|
-
console.log('');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async function resolveAndValidateLicence(validateLicenceFn) {
|
|
62
|
-
|
|
63
|
-
// Priority 1 — env var (silent, MCP/server/CI safe)
|
|
64
|
-
const envKey = process.env.VEKTOR_LICENCE_KEY;
|
|
65
|
-
if (envKey && envKey.trim().length >= 8) {
|
|
66
|
-
await validateLicenceFn(envKey.trim());
|
|
67
|
-
_saveCachedKey(envKey.trim());
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Priority 2 — cached key
|
|
72
|
-
const cachedKey = _getCachedKey();
|
|
73
|
-
if (cachedKey) {
|
|
74
|
-
try {
|
|
75
|
-
await validateLicenceFn(cachedKey);
|
|
76
|
-
return;
|
|
77
|
-
} catch (e) {
|
|
78
|
-
process.stderr.write('\n [vektor] Cached licence key is no longer valid. Please re-enter.\n\n');
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Priority 3 — non-TTY (MCP, CI, piped) — stderr only, never stdout
|
|
83
|
-
if (!process.stdin.isTTY) {
|
|
84
|
-
process.stderr.write(
|
|
85
|
-
'\n[vektor] LICENCE REQUIRED — stdin is not interactive.\n' +
|
|
86
|
-
'[vektor] Set VEKTOR_LICENCE_KEY env var:\n' +
|
|
87
|
-
'[vektor] VEKTOR_LICENCE_KEY=YOUR-KEY node your-agent.js\n' +
|
|
88
|
-
'[vektor] Purchase at: ' + PURCHASE_URL + '\n\n'
|
|
89
|
-
);
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Priority 4 — interactive prompt (TTY only)
|
|
94
|
-
_printLicenceBanner();
|
|
95
|
-
|
|
96
|
-
let attempts = 0;
|
|
97
|
-
while (attempts < 3) {
|
|
98
|
-
const input = await _prompt(' Paste your licence key › ');
|
|
99
|
-
if (!input || input.length < 8) {
|
|
100
|
-
console.log(' ✗ No key entered. Try again.\n');
|
|
101
|
-
attempts++;
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
await validateLicenceFn(input);
|
|
106
|
-
_saveCachedKey(input);
|
|
107
|
-
console.log(' ✓ Licence validated — this machine is now activated.\n');
|
|
108
|
-
console.log(' Your key has been saved to ~/.vektor/licence.json');
|
|
109
|
-
console.log(' You will not be prompted again on this machine.\n');
|
|
110
|
-
return;
|
|
111
|
-
} catch (e) {
|
|
112
|
-
console.log('');
|
|
113
|
-
console.log(e.message);
|
|
114
|
-
attempts++;
|
|
115
|
-
if (attempts < 3) {
|
|
116
|
-
console.log(` Try again (${3 - attempts} attempt${3 - attempts === 1 ? '' : 's'} remaining)...\n`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
throw new Error(
|
|
122
|
-
'\n Licence validation failed after 3 attempts.\n' +
|
|
123
|
-
' Purchase at: ' + PURCHASE_URL + '\n' +
|
|
124
|
-
' Already purchased? Contact hello@vektormemory.com\n'
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
module.exports = { resolveAndValidateLicence };
|
package/vektor-licence.js
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
/**
|
|
3
|
-
* vektor-licence.js
|
|
4
|
-
* Licence validation for VEKTOR Slipstream.
|
|
5
|
-
* Validates against cached licence in ~/.vektor/licence.json
|
|
6
|
-
* or VEKTOR_LICENCE_KEY environment variable.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const os = require('os');
|
|
12
|
-
const crypto = require('crypto');
|
|
13
|
-
|
|
14
|
-
const CACHE_PATH = path.join(os.homedir(), '.vektor', 'licence.json');
|
|
15
|
-
const PURCHASE_URL = 'https://vektormemory.com/product#pricing';
|
|
16
|
-
|
|
17
|
-
// Known valid key format: UUID v4 uppercase
|
|
18
|
-
const KEY_RE = /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i;
|
|
19
|
-
|
|
20
|
-
function readCache() {
|
|
21
|
-
try {
|
|
22
|
-
if (!fs.existsSync(CACHE_PATH)) return null;
|
|
23
|
-
const raw = fs.readFileSync(CACHE_PATH, 'utf8');
|
|
24
|
-
return JSON.parse(raw);
|
|
25
|
-
} catch { return null; }
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function writeCache(key, data) {
|
|
29
|
-
try {
|
|
30
|
-
const dir = path.dirname(CACHE_PATH);
|
|
31
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
32
|
-
fs.writeFileSync(CACHE_PATH, JSON.stringify({ key, ...data, cachedAt: new Date().toISOString() }, null, 2), { mode: 0o600 });
|
|
33
|
-
} catch { /* ignore */ }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function getCachedKey() {
|
|
37
|
-
const cache = readCache();
|
|
38
|
-
return cache?.key || null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Validate a licence key.
|
|
43
|
-
* Checks format, then attempts Polar API verification.
|
|
44
|
-
* Falls back to cached validation if offline.
|
|
45
|
-
*/
|
|
46
|
-
async function validateLicence(key) {
|
|
47
|
-
if (!key) {
|
|
48
|
-
const envKey = process.env.VEKTOR_LICENCE_KEY;
|
|
49
|
-
const cached = readCache();
|
|
50
|
-
key = envKey || cached?.key;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (!key) {
|
|
54
|
-
throw new Error(
|
|
55
|
-
`\n\n VEKTOR SLIPSTREAM — Licence Required\n` +
|
|
56
|
-
` ─────────────────────────────────────\n` +
|
|
57
|
-
` No licence key found.\n\n` +
|
|
58
|
-
` Purchase at: ${PURCHASE_URL}\n` +
|
|
59
|
-
` Then run: npx vektor setup\n`
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Format check
|
|
64
|
-
if (!KEY_RE.test(key.trim())) {
|
|
65
|
-
throw new Error(`Invalid licence key format. Expected UUID format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const cleanKey = key.trim().toUpperCase();
|
|
69
|
-
|
|
70
|
-
// Check cache first (avoid network on every boot)
|
|
71
|
-
const cache = readCache();
|
|
72
|
-
if (cache?.key?.toUpperCase() === cleanKey && cache?.valid) {
|
|
73
|
-
// Re-validate online max once per 24hrs
|
|
74
|
-
const cachedAt = cache.cachedAt ? new Date(cache.cachedAt) : new Date(0);
|
|
75
|
-
const ageHours = (Date.now() - cachedAt.getTime()) / 3600000;
|
|
76
|
-
if (ageHours < 24) {
|
|
77
|
-
return { valid: true, key: cleanKey, source: 'cache' };
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Online validation via Polar
|
|
82
|
-
try {
|
|
83
|
-
const result = await _polarValidate(cleanKey);
|
|
84
|
-
writeCache(cleanKey, { valid: true, plan: result.plan, activatedAt: result.activatedAt });
|
|
85
|
-
return { valid: true, key: cleanKey, source: 'polar', ...result };
|
|
86
|
-
} catch (e) {
|
|
87
|
-
// If network fails but we have a cached valid key — allow offline use
|
|
88
|
-
if (cache?.key?.toUpperCase() === cleanKey && cache?.valid) {
|
|
89
|
-
return { valid: true, key: cleanKey, source: 'cache-offline' };
|
|
90
|
-
}
|
|
91
|
-
// New key that's never been validated — can't verify offline
|
|
92
|
-
if (e.code === 'ENOTFOUND' || e.code === 'ECONNREFUSED' || e.message?.includes('timeout')) {
|
|
93
|
-
throw new Error(`Licence validation failed: network unavailable. Connect to the internet to activate.`);
|
|
94
|
-
}
|
|
95
|
-
throw new Error(`Licence validation failed: ${e.message}`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async function _polarValidate(key) {
|
|
100
|
-
return new Promise((resolve, reject) => {
|
|
101
|
-
const https = require('https');
|
|
102
|
-
const body = JSON.stringify({ licenceKey: key });
|
|
103
|
-
const opts = {
|
|
104
|
-
hostname: 'api.polar.sh',
|
|
105
|
-
path: '/v1/users/license-keys/validate',
|
|
106
|
-
method: 'POST',
|
|
107
|
-
headers: {
|
|
108
|
-
'Content-Type': 'application/json',
|
|
109
|
-
'Content-Length': Buffer.byteLength(body),
|
|
110
|
-
'User-Agent': 'vektor-slipstream/1.1.13',
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const req = https.request(opts, res => {
|
|
115
|
-
let data = '';
|
|
116
|
-
res.setEncoding('utf8');
|
|
117
|
-
res.on('data', c => data += c);
|
|
118
|
-
res.on('end', () => {
|
|
119
|
-
try {
|
|
120
|
-
const json = JSON.parse(data);
|
|
121
|
-
if (res.statusCode === 200 && (json.valid || json.status === 'granted')) {
|
|
122
|
-
resolve({ plan: json.benefit?.description || 'slipstream', activatedAt: json.activated_at });
|
|
123
|
-
} else if (res.statusCode === 404 || json.valid === false) {
|
|
124
|
-
reject(new Error(`Invalid licence key. Purchase at: ${PURCHASE_URL}`));
|
|
125
|
-
} else {
|
|
126
|
-
// Unknown response — treat as valid if 2xx
|
|
127
|
-
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
128
|
-
resolve({ plan: 'slipstream', activatedAt: new Date().toISOString() });
|
|
129
|
-
} else {
|
|
130
|
-
reject(new Error(`Polar API returned ${res.statusCode}`));
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
} catch { reject(new Error('Invalid response from licence server')); }
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
req.setTimeout(8000, () => { req.destroy(); reject(Object.assign(new Error('timeout'), { code: 'ECONNREFUSED' })); });
|
|
138
|
-
req.on('error', reject);
|
|
139
|
-
req.write(body);
|
|
140
|
-
req.end();
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Activate a new licence key interactively and cache it.
|
|
146
|
-
*/
|
|
147
|
-
async function activateLicence(key) {
|
|
148
|
-
const result = await validateLicence(key);
|
|
149
|
-
writeCache(result.key, { valid: true, plan: result.plan, activatedAt: result.activatedAt });
|
|
150
|
-
return result;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Deactivate — clear the local cache.
|
|
155
|
-
*/
|
|
156
|
-
function deactivateLicence() {
|
|
157
|
-
try {
|
|
158
|
-
if (fs.existsSync(CACHE_PATH)) fs.unlinkSync(CACHE_PATH);
|
|
159
|
-
return true;
|
|
160
|
-
} catch { return false; }
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Get licence status without throwing.
|
|
165
|
-
*/
|
|
166
|
-
function getLicenceStatus() {
|
|
167
|
-
const cache = readCache();
|
|
168
|
-
const envKey = process.env.VEKTOR_LICENCE_KEY;
|
|
169
|
-
if (!cache?.key && !envKey) return { status: 'none' };
|
|
170
|
-
const key = cache?.key || envKey;
|
|
171
|
-
const cachedAt = cache?.cachedAt ? new Date(cache.cachedAt) : null;
|
|
172
|
-
const ageHours = cachedAt ? (Date.now() - cachedAt.getTime()) / 3600000 : null;
|
|
173
|
-
return {
|
|
174
|
-
status: cache?.valid ? 'active' : 'unknown',
|
|
175
|
-
key: key ? key.slice(0, 8) + '...' : null,
|
|
176
|
-
plan: cache?.plan || null,
|
|
177
|
-
cachedAt: cache?.cachedAt || null,
|
|
178
|
-
ageHours: ageHours ? Math.round(ageHours) : null,
|
|
179
|
-
source: envKey ? 'env' : 'cache',
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
module.exports = {
|
|
184
|
-
validateLicence,
|
|
185
|
-
activateLicence,
|
|
186
|
-
deactivateLicence,
|
|
187
|
-
getLicenceStatus,
|
|
188
|
-
getCachedKey,
|
|
189
|
-
readCache,
|
|
190
|
-
CACHE_PATH,
|
|
191
|
-
PURCHASE_URL,
|
|
192
|
-
};
|