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.
Files changed (2) hide show
  1. package/cli.js +220 -519
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -1,558 +1,259 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- let path = require("path");
4
- let os = require("os");
5
- let fs = require("fs");
6
- let { spawnSync } = require("child_process");
7
- let readline = require("readline");
8
- let { Satori } = require("satori-node");
9
-
10
- let binName = os.platform() === "win32" ? "satori.exe" : "satori";
11
- let binPath = path.join(os.homedir(), ".satori", "bin", binName);
12
-
13
- let nl = true;
14
-
15
- let satoriInstance = null;
16
- let currentUser = null;
17
- let currentPassword = null;
18
- let currentMindspace = null;
19
-
20
- // Function to parse arguments with quoted strings support
21
- function parseArguments(line) {
22
- let args = [];
23
- let current = '';
24
- let inQuotes = false;
25
- let quoteChar = '';
26
-
27
- for (let i = 0; i < line.length; i++) {
28
- let char = line[i];
29
-
30
- if ((char === '"' || char === "'") && !inQuotes) {
31
- inQuotes = true;
32
- quoteChar = char;
33
- continue;
34
- }
35
-
36
- if (char === quoteChar && inQuotes) {
37
- inQuotes = false;
38
- quoteChar = '';
39
- continue;
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
- // Función helper para parsear JSON, arrays y tipos básicos
61
- function parseData(data) {
62
- if (typeof data === 'string') {
63
- let trimmed = data.trim();
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 run(args) {
95
- if (!fs.existsSync(binPath)) {
96
- console.log("❌ Satori is not installed. Try reinstalling the package.");
97
- process.exit(1);
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
- // Helper function to add user and password to command parameters if defined
108
- function addCredentials(params) {
109
- if (currentUser !== null && currentUser !== undefined) {
110
- params.username = currentUser;
111
- }
112
- if (currentPassword !== null && currentPassword !== undefined) {
113
- params.password = currentPassword;
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 params;
66
+ return v;
116
67
  }
117
68
 
118
- async function connectToSatori(host, user = null, password = null) {
119
- try {
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
- async function executeCommand(command, args) {
135
- // Comandos que no requieren conexión
136
- switch (command) {
137
- case "help":
138
- showHelp();
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
- // Commands that require connection
160
- if (!satoriInstance) {
161
- console.log("❌ No active connection. Use 'connect <host> [user] [password]' first.");
162
- return;
163
- }
79
+ function promptLabel() {
80
+ return `satori${session.mindspace ? `:${session.mindspace}` : ""}> `;
81
+ }
164
82
 
165
- try {
166
- switch (command) {
167
- case "set":
168
- if (args.length < 2) {
169
- console.log("❌ Uso: set <key> <data>");
170
- return;
171
- }
172
- let key = args[0];
173
- let data = args.slice(1).join(' '); // Unir todos los argumentos restantes
174
-
175
- // Parsear JSON si es necesario
176
- data = parseData(data);
177
-
178
- await satoriInstance.set(addCredentials({ key, data }));
179
- console.log(`✅ Data saved in key: ${key}`);
180
- break;
181
-
182
- case "put":
183
- if (args.length < 3) {
184
- console.log("❌ Uso: put <key> <replace_field> <replace_value>");
185
- return;
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
- } catch (error) {
443
- console.log("❌ Error executing command:", error.message);
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
- 📚 Available commands:
450
-
451
- 🔗 Connection:
452
- connect <host> [user] [password] - Connect to SatoriDB
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
- async function startInteractiveCLI() {
479
- let rl = readline.createInterface({
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
- prompt: 'satori> '
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
- console.log("🚀 SatoriDB Interactive CLI");
486
- console.log("📝 Type 'help' to see available commands");
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('line', async (line) => {
492
- let trimmedLine = line.trim();
227
+ rl.on("line", async (line) => {
228
+ const parts = parseArgs(line.trim());
229
+ if (!parts.length) return rl.prompt();
493
230
 
494
- if (trimmedLine === '') {
495
- rl.prompt();
496
- return;
497
- }
231
+ const [cmd, ...args] = parts;
232
+ const entry = commands[cmd];
498
233
 
499
- // Parse arguments with quoted strings support
500
- let parts = parseArguments(trimmedLine);
501
- let command = parts[0];
502
- let args = parts.slice(1);
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
- let args = process.argv.slice(2);
246
+ // -------------------------------
247
+ // Entry
248
+ // -------------------------------
249
+ const argv = process.argv.slice(2);
531
250
 
532
- if (args[0] === "update") {
533
- console.log("🔄 Ejecutando actualización...");
251
+ if (argv[0] === "run") {
252
+ runBinary(argv.slice(1));
253
+ } else if (argv[0] === "update") {
534
254
  require("./postinstall");
535
- } else if (args[0] === "run") {
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
- // If no arguments or unrecognized arguments, start interactive CLI
557
- startInteractiveCLI();
558
- }
258
+ startREPL();
259
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "satoridb",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Install satori",
5
5
  "bin": {
6
6
  "satoridb": "./cli.js"