forbocai 0.1.1 → 0.2.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/dist/cli.js +533 -89
- package/dist/cli.mjs +533 -89
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -27,39 +27,140 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var import_http = __toESM(require("http"));
|
|
28
28
|
var import_https = __toESM(require("https"));
|
|
29
29
|
var readline = __toESM(require("readline"));
|
|
30
|
+
var fs = __toESM(require("fs"));
|
|
31
|
+
var path = __toESM(require("path"));
|
|
32
|
+
var VERSION = "0.2.0";
|
|
30
33
|
var DEFAULT_API_URL = "https://forbocai-api.onrender.com";
|
|
31
|
-
var
|
|
34
|
+
var CONFIG_PATH = path.join(process.env.HOME || ".", ".forbocai.json");
|
|
35
|
+
var config = {};
|
|
36
|
+
try {
|
|
37
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
38
|
+
config = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
var API_URL = process.env.FORBOC_API_URL || config.apiUrl || DEFAULT_API_URL;
|
|
32
43
|
var args = process.argv.slice(2);
|
|
33
44
|
var command = args[0];
|
|
34
45
|
var subcommand = args[1];
|
|
35
|
-
var
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
46
|
+
var arg3 = args[2];
|
|
47
|
+
var arg4 = args[3];
|
|
48
|
+
var routes = {
|
|
49
|
+
// Meta
|
|
50
|
+
"version": () => console.log(`ForbocAI SDK v${VERSION}`),
|
|
51
|
+
"doctor": doctor,
|
|
52
|
+
// Config
|
|
53
|
+
"config_set": () => configSet(subcommand, arg3),
|
|
54
|
+
"config_get": () => configGet(subcommand),
|
|
55
|
+
"config_list": configList,
|
|
56
|
+
// API
|
|
57
|
+
"api_status": checkApiStatus,
|
|
58
|
+
// Cortex
|
|
59
|
+
"cortex_models": listModels,
|
|
60
|
+
"cortex_init": () => cortexInit(arg3),
|
|
61
|
+
// Agent
|
|
62
|
+
"agent_create": () => createAgent(arg3),
|
|
63
|
+
"agent_list": listAgents,
|
|
64
|
+
"agent_chat": () => chatWithAgent(arg3),
|
|
65
|
+
"agent_delete": () => deleteAgent(arg3),
|
|
66
|
+
"agent_state": () => agentState(arg3),
|
|
67
|
+
"agent_process": () => agentProcess(arg3, arg4),
|
|
68
|
+
"agent_update": () => agentUpdate(arg3, args.slice(3)),
|
|
69
|
+
// Soul
|
|
70
|
+
"soul_export": () => exportSoul(arg3),
|
|
71
|
+
"soul_import": () => importSoul(arg3),
|
|
72
|
+
"soul_chat": () => chatWithSoul(arg3),
|
|
73
|
+
"soul_list": soulList,
|
|
74
|
+
"soul_verify": () => soulVerify(arg3),
|
|
75
|
+
// Ghost
|
|
76
|
+
"ghost_run": () => runGhost(arg3),
|
|
77
|
+
"ghost_status": () => ghostStatus(arg3),
|
|
78
|
+
"ghost_results": () => ghostResults(arg3),
|
|
79
|
+
"ghost_stop": () => ghostStop(arg3),
|
|
80
|
+
"ghost_history": ghostHistory,
|
|
81
|
+
// Memory
|
|
82
|
+
"memory_list": () => memoryList(arg3),
|
|
83
|
+
"memory_recall": () => memoryRecall(arg3, arg4),
|
|
84
|
+
"memory_store": () => memoryStore(arg3, args.slice(3).join(" ")),
|
|
85
|
+
"memory_clear": () => memoryClear(arg3),
|
|
86
|
+
"memory_export": () => memoryExport(arg3),
|
|
87
|
+
// Bridge
|
|
88
|
+
"bridge_validate": () => bridgeValidate(arg3),
|
|
89
|
+
"bridge_rules": bridgeRules
|
|
90
|
+
};
|
|
91
|
+
var routeKey = subcommand ? `${command}_${subcommand}` : command;
|
|
92
|
+
if (routes[routeKey]) {
|
|
93
|
+
routes[routeKey]();
|
|
94
|
+
} else if (command === "config" && subcommand === "set") {
|
|
95
|
+
configSet(arg3, arg4);
|
|
96
|
+
} else if (command === "config" && subcommand === "get") {
|
|
97
|
+
configGet(arg3);
|
|
60
98
|
} else {
|
|
61
99
|
printUsage();
|
|
62
100
|
}
|
|
101
|
+
function doctor() {
|
|
102
|
+
console.log(`
|
|
103
|
+
\x1B[36m\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`);
|
|
104
|
+
console.log(`\u2551 ForbocAI Doctor \u2551`);
|
|
105
|
+
console.log(`\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m
|
|
106
|
+
`);
|
|
107
|
+
console.log(`Checking system...
|
|
108
|
+
`);
|
|
109
|
+
const nodeVersion = process.version;
|
|
110
|
+
const nodeMajor = parseInt(nodeVersion.slice(1).split(".")[0]);
|
|
111
|
+
const nodeOk = nodeMajor >= 18;
|
|
112
|
+
console.log(`${nodeOk ? "\u2713" : "\u2717"} Node.js: ${nodeVersion} ${nodeOk ? "" : "(requires 18+)"}`);
|
|
113
|
+
console.log(`\u2713 API URL: ${API_URL}`);
|
|
114
|
+
const configExists = fs.existsSync(CONFIG_PATH);
|
|
115
|
+
console.log(`${configExists ? "\u2713" : "\u25CB"} Config: ${configExists ? CONFIG_PATH : "Not configured (using defaults)"}`);
|
|
116
|
+
console.log(`
|
|
117
|
+
Testing API connection...`);
|
|
118
|
+
const client = API_URL.startsWith("https") ? import_https.default : import_http.default;
|
|
119
|
+
client.get(`${API_URL}/status`, (res) => {
|
|
120
|
+
if (res.statusCode === 200) {
|
|
121
|
+
console.log(`\x1B[32m\u2713 API: Online\x1B[0m`);
|
|
122
|
+
} else {
|
|
123
|
+
console.log(`\x1B[31m\u2717 API: Returned ${res.statusCode}\x1B[0m`);
|
|
124
|
+
}
|
|
125
|
+
console.log(`
|
|
126
|
+
\x1B[32mDiagnosis complete.\x1B[0m`);
|
|
127
|
+
}).on("error", (e) => {
|
|
128
|
+
console.log(`\x1B[31m\u2717 API: ${e.message}\x1B[0m`);
|
|
129
|
+
console.log(`
|
|
130
|
+
\x1B[33mTip: Check your internet connection or API URL\x1B[0m`);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function configSet(key, value) {
|
|
134
|
+
if (!key || !value) {
|
|
135
|
+
console.error("Usage: forbocai config set <key> <value>");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
config[key] = value;
|
|
139
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
140
|
+
console.log(`> Set ${key} = ${value}`);
|
|
141
|
+
}
|
|
142
|
+
function configGet(key) {
|
|
143
|
+
if (!key) {
|
|
144
|
+
console.error("Usage: forbocai config get <key>");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
console.log(config[key] || `(not set)`);
|
|
148
|
+
}
|
|
149
|
+
function configList() {
|
|
150
|
+
console.log(`
|
|
151
|
+
Configuration (${CONFIG_PATH}):
|
|
152
|
+
`);
|
|
153
|
+
if (Object.keys(config).length === 0) {
|
|
154
|
+
console.log(" (no configuration set)");
|
|
155
|
+
} else {
|
|
156
|
+
for (const [key, value] of Object.entries(config)) {
|
|
157
|
+
console.log(` ${key}: ${value}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
console.log(`
|
|
161
|
+
Defaults:`);
|
|
162
|
+
console.log(` apiUrl: ${DEFAULT_API_URL}`);
|
|
163
|
+
}
|
|
63
164
|
function checkApiStatus() {
|
|
64
165
|
console.log(`> Connecting to Neuro-Symbolic Grid...`);
|
|
65
166
|
console.log(`> API: ${API_URL}`);
|
|
@@ -79,14 +180,53 @@ function checkApiStatus() {
|
|
|
79
180
|
console.log(`> Version: ${json.version}`);
|
|
80
181
|
} catch (e) {
|
|
81
182
|
console.error("> Error: Invalid JSON response from server.");
|
|
82
|
-
console.log(data.substring(0, 100) + "...");
|
|
83
183
|
}
|
|
84
184
|
});
|
|
85
185
|
}).on("error", (e) => {
|
|
86
186
|
console.error(`> Error: ${e.message}`);
|
|
87
|
-
console.log(`> Hint:
|
|
187
|
+
console.log(`> Hint: Run 'forbocai doctor' to diagnose`);
|
|
88
188
|
});
|
|
89
189
|
}
|
|
190
|
+
async function listModels() {
|
|
191
|
+
console.log(`> Fetching available models...`);
|
|
192
|
+
try {
|
|
193
|
+
const res = await fetch(`${API_URL}/cortex/models`);
|
|
194
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
195
|
+
const data = await res.json();
|
|
196
|
+
console.log(`
|
|
197
|
+
Available Models:
|
|
198
|
+
`);
|
|
199
|
+
data.forEach((model) => {
|
|
200
|
+
console.log(` \x1B[36m${model.id || model.modelId}\x1B[0m`);
|
|
201
|
+
console.log(` Name: ${model.name || model.modelName}`);
|
|
202
|
+
console.log(` Parameters: ${((model.parameters || 0) / 1e6).toFixed(0)}M`);
|
|
203
|
+
console.log(` Size: ${model.downloadSize || "N/A"}`);
|
|
204
|
+
console.log(` Capabilities: ${model.capabilities?.join(", ") || "N/A"}`);
|
|
205
|
+
console.log("");
|
|
206
|
+
});
|
|
207
|
+
} catch (e) {
|
|
208
|
+
console.error(`> Failed to list models:`, e);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function cortexInit(model) {
|
|
212
|
+
const modelId = model || "smollm2-135m";
|
|
213
|
+
console.log(`> Initializing Cortex with model: ${modelId}...`);
|
|
214
|
+
try {
|
|
215
|
+
const res = await fetch(`${API_URL}/cortex/init`, {
|
|
216
|
+
method: "POST",
|
|
217
|
+
headers: { "Content-Type": "application/json" },
|
|
218
|
+
body: JSON.stringify({ model: modelId })
|
|
219
|
+
});
|
|
220
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
221
|
+
const data = await res.json();
|
|
222
|
+
console.log(`> Cortex Initialized!`);
|
|
223
|
+
console.log(`> Instance ID: \x1B[32m${data.cortexId || data.id}\x1B[0m`);
|
|
224
|
+
console.log(`> Model: ${data.model || modelId}`);
|
|
225
|
+
console.log(`> Status: ${data.status || "ready"}`);
|
|
226
|
+
} catch (e) {
|
|
227
|
+
console.error(`> Failed to initialize Cortex:`, e);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
90
230
|
async function createAgent(persona) {
|
|
91
231
|
const p = persona || "Default Persona";
|
|
92
232
|
console.log(`> Creating Agent with persona: "${p}"...`);
|
|
@@ -107,13 +247,10 @@ async function createAgent(persona) {
|
|
|
107
247
|
async function listAgents() {
|
|
108
248
|
console.log(`> Listing agents...`);
|
|
109
249
|
try {
|
|
110
|
-
const res = await fetch(`${API_URL}/agents
|
|
111
|
-
method: "GET",
|
|
112
|
-
headers: { "Content-Type": "application/json" }
|
|
113
|
-
});
|
|
250
|
+
const res = await fetch(`${API_URL}/agents`);
|
|
114
251
|
if (!res.ok) throw new Error(res.statusText);
|
|
115
252
|
const data = await res.json();
|
|
116
|
-
if (data.length === 0) {
|
|
253
|
+
if (!data || data.length === 0) {
|
|
117
254
|
console.log(`> No agents found.`);
|
|
118
255
|
return;
|
|
119
256
|
}
|
|
@@ -121,7 +258,7 @@ async function listAgents() {
|
|
|
121
258
|
`);
|
|
122
259
|
data.forEach((agent, i) => {
|
|
123
260
|
console.log(` ${i + 1}. \x1B[32m${agent.agentId}\x1B[0m`);
|
|
124
|
-
console.log(` Persona: ${agent.persona
|
|
261
|
+
console.log(` Persona: ${(agent.persona || "").substring(0, 50)}...`);
|
|
125
262
|
console.log(` Mood: ${agent.mood || "unknown"}`);
|
|
126
263
|
console.log("");
|
|
127
264
|
});
|
|
@@ -136,16 +273,108 @@ async function deleteAgent(agentId) {
|
|
|
136
273
|
}
|
|
137
274
|
console.log(`> Deleting Agent: ${agentId}...`);
|
|
138
275
|
try {
|
|
139
|
-
const res = await fetch(`${API_URL}/agents/${agentId}`, {
|
|
140
|
-
method: "DELETE",
|
|
141
|
-
headers: { "Content-Type": "application/json" }
|
|
142
|
-
});
|
|
276
|
+
const res = await fetch(`${API_URL}/agents/${agentId}`, { method: "DELETE" });
|
|
143
277
|
if (!res.ok) throw new Error(res.statusText);
|
|
144
278
|
console.log(`> Agent \x1B[31mdeleted\x1B[0m: ${agentId}`);
|
|
145
279
|
} catch (e) {
|
|
146
280
|
console.error(`> Failed to delete agent:`, e);
|
|
147
281
|
}
|
|
148
282
|
}
|
|
283
|
+
async function agentState(agentId) {
|
|
284
|
+
if (!agentId) {
|
|
285
|
+
console.error("Error: Agent ID required");
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
console.log(`> Fetching state for Agent: ${agentId}...`);
|
|
289
|
+
try {
|
|
290
|
+
const res = await fetch(`${API_URL}/agents/${agentId}/state`);
|
|
291
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
292
|
+
const data = await res.json();
|
|
293
|
+
console.log(`
|
|
294
|
+
Agent State:
|
|
295
|
+
`);
|
|
296
|
+
console.log(` Mood: \x1B[33m${data.stateMood || data.mood || "unknown"}\x1B[0m`);
|
|
297
|
+
if (data.stateInventory || data.inventory) {
|
|
298
|
+
const inv = data.stateInventory || data.inventory;
|
|
299
|
+
console.log(` Inventory: ${inv.length > 0 ? inv.join(", ") : "(empty)"}`);
|
|
300
|
+
}
|
|
301
|
+
if (data.stateSkills || data.skills) {
|
|
302
|
+
console.log(` Skills:`);
|
|
303
|
+
const skills = data.stateSkills || data.skills || {};
|
|
304
|
+
for (const [skill, level] of Object.entries(skills)) {
|
|
305
|
+
console.log(` ${skill}: ${level}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (data.stateRelationships || data.relationships) {
|
|
309
|
+
console.log(` Relationships:`);
|
|
310
|
+
const rels = data.stateRelationships || data.relationships || {};
|
|
311
|
+
for (const [entity, value] of Object.entries(rels)) {
|
|
312
|
+
const indicator = value > 0 ? "\x1B[32m+" : "\x1B[31m";
|
|
313
|
+
console.log(` ${entity}: ${indicator}${value}\x1B[0m`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch (e) {
|
|
317
|
+
console.error(`> Failed to get agent state:`, e);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async function agentProcess(agentId, input) {
|
|
321
|
+
if (!agentId) {
|
|
322
|
+
console.error("Error: Agent ID required");
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (!input) {
|
|
326
|
+
console.error("Error: Input text required");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
const res = await fetch(`${API_URL}/agents/${agentId}/process`, {
|
|
331
|
+
method: "POST",
|
|
332
|
+
headers: { "Content-Type": "application/json" },
|
|
333
|
+
body: JSON.stringify({ inputText: input, context: { source: "cli" } })
|
|
334
|
+
});
|
|
335
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
336
|
+
const data = await res.json();
|
|
337
|
+
console.log(`\x1B[32m${data.dialogue || data.response || "No response"}\x1B[0m`);
|
|
338
|
+
if (data.actions && data.actions.length > 0) {
|
|
339
|
+
console.log(`\x1B[2mActions: ${data.actions.map((a) => a.type).join(", ")}\x1B[0m`);
|
|
340
|
+
}
|
|
341
|
+
} catch (e) {
|
|
342
|
+
console.error(`> Error:`, e);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
async function agentUpdate(agentId, updateArgs) {
|
|
346
|
+
if (!agentId) {
|
|
347
|
+
console.error("Error: Agent ID required");
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const updates = {};
|
|
351
|
+
for (let i = 0; i < updateArgs.length; i++) {
|
|
352
|
+
if (updateArgs[i] === "--mood" && updateArgs[i + 1]) {
|
|
353
|
+
updates.mood = updateArgs[++i];
|
|
354
|
+
} else if (updateArgs[i] === "--inventory" && updateArgs[i + 1]) {
|
|
355
|
+
updates.inventory = updateArgs[++i].split(",");
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (Object.keys(updates).length === 0) {
|
|
359
|
+
console.error("Usage: forbocai agent update <id> --mood <mood> [--inventory <item1,item2>]");
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
console.log(`> Updating Agent: ${agentId}...`);
|
|
363
|
+
try {
|
|
364
|
+
const res = await fetch(`${API_URL}/agents/${agentId}/state`, {
|
|
365
|
+
method: "PATCH",
|
|
366
|
+
headers: { "Content-Type": "application/json" },
|
|
367
|
+
body: JSON.stringify({ stateUpdate: updates })
|
|
368
|
+
});
|
|
369
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
370
|
+
console.log(`> Agent updated!`);
|
|
371
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
372
|
+
console.log(` ${key}: ${value}`);
|
|
373
|
+
}
|
|
374
|
+
} catch (e) {
|
|
375
|
+
console.error(`> Failed to update agent:`, e);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
149
378
|
async function chatWithAgent(agentId) {
|
|
150
379
|
if (!agentId) {
|
|
151
380
|
console.error("Error: Agent ID required");
|
|
@@ -158,10 +387,7 @@ async function chatWithAgent(agentId) {
|
|
|
158
387
|
console.log(`\x1B[36m\u2551 Type 'exit' to quit \u2551\x1B[0m`);
|
|
159
388
|
console.log(`\x1B[36m\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m
|
|
160
389
|
`);
|
|
161
|
-
const rl = readline.createInterface({
|
|
162
|
-
input: process.stdin,
|
|
163
|
-
output: process.stdout
|
|
164
|
-
});
|
|
390
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
165
391
|
const promptUser = () => {
|
|
166
392
|
rl.question("\x1B[33m> You: \x1B[0m", async (input) => {
|
|
167
393
|
if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit") {
|
|
@@ -173,10 +399,7 @@ async function chatWithAgent(agentId) {
|
|
|
173
399
|
const res = await fetch(`${API_URL}/agents/${agentId}/process`, {
|
|
174
400
|
method: "POST",
|
|
175
401
|
headers: { "Content-Type": "application/json" },
|
|
176
|
-
body: JSON.stringify({
|
|
177
|
-
inputText: input,
|
|
178
|
-
context: { source: "cli" }
|
|
179
|
-
})
|
|
402
|
+
body: JSON.stringify({ inputText: input, context: { source: "cli" } })
|
|
180
403
|
});
|
|
181
404
|
if (!res.ok) throw new Error(res.statusText);
|
|
182
405
|
const data = await res.json();
|
|
@@ -257,6 +480,36 @@ async function chatWithSoul(cid) {
|
|
|
257
480
|
console.error(`> Failed to wake soul:`, e);
|
|
258
481
|
}
|
|
259
482
|
}
|
|
483
|
+
async function soulList() {
|
|
484
|
+
console.log(`> Listing exported Souls...`);
|
|
485
|
+
try {
|
|
486
|
+
console.log(`
|
|
487
|
+
Exported Souls:
|
|
488
|
+
`);
|
|
489
|
+
console.log(` (Soul listing requires local storage or API endpoint)`);
|
|
490
|
+
console.log(` Use 'soul export <agentId>' to create a new Soul`);
|
|
491
|
+
} catch (e) {
|
|
492
|
+
console.error(`> Failed to list souls:`, e);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
async function soulVerify(cid) {
|
|
496
|
+
if (!cid) {
|
|
497
|
+
console.error("Error: CID required");
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
console.log(`> Verifying Soul: ${cid}...`);
|
|
501
|
+
try {
|
|
502
|
+
const res = await fetch(`${API_URL}/souls/${cid}`);
|
|
503
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
504
|
+
const data = await res.json();
|
|
505
|
+
console.log(`> Soul Verified!`);
|
|
506
|
+
console.log(`> Name: ${data.soulName}`);
|
|
507
|
+
console.log(`> DNA: ${(data.dna || "").substring(0, 50)}...`);
|
|
508
|
+
console.log(`> Signature: ${data.signature ? "\x1B[32m\u2713 Valid\x1B[0m" : "\x1B[33m\u25CB Not signed\x1B[0m"}`);
|
|
509
|
+
} catch (e) {
|
|
510
|
+
console.error(`> Failed to verify soul:`, e);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
260
513
|
async function runGhost(suite) {
|
|
261
514
|
const testSuite = suite || "exploration";
|
|
262
515
|
console.log(`> Starting Ghost QA session...`);
|
|
@@ -265,10 +518,7 @@ async function runGhost(suite) {
|
|
|
265
518
|
const res = await fetch(`${API_URL}/ghost/run`, {
|
|
266
519
|
method: "POST",
|
|
267
520
|
headers: { "Content-Type": "application/json" },
|
|
268
|
-
body: JSON.stringify({
|
|
269
|
-
testSuite,
|
|
270
|
-
duration: 300
|
|
271
|
-
})
|
|
521
|
+
body: JSON.stringify({ testSuite, duration: 300 })
|
|
272
522
|
});
|
|
273
523
|
if (!res.ok) throw new Error(res.statusText);
|
|
274
524
|
const data = await res.json();
|
|
@@ -289,14 +539,11 @@ async function ghostStatus(sessionId) {
|
|
|
289
539
|
}
|
|
290
540
|
console.log(`> Checking Ghost session: ${sessionId}...`);
|
|
291
541
|
try {
|
|
292
|
-
const res = await fetch(`${API_URL}/ghost/${sessionId}/status
|
|
293
|
-
method: "GET",
|
|
294
|
-
headers: { "Content-Type": "application/json" }
|
|
295
|
-
});
|
|
542
|
+
const res = await fetch(`${API_URL}/ghost/${sessionId}/status`);
|
|
296
543
|
if (!res.ok) throw new Error(res.statusText);
|
|
297
544
|
const data = await res.json();
|
|
298
545
|
const statusColor = data.ghostStatus === "completed" ? "\x1B[32m" : data.ghostStatus === "failed" ? "\x1B[31m" : "\x1B[33m";
|
|
299
|
-
console.log(`> Status: ${statusColor}${data.ghostStatus
|
|
546
|
+
console.log(`> Status: ${statusColor}${(data.ghostStatus || "unknown").toUpperCase()}\x1B[0m`);
|
|
300
547
|
console.log(`> Progress: ${data.ghostProgress || 0}%`);
|
|
301
548
|
console.log(`> Duration: ${data.ghostDuration || 0}s`);
|
|
302
549
|
console.log(`> Errors: ${data.ghostErrors || 0}`);
|
|
@@ -311,10 +558,7 @@ async function ghostResults(sessionId) {
|
|
|
311
558
|
}
|
|
312
559
|
console.log(`> Fetching Ghost results: ${sessionId}...`);
|
|
313
560
|
try {
|
|
314
|
-
const res = await fetch(`${API_URL}/ghost/${sessionId}/results
|
|
315
|
-
method: "GET",
|
|
316
|
-
headers: { "Content-Type": "application/json" }
|
|
317
|
-
});
|
|
561
|
+
const res = await fetch(`${API_URL}/ghost/${sessionId}/results`);
|
|
318
562
|
if (!res.ok) throw new Error(res.statusText);
|
|
319
563
|
const data = await res.json();
|
|
320
564
|
console.log(`
|
|
@@ -351,70 +595,270 @@ async function ghostResults(sessionId) {
|
|
|
351
595
|
console.error(`> Failed to get Ghost results:`, e);
|
|
352
596
|
}
|
|
353
597
|
}
|
|
354
|
-
async function
|
|
355
|
-
|
|
598
|
+
async function ghostStop(sessionId) {
|
|
599
|
+
if (!sessionId) {
|
|
600
|
+
console.error("Error: Session ID required");
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
console.log(`> Stopping Ghost session: ${sessionId}...`);
|
|
604
|
+
console.log(`> Session stop requested (mock)`);
|
|
605
|
+
console.log(`> Status: \x1B[33mStopped\x1B[0m`);
|
|
606
|
+
}
|
|
607
|
+
async function ghostHistory() {
|
|
608
|
+
console.log(`> Fetching Ghost session history...`);
|
|
609
|
+
console.log(`
|
|
610
|
+
Recent Sessions:
|
|
611
|
+
`);
|
|
612
|
+
console.log(` (Session history requires persistent storage)`);
|
|
613
|
+
console.log(` Use 'ghost run <suite>' to start a new session`);
|
|
614
|
+
}
|
|
615
|
+
async function memoryList(agentId) {
|
|
616
|
+
if (!agentId) {
|
|
617
|
+
console.error("Error: Agent ID required");
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
console.log(`> Listing memories for Agent: ${agentId}...`);
|
|
621
|
+
try {
|
|
622
|
+
const res = await fetch(`${API_URL}/agents/${agentId}/memory`);
|
|
623
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
624
|
+
const data = await res.json();
|
|
625
|
+
const memories = data.memories || data;
|
|
626
|
+
if (!memories || memories.length === 0) {
|
|
627
|
+
console.log(`> No memories found.`);
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
console.log(`
|
|
631
|
+
Memories (${memories.length}):
|
|
632
|
+
`);
|
|
633
|
+
memories.slice(0, 20).forEach((mem, i) => {
|
|
634
|
+
const importance = mem.importance || mem.memImportance || 0.5;
|
|
635
|
+
const bar = "\u2588".repeat(Math.floor(importance * 10));
|
|
636
|
+
console.log(` ${i + 1}. [${bar.padEnd(10)}] ${(mem.text || mem.memText || "").substring(0, 50)}...`);
|
|
637
|
+
});
|
|
638
|
+
if (memories.length > 20) {
|
|
639
|
+
console.log(`
|
|
640
|
+
... and ${memories.length - 20} more`);
|
|
641
|
+
}
|
|
642
|
+
} catch (e) {
|
|
643
|
+
console.error(`> Failed to list memories:`, e);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
async function memoryRecall(agentId, query) {
|
|
647
|
+
if (!agentId) {
|
|
648
|
+
console.error("Error: Agent ID required");
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
if (!query) {
|
|
652
|
+
console.error("Error: Query required");
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
console.log(`> Recalling memories for: "${query}"...`);
|
|
356
656
|
try {
|
|
357
|
-
const res = await fetch(`${API_URL}/
|
|
358
|
-
method: "
|
|
359
|
-
headers: { "Content-Type": "application/json" }
|
|
657
|
+
const res = await fetch(`${API_URL}/agents/${agentId}/memory/recall`, {
|
|
658
|
+
method: "POST",
|
|
659
|
+
headers: { "Content-Type": "application/json" },
|
|
660
|
+
body: JSON.stringify({ recallQuery: query, recallLimit: 5 })
|
|
360
661
|
});
|
|
361
662
|
if (!res.ok) throw new Error(res.statusText);
|
|
362
663
|
const data = await res.json();
|
|
664
|
+
const memories = data.recalledMemories || data;
|
|
665
|
+
if (!memories || memories.length === 0) {
|
|
666
|
+
console.log(`> No relevant memories found.`);
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
363
669
|
console.log(`
|
|
364
|
-
|
|
670
|
+
Relevant Memories:
|
|
365
671
|
`);
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
console.log(`
|
|
369
|
-
console.log(` Parameters: ${(model.parameters / 1e6).toFixed(0)}M`);
|
|
370
|
-
console.log(` Size: ${model.downloadSize}`);
|
|
371
|
-
console.log(` Capabilities: ${model.capabilities?.join(", ") || "N/A"}`);
|
|
372
|
-
console.log("");
|
|
672
|
+
memories.forEach((mem, i) => {
|
|
673
|
+
const score = mem.score || mem.relevance || "?";
|
|
674
|
+
console.log(` ${i + 1}. [Score: ${score}] ${(mem.text || mem.memText || "").substring(0, 60)}...`);
|
|
373
675
|
});
|
|
374
676
|
} catch (e) {
|
|
375
|
-
console.error(`> Failed to
|
|
677
|
+
console.error(`> Failed to recall memories:`, e);
|
|
376
678
|
}
|
|
377
679
|
}
|
|
680
|
+
async function memoryStore(agentId, text) {
|
|
681
|
+
if (!agentId) {
|
|
682
|
+
console.error("Error: Agent ID required");
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
if (!text) {
|
|
686
|
+
console.error("Error: Memory text required");
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
console.log(`> Storing memory...`);
|
|
690
|
+
try {
|
|
691
|
+
const res = await fetch(`${API_URL}/agents/${agentId}/memory`, {
|
|
692
|
+
method: "POST",
|
|
693
|
+
headers: { "Content-Type": "application/json" },
|
|
694
|
+
body: JSON.stringify({ storeText: text, storeType: "observation" })
|
|
695
|
+
});
|
|
696
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
697
|
+
const data = await res.json();
|
|
698
|
+
console.log(`> Memory stored!`);
|
|
699
|
+
console.log(`> ID: ${data.storedId || data.id}`);
|
|
700
|
+
} catch (e) {
|
|
701
|
+
console.error(`> Failed to store memory:`, e);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
async function memoryClear(agentId) {
|
|
705
|
+
if (!agentId) {
|
|
706
|
+
console.error("Error: Agent ID required");
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
console.log(`> Clearing memories for Agent: ${agentId}...`);
|
|
710
|
+
console.log(`> \x1B[31mThis action cannot be undone!\x1B[0m`);
|
|
711
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
712
|
+
rl.question('Type "CONFIRM" to proceed: ', async (answer) => {
|
|
713
|
+
if (answer !== "CONFIRM") {
|
|
714
|
+
console.log("> Aborted.");
|
|
715
|
+
rl.close();
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
try {
|
|
719
|
+
console.log(`> Memories cleared (mock)`);
|
|
720
|
+
} catch (e) {
|
|
721
|
+
console.error(`> Failed to clear memories:`, e);
|
|
722
|
+
}
|
|
723
|
+
rl.close();
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
async function memoryExport(agentId) {
|
|
727
|
+
if (!agentId) {
|
|
728
|
+
console.error("Error: Agent ID required");
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
console.log(`> Exporting memories for Agent: ${agentId}...`);
|
|
732
|
+
try {
|
|
733
|
+
const res = await fetch(`${API_URL}/agents/${agentId}/memory`);
|
|
734
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
735
|
+
const data = await res.json();
|
|
736
|
+
const filename = `memories_${agentId}_${Date.now()}.json`;
|
|
737
|
+
fs.writeFileSync(filename, JSON.stringify(data, null, 2));
|
|
738
|
+
console.log(`> Memories exported to: ${filename}`);
|
|
739
|
+
} catch (e) {
|
|
740
|
+
console.error(`> Failed to export memories:`, e);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
async function bridgeValidate(actionFile) {
|
|
744
|
+
if (!actionFile) {
|
|
745
|
+
console.error("Error: Action file (JSON) required");
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
console.log(`> Validating action from: ${actionFile}...`);
|
|
749
|
+
try {
|
|
750
|
+
const actionJson = fs.readFileSync(actionFile, "utf-8");
|
|
751
|
+
const action = JSON.parse(actionJson);
|
|
752
|
+
const res = await fetch(`${API_URL}/bridge/validate`, {
|
|
753
|
+
method: "POST",
|
|
754
|
+
headers: { "Content-Type": "application/json" },
|
|
755
|
+
body: JSON.stringify({ validateAction: action })
|
|
756
|
+
});
|
|
757
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
758
|
+
const data = await res.json();
|
|
759
|
+
if (data.validationIsValid || data.valid) {
|
|
760
|
+
console.log(`> \x1B[32m\u2713 Action is VALID\x1B[0m`);
|
|
761
|
+
} else {
|
|
762
|
+
console.log(`> \x1B[31m\u2717 Action is INVALID\x1B[0m`);
|
|
763
|
+
console.log(`> Reason: ${data.validationReason || data.reason}`);
|
|
764
|
+
}
|
|
765
|
+
} catch (e) {
|
|
766
|
+
console.error(`> Failed to validate action:`, e);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
async function bridgeRules() {
|
|
770
|
+
console.log(`> Fetching validation rules...`);
|
|
771
|
+
console.log(`
|
|
772
|
+
Built-in Rules:
|
|
773
|
+
`);
|
|
774
|
+
console.log(` \x1B[36mcore.movement\x1B[0m`);
|
|
775
|
+
console.log(` Actions: MOVE, WALK, RUN`);
|
|
776
|
+
console.log(` Validates: Coordinates, world bounds`);
|
|
777
|
+
console.log("");
|
|
778
|
+
console.log(` \x1B[36mcore.attack\x1B[0m`);
|
|
779
|
+
console.log(` Actions: ATTACK, HIT, STRIKE`);
|
|
780
|
+
console.log(` Validates: Target exists`);
|
|
781
|
+
console.log("");
|
|
782
|
+
console.log(` \x1B[36mcore.interact\x1B[0m`);
|
|
783
|
+
console.log(` Actions: INTERACT, USE, PICKUP`);
|
|
784
|
+
console.log(` Validates: Object specified`);
|
|
785
|
+
console.log("");
|
|
786
|
+
console.log(` \x1B[36mcore.speak\x1B[0m`);
|
|
787
|
+
console.log(` Actions: SPEAK, SAY, SHOUT`);
|
|
788
|
+
console.log(` Validates: Text not empty`);
|
|
789
|
+
console.log("");
|
|
790
|
+
console.log(` \x1B[36mcore.resources\x1B[0m`);
|
|
791
|
+
console.log(` Actions: (all)`);
|
|
792
|
+
console.log(` Validates: HP > 0, sufficient mana`);
|
|
793
|
+
}
|
|
378
794
|
function printUsage() {
|
|
379
795
|
console.log(`
|
|
380
796
|
\x1B[36m\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
381
|
-
\u2551 ForbocAI CLI
|
|
797
|
+
\u2551 ForbocAI CLI v${VERSION} \u2551
|
|
382
798
|
\u2551 The Neuro-Symbolic Grid Interface \u2551
|
|
383
799
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m
|
|
384
800
|
|
|
385
801
|
\x1B[1mUsage:\x1B[0m
|
|
386
802
|
forbocai <command> <subcommand> [options]
|
|
387
803
|
|
|
388
|
-
\x1B[
|
|
389
|
-
|
|
804
|
+
\x1B[1mMeta:\x1B[0m
|
|
805
|
+
version Show SDK version
|
|
806
|
+
doctor Diagnose SDK/API issues
|
|
807
|
+
|
|
808
|
+
\x1B[1mConfig:\x1B[0m
|
|
809
|
+
config set <k> <v> Set configuration value
|
|
810
|
+
config get <key> Get configuration value
|
|
811
|
+
config list List all configuration
|
|
812
|
+
|
|
813
|
+
\x1B[1mAPI:\x1B[0m
|
|
814
|
+
api status Check API connection
|
|
390
815
|
|
|
391
|
-
\x1B[
|
|
816
|
+
\x1B[1mCortex:\x1B[0m
|
|
817
|
+
cortex models List available SLM models
|
|
818
|
+
cortex init [model] Initialize Cortex with model
|
|
819
|
+
|
|
820
|
+
\x1B[1mAgent:\x1B[0m
|
|
392
821
|
agent create [persona] Create a new agent
|
|
393
822
|
agent list List all agents
|
|
394
|
-
agent chat <
|
|
395
|
-
agent
|
|
823
|
+
agent chat <id> Interactive chat with agent
|
|
824
|
+
agent state <id> View agent's current state
|
|
825
|
+
agent process <id> <t> One-shot process input
|
|
826
|
+
agent update <id> ... Update agent state
|
|
827
|
+
agent delete <id> Delete an agent
|
|
828
|
+
|
|
829
|
+
\x1B[1mMemory:\x1B[0m
|
|
830
|
+
memory list <agentId> List agent's memories
|
|
831
|
+
memory recall <id> <q> Semantic search memories
|
|
832
|
+
memory store <id> <t> Store new observation
|
|
833
|
+
memory clear <id> Clear all memories
|
|
834
|
+
memory export <id> Export memories to JSON
|
|
396
835
|
|
|
397
|
-
\x1B[
|
|
836
|
+
\x1B[1mBridge:\x1B[0m
|
|
837
|
+
bridge validate <file> Validate action JSON
|
|
838
|
+
bridge rules List validation rules
|
|
839
|
+
|
|
840
|
+
\x1B[1mSoul:\x1B[0m
|
|
398
841
|
soul export <agentId> Export agent to IPFS
|
|
399
842
|
soul import <cid> Import agent from IPFS
|
|
400
|
-
soul chat <cid> Wake and chat with
|
|
843
|
+
soul chat <cid> Wake and chat with Soul
|
|
844
|
+
soul list List exported Souls
|
|
845
|
+
soul verify <cid> Verify Soul signature
|
|
401
846
|
|
|
402
|
-
\x1B[1mGhost
|
|
847
|
+
\x1B[1mGhost:\x1B[0m
|
|
403
848
|
ghost run [suite] Start QA test session
|
|
404
849
|
ghost status <id> Check session progress
|
|
405
850
|
ghost results <id> Get test results
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
cortex models List available SLM models
|
|
851
|
+
ghost stop <id> Stop running session
|
|
852
|
+
ghost history List past sessions
|
|
409
853
|
|
|
410
854
|
\x1B[1mEnvironment:\x1B[0m
|
|
411
|
-
FORBOC_API_URL Override API URL
|
|
855
|
+
FORBOC_API_URL Override API URL
|
|
412
856
|
|
|
413
857
|
\x1B[1mExamples:\x1B[0m
|
|
414
858
|
forbocai api status
|
|
415
|
-
forbocai agent create "A wise
|
|
859
|
+
forbocai agent create "A wise wizard"
|
|
416
860
|
forbocai agent chat agent_abc123
|
|
417
|
-
forbocai
|
|
418
|
-
forbocai
|
|
861
|
+
forbocai memory recall agent_abc123 "battle"
|
|
862
|
+
forbocai ghost run combat
|
|
419
863
|
`);
|
|
420
864
|
}
|