satoridb 1.2.2 → 1.2.3
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/cli.js +220 -519
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -1,558 +1,259 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (char === ' ' && !inQuotes) {
|
|
43
|
-
if (current.trim()) {
|
|
44
|
-
args.push(current.trim());
|
|
45
|
-
current = '';
|
|
46
|
-
}
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
current += char;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (current.trim()) {
|
|
54
|
-
args.push(current.trim());
|
|
3
|
+
/**
|
|
4
|
+
* Satori Interactive CLI (Improved)
|
|
5
|
+
* - Command registry (easy to extend)
|
|
6
|
+
* - Robust arg parsing (quotes, escapes)
|
|
7
|
+
* - Fixed bugs (lecture args check, set_mindspace double call)
|
|
8
|
+
* - Better UX (history, tab completion, prompt context)
|
|
9
|
+
* - Centralized error handling
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const path = require("path");
|
|
13
|
+
const os = require("os");
|
|
14
|
+
const fs = require("fs");
|
|
15
|
+
const { spawnSync } = require("child_process");
|
|
16
|
+
const readline = require("readline");
|
|
17
|
+
const { Satori } = require("satori-node");
|
|
18
|
+
|
|
19
|
+
// -------------------------------
|
|
20
|
+
// Globals / State
|
|
21
|
+
// -------------------------------
|
|
22
|
+
const binName = os.platform() === "win32" ? "satori.exe" : "satori";
|
|
23
|
+
const binPath = path.join(os.homedir(), ".satori", "bin", binName);
|
|
24
|
+
|
|
25
|
+
let satori = null;
|
|
26
|
+
let session = {
|
|
27
|
+
host: null,
|
|
28
|
+
user: null,
|
|
29
|
+
password: null,
|
|
30
|
+
mindspace: null,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// -------------------------------
|
|
34
|
+
// Utils
|
|
35
|
+
// -------------------------------
|
|
36
|
+
function assertInstalled() {
|
|
37
|
+
if (!fs.existsSync(binPath)) {
|
|
38
|
+
console.error("❌ Satori binary not found. Reinstall the package.");
|
|
39
|
+
process.exit(1);
|
|
55
40
|
}
|
|
56
|
-
|
|
57
|
-
return args;
|
|
58
41
|
}
|
|
59
42
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// Intentar parsear como número
|
|
66
|
-
if (!isNaN(trimmed) && trimmed !== '') {
|
|
67
|
-
let numValue = Number(trimmed);
|
|
68
|
-
if (Number.isInteger(numValue)) return parseInt(trimmed);
|
|
69
|
-
return numValue;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Intentar parsear booleanos
|
|
73
|
-
if (trimmed.toLowerCase() === 'true') return true;
|
|
74
|
-
if (trimmed.toLowerCase() === 'false') return false;
|
|
75
|
-
|
|
76
|
-
// Intentar parsear JSON solo si empieza con { o [
|
|
77
|
-
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
|
|
78
|
-
try {
|
|
79
|
-
return JSON.parse(trimmed);
|
|
80
|
-
} catch (e) {
|
|
81
|
-
// Intentar evaluar como objeto JavaScript literal
|
|
82
|
-
try {
|
|
83
|
-
return new Function('return (' + trimmed + ')')();
|
|
84
|
-
} catch (evalError) {
|
|
85
|
-
console.log("⚠️ Could not parse as JSON or JavaScript object, returning original string");
|
|
86
|
-
return data;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return data;
|
|
43
|
+
function runBinary(args) {
|
|
44
|
+
assertInstalled();
|
|
45
|
+
const r = spawnSync(binPath, args, { stdio: "inherit" });
|
|
46
|
+
if (r.error) throw r.error;
|
|
92
47
|
}
|
|
93
48
|
|
|
94
|
-
function
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
let result = spawnSync(binPath, args, { stdio: "inherit" });
|
|
101
|
-
if (result.error) {
|
|
102
|
-
console.log("❌ Error executing:", result.error.message);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
49
|
+
function parseArgs(line) {
|
|
50
|
+
const re = /"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|(\S+)/g;
|
|
51
|
+
const out = [];
|
|
52
|
+
let m;
|
|
53
|
+
while ((m = re.exec(line))) out.push(m[1] ?? m[2] ?? m[3]);
|
|
54
|
+
return out.map(v => v.replace(/\\"/g, '"').replace(/\\'/g, "'"));
|
|
105
55
|
}
|
|
106
56
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (
|
|
113
|
-
|
|
57
|
+
function parseData(v) {
|
|
58
|
+
if (typeof v !== "string") return v;
|
|
59
|
+
const t = v.trim();
|
|
60
|
+
if (t === "true") return true;
|
|
61
|
+
if (t === "false") return false;
|
|
62
|
+
if (!isNaN(t) && t !== "") return Number(t);
|
|
63
|
+
if (t.startsWith("{") || t.startsWith("[")) {
|
|
64
|
+
try { return JSON.parse(t); } catch {}
|
|
114
65
|
}
|
|
115
|
-
return
|
|
66
|
+
return v;
|
|
116
67
|
}
|
|
117
68
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
console.log(`🔗 Connecting to ${host}...`);
|
|
121
|
-
// Store credentials for use in all commands
|
|
122
|
-
currentUser = user;
|
|
123
|
-
currentPassword = password;
|
|
124
|
-
satoriInstance = new Satori({ host, user, password });
|
|
125
|
-
await satoriInstance.connect();
|
|
126
|
-
console.log("✅ Successfully connected to SatoriDB");
|
|
127
|
-
return true;
|
|
128
|
-
} catch (error) {
|
|
129
|
-
console.log("❌ Error connecting:", error.message);
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
69
|
+
function requireConn() {
|
|
70
|
+
if (!satori) throw new Error("No active connection. Use: connect <host> [user] [password]");
|
|
132
71
|
}
|
|
133
72
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return;
|
|
140
|
-
|
|
141
|
-
case "exit":
|
|
142
|
-
case "quit":
|
|
143
|
-
console.log("👋 ¡Hasta luego!");
|
|
144
|
-
process.exit(0);
|
|
145
|
-
return;
|
|
146
|
-
|
|
147
|
-
case "clear":
|
|
148
|
-
clearScreen();
|
|
149
|
-
return;
|
|
150
|
-
|
|
151
|
-
case "mindspace":
|
|
152
|
-
let cmd = args[0];
|
|
153
|
-
if (cmd == "select"){
|
|
154
|
-
let mId = args[1];
|
|
155
|
-
currentMindspace = mId;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
73
|
+
function withCreds(p = {}) {
|
|
74
|
+
if (session.user) p.user = session.user;
|
|
75
|
+
if (session.password) p.password = session.password;
|
|
76
|
+
return p;
|
|
77
|
+
}
|
|
158
78
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
79
|
+
function promptLabel() {
|
|
80
|
+
return `satori${session.mindspace ? `:${session.mindspace}` : ""}> `;
|
|
81
|
+
}
|
|
164
82
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
let [putKey, replaceField, replaceValue, encryption_key_put] = args;
|
|
188
|
-
// Parsear JSON en el valor si es necesario
|
|
189
|
-
replaceValue = parseData(replaceValue);
|
|
190
|
-
await satoriInstance.put(addCredentials({ key: putKey, replace_field: replaceField, replace_value: replaceValue, encryption_key: encryption_key_put }));
|
|
191
|
-
console.log(`✅ Field updated: ${putKey}.${replaceField} = ${replaceValue}`);
|
|
192
|
-
break;
|
|
193
|
-
|
|
194
|
-
case "get":
|
|
195
|
-
if (args.length >= 1) {
|
|
196
|
-
let getKey = args[0];
|
|
197
|
-
let encryption_key_get = args[1] || null;
|
|
198
|
-
let result = await satoriInstance.get(addCredentials({ key: getKey, encryption_key: encryption_key_get }));
|
|
199
|
-
console.log(`📄 Data from ${getKey}:`, JSON.stringify(result, null, 2));
|
|
200
|
-
break;
|
|
201
|
-
} else {
|
|
202
|
-
let result = await satoriInstance.get(addCredentials({}));
|
|
203
|
-
console.log(`📄 Data from get:`, JSON.stringify(result, null, 2));
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
case "set_mindspace":
|
|
208
|
-
if (args.length == 1) {
|
|
209
|
-
let profile = args[0];
|
|
210
|
-
let res = null;
|
|
211
|
-
if (currentMindspace != null){
|
|
212
|
-
|
|
213
|
-
res = await satoriInstance.setMindspace({
|
|
214
|
-
config: profile,
|
|
215
|
-
mindspace_id: currentMindspace
|
|
216
|
-
})
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
res = await satoriInstance.setMindspace({
|
|
220
|
-
config: profile
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
console.log(`✅ Mindspace set: ${res.data}`);
|
|
224
|
-
break;
|
|
225
|
-
} else if (args.length == 2) {
|
|
226
|
-
let profile = args[0];
|
|
227
|
-
let mindspace_id = args[1];
|
|
228
|
-
|
|
229
|
-
let res = await satoriInstance.setMindspace({
|
|
230
|
-
mindspace_id: mindspace_id,
|
|
231
|
-
config: profile
|
|
232
|
-
})
|
|
233
|
-
console.log(`✅ Mindspace set: ${res.data}`);
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
case "delete_mindspace":
|
|
238
|
-
if (args.length == 1) {
|
|
239
|
-
let mid = args[0];
|
|
240
|
-
|
|
241
|
-
let res = await satoriInstance.deleteMindspace({
|
|
242
|
-
mindspace_id: mid
|
|
243
|
-
})
|
|
244
|
-
console.log(`✅ Mindspace deleted: ${mid}`);
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
case "chat":
|
|
249
|
-
if (args.length == 1) {
|
|
250
|
-
if(currentMindspace == null){
|
|
251
|
-
console.log("Select a mindspace with: mindspace select <mindspace_id>")
|
|
252
|
-
}
|
|
253
|
-
let mid = currentMindspace;
|
|
254
|
-
let message = args[0]
|
|
255
|
-
|
|
256
|
-
let res = await satoriInstance.chatMindspace({
|
|
257
|
-
mindspace_id: mid,
|
|
258
|
-
message: message
|
|
259
|
-
})
|
|
260
|
-
console.log(`${res.data}`);
|
|
261
|
-
break;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
case "lecture":
|
|
265
|
-
if(args == 1){
|
|
266
|
-
if(currentMindspace == null){
|
|
267
|
-
console.log("Select a mindspace with: mindspace select <mindspace_id>")
|
|
268
|
-
}
|
|
269
|
-
let mid = currentMindspace;
|
|
270
|
-
let message = args[0]
|
|
271
|
-
|
|
272
|
-
let res = await satoriInstance.lectureMindspace({
|
|
273
|
-
mindspace_id: mid,
|
|
274
|
-
corpus: message
|
|
275
|
-
})
|
|
276
|
-
console.log(`${res.data}`);
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
case "delete":
|
|
281
|
-
if (args.length < 1) {
|
|
282
|
-
console.log("❌ Uso: delete <key> [encryption_key]");
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
let deleteKey = args[0];
|
|
286
|
-
await satoriInstance.delete(addCredentials({ key: deleteKey }));
|
|
287
|
-
console.log(`🗑️ Key deleted: ${deleteKey}`);
|
|
288
|
-
break;
|
|
289
|
-
|
|
290
|
-
case "ask":
|
|
291
|
-
if (args.length < 1) {
|
|
292
|
-
console.log("❌ Usage: ask \"<question>\" [backend]");
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
let question = args[0];
|
|
296
|
-
let backend = args[1] || null;
|
|
297
|
-
let result = await satoriInstance.ask(addCredentials({ question, backend }));
|
|
298
|
-
console.log("🔍 Search results:", JSON.stringify(result, null, 2));
|
|
299
|
-
break;
|
|
300
|
-
|
|
301
|
-
case "query":
|
|
302
|
-
if (args.length < 1) {
|
|
303
|
-
console.log("❌ Usage: query \"<query>\" [backend]");
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
let query = args[0];
|
|
307
|
-
let backend_q = args[1] || null;
|
|
308
|
-
let result_q = await satoriInstance.query(addCredentials({ query, backend: backend_q }));
|
|
309
|
-
console.log("🔍 Search results:", JSON.stringify(result_q, null, 2));
|
|
310
|
-
break;
|
|
311
|
-
|
|
312
|
-
case "dfs":
|
|
313
|
-
if (args.length < 1) {
|
|
314
|
-
console.log("❌ Uso: dfs <node> [relation] [encryption_key]");
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
let node = args[0];
|
|
318
|
-
let relation = args[1] || null;
|
|
319
|
-
let encryption_key = args[2] || null;
|
|
320
|
-
let result_dfs = await satoriInstance.dfs(addCredentials({ node, relation, encryption_key }));
|
|
321
|
-
console.log("🔍 Search results:", JSON.stringify(result_dfs, null, 2));
|
|
322
|
-
break;
|
|
323
|
-
|
|
324
|
-
case "encrypt":
|
|
325
|
-
if (args.length < 1) {
|
|
326
|
-
console.log("❌ Uso: encrypt <key> [encryption_key]");
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
let key_encrypt = args[0];
|
|
330
|
-
let encryption_key_encrypt = args[1] || null;
|
|
331
|
-
let result_encrypt = await satoriInstance.encrypt(addCredentials({ key: key_encrypt, encryption_key: encryption_key_encrypt }));
|
|
332
|
-
console.log("🔍 Encryption results:", JSON.stringify(result_encrypt, null, 2));
|
|
333
|
-
break;
|
|
334
|
-
|
|
335
|
-
case "decrypt":
|
|
336
|
-
if (args.length < 1) {
|
|
337
|
-
console.log("❌ Uso: decrypt <key> [encryption_key]");
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
let key_decrypt = args[0];
|
|
341
|
-
let encryption_key_decrypt = args[1] || null;
|
|
342
|
-
let result_decrypt = await satoriInstance.decrypt(addCredentials({ key: key_decrypt, encryption_key: encryption_key_decrypt }));
|
|
343
|
-
console.log("🔍 Decryption results:", JSON.stringify(result_decrypt, null, 2));
|
|
344
|
-
break;
|
|
345
|
-
|
|
346
|
-
case "push":
|
|
347
|
-
if (args.length < 3) {
|
|
348
|
-
console.log("❌ Uso: push <key> <array> <value> [encryption_key]");
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
let key_push = args[0];
|
|
352
|
-
let array_push = args[1];
|
|
353
|
-
let value_push = args[2];
|
|
354
|
-
let encryption_key_push = args[3] || null;
|
|
355
|
-
// Parsear JSON en el valor si es necesario
|
|
356
|
-
value_push = parseData(value_push);
|
|
357
|
-
let result_push = await satoriInstance.push(addCredentials({ key: key_push, array: array_push, value: value_push, encryption_key: encryption_key_push }));
|
|
358
|
-
console.log("🔍 Insertion results:", JSON.stringify(result_push, null, 2));
|
|
359
|
-
break;
|
|
360
|
-
|
|
361
|
-
case "pop":
|
|
362
|
-
if (args.length < 2) {
|
|
363
|
-
console.log("❌ Uso: pop <key> <array> [encryption_key]");
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
let key_pop = args[0];
|
|
367
|
-
let array_pop = args[1];
|
|
368
|
-
let encryption_key_pop = args[2] || null;
|
|
369
|
-
let result_pop = await satoriInstance.pop(addCredentials({ key: key_pop, array: array_pop, encryption_key: encryption_key_pop }));
|
|
370
|
-
console.log("🔍 Removal results:", JSON.stringify(result_pop, null, 2));
|
|
371
|
-
break;
|
|
372
|
-
|
|
373
|
-
case "splice":
|
|
374
|
-
if (args.length < 2) {
|
|
375
|
-
console.log("❌ Uso: splice <key> <array> [encryption_key]");
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
let key_splice = args[0];
|
|
379
|
-
let array_splice = args[1];
|
|
380
|
-
let encryption_key_splice = args[2] || null;
|
|
381
|
-
let result_splice = await satoriInstance.splice(addCredentials({ key: key_splice, array: array_splice, encryption_key: encryption_key_splice }));
|
|
382
|
-
console.log("🔍 Insertion results:", JSON.stringify(result_splice, null, 2));
|
|
383
|
-
break;
|
|
384
|
-
|
|
385
|
-
case "remove":
|
|
386
|
-
if (args.length < 3) {
|
|
387
|
-
console.log("❌ Uso: remove <key> <array> <value> [encryption_key]");
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
let key_remove = args[0];
|
|
391
|
-
let array_remove = args[1];
|
|
392
|
-
let value_remove = args[2];
|
|
393
|
-
let encryption_key_remove = args[3] || null;
|
|
394
|
-
// Parsear JSON en el valor si es necesario
|
|
395
|
-
value_remove = parseData(value_remove);
|
|
396
|
-
let result_remove = await satoriInstance.remove(addCredentials({ key: key_remove, array: array_remove, value: value_remove, encryption_key: encryption_key_remove }));
|
|
397
|
-
console.log("🔍 Removal results:", JSON.stringify(result_remove, null, 2));
|
|
398
|
-
break;
|
|
399
|
-
|
|
400
|
-
case "set_vertex":
|
|
401
|
-
if (args.length < 2) {
|
|
402
|
-
console.log("❌ Uso: set_vertex <key> <vertex> [encryption_key]");
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
|
-
let key_set_vertex = args[0];
|
|
406
|
-
let vertex_set_vertex = args[1];
|
|
407
|
-
let encryption_key_set_vertex = args[2] || null;
|
|
408
|
-
// Parsear JSON en el vertex si es necesario
|
|
409
|
-
vertex_set_vertex = parseData(vertex_set_vertex);
|
|
410
|
-
let result_set_vertex = await satoriInstance.set_vertex(addCredentials({ key: key_set_vertex, vertex: vertex_set_vertex, encryption_key: encryption_key_set_vertex }));
|
|
411
|
-
console.log("🔍 Insertion results:", JSON.stringify(result_set_vertex, null, 2));
|
|
412
|
-
break;
|
|
413
|
-
|
|
414
|
-
case "get_vertex":
|
|
415
|
-
if (args.length < 1) {
|
|
416
|
-
console.log("❌ Uso: get_vertex <key> [encryption_key]");
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
let key_get_vertex = args[0];
|
|
420
|
-
let encryption_key_get_vertex = args[1] || null;
|
|
421
|
-
let result_get_vertex = await satoriInstance.get_vertex(addCredentials({ key: key_get_vertex, encryption_key: encryption_key_get_vertex }));
|
|
422
|
-
console.log("🔍 Insertion results:", JSON.stringify(result_get_vertex, null, 2));
|
|
423
|
-
break;
|
|
424
|
-
|
|
425
|
-
case "delete_vertex":
|
|
426
|
-
if (args.length < 2) {
|
|
427
|
-
console.log("❌ Uso: delete_vertex <key> <vertex> [encryption_key]");
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
let key_delete_vertex = args[0];
|
|
431
|
-
let vertex_delete_vertex = args[1];
|
|
432
|
-
let encryption_key_delete_vertex = args[2] || null;
|
|
433
|
-
// Parsear JSON en el vertex si es necesario
|
|
434
|
-
vertex_delete_vertex = parseData(vertex_delete_vertex);
|
|
435
|
-
let result_delete_vertex = await satoriInstance.delete_vertex(addCredentials({ key: key_delete_vertex, vertex: vertex_delete_vertex, encryption_key: encryption_key_delete_vertex }));
|
|
436
|
-
console.log("🔍 Removal results:", JSON.stringify(result_delete_vertex, null, 2));
|
|
437
|
-
break;
|
|
438
|
-
|
|
439
|
-
default:
|
|
440
|
-
console.log("❌ Command not recognized. Use 'help' to see available commands.");
|
|
83
|
+
// -------------------------------
|
|
84
|
+
// Commands Registry
|
|
85
|
+
// -------------------------------
|
|
86
|
+
const commands = {
|
|
87
|
+
help: {
|
|
88
|
+
desc: "Show help",
|
|
89
|
+
run() { showHelp(); }
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
exit: { run() { process.exit(0); } },
|
|
93
|
+
quit: { run() { process.exit(0); } },
|
|
94
|
+
clear: { run() { console.clear(); } },
|
|
95
|
+
|
|
96
|
+
connect: {
|
|
97
|
+
desc: "connect <host> [user] [password]",
|
|
98
|
+
async run([host, user = null, password = null]) {
|
|
99
|
+
if (!host) throw new Error("Usage: connect <host> [user] [password]");
|
|
100
|
+
console.log(`🔗 Connecting to ${host}...`);
|
|
101
|
+
satori = new Satori({ host, user, password });
|
|
102
|
+
await satori.connect();
|
|
103
|
+
Object.assign(session, { host, user, password });
|
|
104
|
+
console.log("✅ Connected");
|
|
441
105
|
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
mindspace: {
|
|
109
|
+
desc: "mindspace select <id>",
|
|
110
|
+
run([sub, id]) {
|
|
111
|
+
if (sub !== "select" || !id) throw new Error("Usage: mindspace select <id>");
|
|
112
|
+
session.mindspace = id;
|
|
113
|
+
console.log(`🧠 Mindspace selected: ${id}`);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
set: {
|
|
118
|
+
desc: "set <key> <data>",
|
|
119
|
+
async run([key, ...rest]) {
|
|
120
|
+
requireConn();
|
|
121
|
+
if (!key || !rest.length) throw new Error("Usage: set <key> <data>");
|
|
122
|
+
const data = parseData(rest.join(" "));
|
|
123
|
+
await satori.set(withCreds({ key, data }));
|
|
124
|
+
console.log(`✅ Saved: ${key}`);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
get: {
|
|
129
|
+
desc: "get <key>",
|
|
130
|
+
async run([key]) {
|
|
131
|
+
requireConn();
|
|
132
|
+
const r = await satori.get(withCreds(key ? { key } : {}));
|
|
133
|
+
console.log(JSON.stringify(r, null, 2));
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
put: {
|
|
138
|
+
desc: "put <key> <field> <value>",
|
|
139
|
+
async run([key, field, value]) {
|
|
140
|
+
requireConn();
|
|
141
|
+
if (!key || !field) throw new Error("Usage: put <key> <field> <value>");
|
|
142
|
+
await satori.put(withCreds({ key, replace_field: field, replace_value: parseData(value) }));
|
|
143
|
+
console.log("✅ Updated");
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
delete: {
|
|
148
|
+
desc: "delete <key>",
|
|
149
|
+
async run([key]) {
|
|
150
|
+
requireConn();
|
|
151
|
+
if (!key) throw new Error("Usage: delete <key>");
|
|
152
|
+
await satori.delete(withCreds({ key }));
|
|
153
|
+
console.log(`🗑️ Deleted: ${key}`);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
ask: {
|
|
158
|
+
desc: "ask \"<question>\"",
|
|
159
|
+
async run([q, backend = null]) {
|
|
160
|
+
requireConn();
|
|
161
|
+
if (!q) throw new Error("Usage: ask \"<question>\"");
|
|
162
|
+
const r = await satori.ask(withCreds({ question: q, backend }));
|
|
163
|
+
console.log(JSON.stringify(r, null, 2));
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
query: {
|
|
168
|
+
desc: "query \"<query>\"",
|
|
169
|
+
async run([q, backend = null]) {
|
|
170
|
+
requireConn();
|
|
171
|
+
if (!q) throw new Error("Usage: query \"<query>\"");
|
|
172
|
+
const r = await satori.query(withCreds({ query: q, backend }));
|
|
173
|
+
console.log(JSON.stringify(r, null, 2));
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
chat: {
|
|
178
|
+
desc: "chat \"<message>\"",
|
|
179
|
+
async run([msg]) {
|
|
180
|
+
requireConn();
|
|
181
|
+
if (!session.mindspace) throw new Error("Select a mindspace first");
|
|
182
|
+
const r = await satori.chatMindspace({ mindspace_id: session.mindspace, message: msg });
|
|
183
|
+
console.log(r.data);
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
lecture: {
|
|
188
|
+
desc: "lecture \"<corpus>\"",
|
|
189
|
+
async run([corpus]) {
|
|
190
|
+
requireConn();
|
|
191
|
+
if (!session.mindspace) throw new Error("Select a mindspace first");
|
|
192
|
+
const r = await satori.lectureMindspace({ mindspace_id: session.mindspace, corpus });
|
|
193
|
+
console.log(r.data);
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
};
|
|
446
197
|
|
|
198
|
+
// -------------------------------
|
|
199
|
+
// Help
|
|
200
|
+
// -------------------------------
|
|
447
201
|
function showHelp() {
|
|
448
|
-
console.log(
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
📝 Data operations:
|
|
455
|
-
set <key> <data> - Save data to a key
|
|
456
|
-
put <key> <field> <value> - Update a specific field
|
|
457
|
-
get <key> - Get data from a key
|
|
458
|
-
delete <key> - Delete a key
|
|
459
|
-
ask "<question>" [backend] - Ask a question
|
|
460
|
-
query "<query>" [backend] - Make a query
|
|
461
|
-
|
|
462
|
-
🛠️ Others:
|
|
463
|
-
help - Show this help
|
|
464
|
-
exit / quit - Exit the CLI
|
|
465
|
-
clear - Clear screen
|
|
466
|
-
|
|
467
|
-
💡 Examples:
|
|
468
|
-
set user:123 '{"name": "John", "age": 25}'
|
|
469
|
-
ask "What is the weather like today?"
|
|
470
|
-
query "Find all users with age > 25"
|
|
471
|
-
`);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
function clearScreen() {
|
|
475
|
-
console.clear();
|
|
202
|
+
console.log("\n📚 Commands:\n");
|
|
203
|
+
Object.entries(commands).forEach(([k, v]) => {
|
|
204
|
+
if (v.desc) console.log(` ${k.padEnd(12)} ${v.desc}`);
|
|
205
|
+
});
|
|
206
|
+
console.log("");
|
|
476
207
|
}
|
|
477
208
|
|
|
478
|
-
|
|
479
|
-
|
|
209
|
+
// -------------------------------
|
|
210
|
+
// Interactive Shell
|
|
211
|
+
// -------------------------------
|
|
212
|
+
async function startREPL() {
|
|
213
|
+
const rl = readline.createInterface({
|
|
480
214
|
input: process.stdin,
|
|
481
215
|
output: process.stdout,
|
|
482
|
-
|
|
216
|
+
historySize: 500,
|
|
217
|
+
completer(line) {
|
|
218
|
+
const hits = Object.keys(commands).filter(c => c.startsWith(line));
|
|
219
|
+
return [hits.length ? hits : Object.keys(commands), line];
|
|
220
|
+
}
|
|
483
221
|
});
|
|
484
222
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
console.log("💡 Use 'connect <host> [user] [password]' to start\n");
|
|
488
|
-
|
|
223
|
+
const refreshPrompt = () => rl.setPrompt(promptLabel());
|
|
224
|
+
refreshPrompt();
|
|
489
225
|
rl.prompt();
|
|
490
226
|
|
|
491
|
-
rl.on(
|
|
492
|
-
|
|
227
|
+
rl.on("line", async (line) => {
|
|
228
|
+
const parts = parseArgs(line.trim());
|
|
229
|
+
if (!parts.length) return rl.prompt();
|
|
493
230
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
231
|
+
const [cmd, ...args] = parts;
|
|
232
|
+
const entry = commands[cmd];
|
|
498
233
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
if (command === 'connect') {
|
|
505
|
-
if (args.length < 1) {
|
|
506
|
-
console.log("❌ Uso: connect <host> [user] [password]");
|
|
507
|
-
rl.prompt();
|
|
508
|
-
return;
|
|
509
|
-
}
|
|
510
|
-
let host = args[0];
|
|
511
|
-
let user = args[1] || null;
|
|
512
|
-
let password = args[2] || null;
|
|
513
|
-
let success = await connectToSatori(host, user, password);
|
|
514
|
-
if (success) {
|
|
515
|
-
console.log("✅ Now you can use commands like 'set', 'get', 'put', etc.");
|
|
516
|
-
}
|
|
517
|
-
} else {
|
|
518
|
-
await executeCommand(command, args);
|
|
234
|
+
try {
|
|
235
|
+
if (!entry) throw new Error("Unknown command. Type 'help'.");
|
|
236
|
+
await entry.run(args);
|
|
237
|
+
} catch (e) {
|
|
238
|
+
console.error("❌", e.message);
|
|
519
239
|
}
|
|
520
240
|
|
|
241
|
+
refreshPrompt();
|
|
521
242
|
rl.prompt();
|
|
522
243
|
});
|
|
523
|
-
|
|
524
|
-
rl.on('close', () => {
|
|
525
|
-
console.log('\n👋 Goodbye!');
|
|
526
|
-
process.exit(0);
|
|
527
|
-
});
|
|
528
244
|
}
|
|
529
245
|
|
|
530
|
-
|
|
246
|
+
// -------------------------------
|
|
247
|
+
// Entry
|
|
248
|
+
// -------------------------------
|
|
249
|
+
const argv = process.argv.slice(2);
|
|
531
250
|
|
|
532
|
-
if (
|
|
533
|
-
|
|
251
|
+
if (argv[0] === "run") {
|
|
252
|
+
runBinary(argv.slice(1));
|
|
253
|
+
} else if (argv[0] === "update") {
|
|
534
254
|
require("./postinstall");
|
|
535
|
-
} else if (
|
|
536
|
-
run(args.slice(1));
|
|
537
|
-
} else if (args[0] === "connect") {
|
|
538
|
-
if (args.length < 2) {
|
|
539
|
-
console.log("❌ Uso: satoridb connect <host> [user] [password]");
|
|
540
|
-
process.exit(1);
|
|
541
|
-
}
|
|
542
|
-
let host = args[1];
|
|
543
|
-
let user = args[2] || null;
|
|
544
|
-
let password = args[3] || null;
|
|
545
|
-
connectToSatori(host, user, password).then(success => {
|
|
546
|
-
if (success) {
|
|
547
|
-
startInteractiveCLI();
|
|
548
|
-
} else {
|
|
549
|
-
process.exit(1);
|
|
550
|
-
}
|
|
551
|
-
});
|
|
552
|
-
} else if (args[0] === "verify") {
|
|
553
|
-
console.log("🔍 Verifying installation...");
|
|
255
|
+
} else if (argv[0] === "verify") {
|
|
554
256
|
require("./verify-install");
|
|
555
257
|
} else {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
258
|
+
startREPL();
|
|
259
|
+
}
|