satoridb 1.2.2 → 1.2.4
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 +238 -518
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -1,558 +1,278 @@
|
|
|
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
|
-
}
|
|
43
|
+
function runBinary(args) {
|
|
44
|
+
assertInstalled();
|
|
45
|
+
const r = spawnSync(binPath, args, { stdio: "inherit" });
|
|
46
|
+
if (r.error) throw r.error;
|
|
47
|
+
}
|
|
71
48
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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;
|
|
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, "'"));
|
|
92
55
|
}
|
|
93
56
|
|
|
94
|
-
function
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
|
|
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 {}
|
|
98
65
|
}
|
|
66
|
+
return v;
|
|
67
|
+
}
|
|
99
68
|
|
|
100
|
-
|
|
101
|
-
if (
|
|
102
|
-
console.log("❌ Error executing:", result.error.message);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
69
|
+
function requireConn() {
|
|
70
|
+
if (!satori) throw new Error("No active connection. Use: connect <host> [user] [password]");
|
|
105
71
|
}
|
|
106
72
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
if (currentPassword !== null && currentPassword !== undefined) {
|
|
113
|
-
params.password = currentPassword;
|
|
114
|
-
}
|
|
115
|
-
return params;
|
|
73
|
+
function withCreds(p = {}) {
|
|
74
|
+
if (session.user) p.user = session.user;
|
|
75
|
+
if (session.password) p.password = session.password;
|
|
76
|
+
return p;
|
|
116
77
|
}
|
|
117
78
|
|
|
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
|
-
}
|
|
79
|
+
function promptLabel() {
|
|
80
|
+
return `satori${session.mindspace ? `:${session.mindspace}` : ""}> `;
|
|
132
81
|
}
|
|
133
82
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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");
|
|
105
|
+
}
|
|
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
|
+
set_mindspace: {
|
|
197
|
+
desc: "set_mindspace <config> [mindspace_id]",
|
|
198
|
+
async run([config, mindspace_id]) {
|
|
199
|
+
requireConn();
|
|
200
|
+
if (!config) throw new Error("Usage: set_mindspace <config> [mindspace_id]");
|
|
150
201
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
console.log(
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
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.");
|
|
202
|
+
|
|
203
|
+
const payload = { config };
|
|
204
|
+
if (mindspace_id) payload.mindspace_id = mindspace_id;
|
|
205
|
+
else if (session.mindspace) payload.mindspace_id = session.mindspace;
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
const res = await satori.setMindspace(payload);
|
|
209
|
+
if (payload.mindspace_id) session.mindspace = payload.mindspace_id;
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
console.log(`🧠 Mindspace configured: ${payload.mindspace_id ?? res.data}`);
|
|
441
213
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
}
|
|
214
|
+
},
|
|
215
|
+
};
|
|
446
216
|
|
|
217
|
+
// -------------------------------
|
|
218
|
+
// Help
|
|
219
|
+
// -------------------------------
|
|
447
220
|
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();
|
|
221
|
+
console.log("\n📚 Commands:\n");
|
|
222
|
+
Object.entries(commands).forEach(([k, v]) => {
|
|
223
|
+
if (v.desc) console.log(` ${k.padEnd(12)} ${v.desc}`);
|
|
224
|
+
});
|
|
225
|
+
console.log("");
|
|
476
226
|
}
|
|
477
227
|
|
|
478
|
-
|
|
479
|
-
|
|
228
|
+
// -------------------------------
|
|
229
|
+
// Interactive Shell
|
|
230
|
+
// -------------------------------
|
|
231
|
+
async function startREPL() {
|
|
232
|
+
const rl = readline.createInterface({
|
|
480
233
|
input: process.stdin,
|
|
481
234
|
output: process.stdout,
|
|
482
|
-
|
|
235
|
+
historySize: 500,
|
|
236
|
+
completer(line) {
|
|
237
|
+
const hits = Object.keys(commands).filter(c => c.startsWith(line));
|
|
238
|
+
return [hits.length ? hits : Object.keys(commands), line];
|
|
239
|
+
}
|
|
483
240
|
});
|
|
484
241
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
console.log("💡 Use 'connect <host> [user] [password]' to start\n");
|
|
488
|
-
|
|
242
|
+
const refreshPrompt = () => rl.setPrompt(promptLabel());
|
|
243
|
+
refreshPrompt();
|
|
489
244
|
rl.prompt();
|
|
490
245
|
|
|
491
|
-
rl.on(
|
|
492
|
-
|
|
246
|
+
rl.on("line", async (line) => {
|
|
247
|
+
const parts = parseArgs(line.trim());
|
|
248
|
+
if (!parts.length) return rl.prompt();
|
|
493
249
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
250
|
+
const [cmd, ...args] = parts;
|
|
251
|
+
const entry = commands[cmd];
|
|
498
252
|
|
|
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);
|
|
253
|
+
try {
|
|
254
|
+
if (!entry) throw new Error("Unknown command. Type 'help'.");
|
|
255
|
+
await entry.run(args);
|
|
256
|
+
} catch (e) {
|
|
257
|
+
console.error("❌", e.message);
|
|
519
258
|
}
|
|
520
259
|
|
|
260
|
+
refreshPrompt();
|
|
521
261
|
rl.prompt();
|
|
522
262
|
});
|
|
523
|
-
|
|
524
|
-
rl.on('close', () => {
|
|
525
|
-
console.log('\n👋 Goodbye!');
|
|
526
|
-
process.exit(0);
|
|
527
|
-
});
|
|
528
263
|
}
|
|
529
264
|
|
|
530
|
-
|
|
265
|
+
// -------------------------------
|
|
266
|
+
// Entry
|
|
267
|
+
// -------------------------------
|
|
268
|
+
const argv = process.argv.slice(2);
|
|
531
269
|
|
|
532
|
-
if (
|
|
533
|
-
|
|
270
|
+
if (argv[0] === "run") {
|
|
271
|
+
runBinary(argv.slice(1));
|
|
272
|
+
} else if (argv[0] === "update") {
|
|
534
273
|
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...");
|
|
274
|
+
} else if (argv[0] === "verify") {
|
|
554
275
|
require("./verify-install");
|
|
555
276
|
} else {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
277
|
+
startREPL();
|
|
278
|
+
}
|