forbocai 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,6 +22,35 @@ Autonomous AI for game NPCs.
22
22
 
23
23
  ---
24
24
 
25
+ ## 🚀 Publishing to NPM (Quick Reference)
26
+
27
+ `Públish_Séquence // NPM_Deploý`
28
+
29
+ To publish a new version to NPM:
30
+
31
+ ```bash
32
+ # 1. Bump version
33
+ npm version <major|minor|patch> --no-git-tag-version
34
+
35
+ # 2. Build
36
+ npm run build
37
+
38
+ # 3. Publish (use token from api/NPM_TOKEN.md)
39
+ echo "//registry.npmjs.org/:_authToken=<TOKEN_FROM_API_NPM_TOKEN_MD>" > .npmrc
40
+ npm publish --access public
41
+
42
+ # 4. Clean up (IMPORTANT: don't commit .npmrc)
43
+ rm .npmrc
44
+
45
+ # 5. Commit and push
46
+ git add . && git commit -m "chore: release vX.X.X" && git push
47
+ ```
48
+
49
+ > **Token Location**: The NPM token is stored in `../api/NPM_TOKEN.md`
50
+ > **Current Version**: Check `package.json` for the current version
51
+
52
+ ---
53
+
25
54
  ## Overview
26
55
 
27
56
  `Córe_Módules // SDK_Init`
package/dist/cli.js CHANGED
@@ -26,6 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  // src/cli.ts
27
27
  var import_http = __toESM(require("http"));
28
28
  var import_https = __toESM(require("https"));
29
+ var readline = __toESM(require("readline"));
29
30
  var DEFAULT_API_URL = "https://forbocai-api.onrender.com";
30
31
  var API_URL = process.env.FORBOC_API_URL || DEFAULT_API_URL;
31
32
  var args = process.argv.slice(2);
@@ -36,15 +37,32 @@ if (command === "api" && subcommand === "status") {
36
37
  checkApiStatus();
37
38
  } else if (command === "agent" && subcommand === "create") {
38
39
  createAgent(subcommand2);
40
+ } else if (command === "agent" && subcommand === "list") {
41
+ listAgents();
42
+ } else if (command === "agent" && subcommand === "chat") {
43
+ chatWithAgent(subcommand2);
44
+ } else if (command === "agent" && subcommand === "delete") {
45
+ deleteAgent(subcommand2);
39
46
  } else if (command === "soul" && subcommand === "export") {
40
47
  exportSoul(subcommand2);
41
48
  } else if (command === "soul" && subcommand === "import") {
42
49
  importSoul(subcommand2);
50
+ } else if (command === "soul" && subcommand === "chat") {
51
+ chatWithSoul(subcommand2);
52
+ } else if (command === "ghost" && subcommand === "run") {
53
+ runGhost(subcommand2);
54
+ } else if (command === "ghost" && subcommand === "status") {
55
+ ghostStatus(subcommand2);
56
+ } else if (command === "ghost" && subcommand === "results") {
57
+ ghostResults(subcommand2);
58
+ } else if (command === "cortex" && subcommand === "models") {
59
+ listModels();
43
60
  } else {
44
61
  printUsage();
45
62
  }
46
63
  function checkApiStatus() {
47
64
  console.log(`> Connecting to Neuro-Symbolic Grid...`);
65
+ console.log(`> API: ${API_URL}`);
48
66
  const client = API_URL.startsWith("https") ? import_https.default : import_http.default;
49
67
  client.get(`${API_URL}/status`, (res) => {
50
68
  let data = "";
@@ -86,6 +104,95 @@ async function createAgent(persona) {
86
104
  console.error(`> Failed to create agent:`, e);
87
105
  }
88
106
  }
107
+ async function listAgents() {
108
+ console.log(`> Listing agents...`);
109
+ try {
110
+ const res = await fetch(`${API_URL}/agents`, {
111
+ method: "GET",
112
+ headers: { "Content-Type": "application/json" }
113
+ });
114
+ if (!res.ok) throw new Error(res.statusText);
115
+ const data = await res.json();
116
+ if (data.length === 0) {
117
+ console.log(`> No agents found.`);
118
+ return;
119
+ }
120
+ console.log(`> Found ${data.length} agents:
121
+ `);
122
+ data.forEach((agent, i) => {
123
+ console.log(` ${i + 1}. \x1B[32m${agent.agentId}\x1B[0m`);
124
+ console.log(` Persona: ${agent.persona?.substring(0, 50)}...`);
125
+ console.log(` Mood: ${agent.mood || "unknown"}`);
126
+ console.log("");
127
+ });
128
+ } catch (e) {
129
+ console.error(`> Failed to list agents:`, e);
130
+ }
131
+ }
132
+ async function deleteAgent(agentId) {
133
+ if (!agentId) {
134
+ console.error("Error: Agent ID required");
135
+ return;
136
+ }
137
+ console.log(`> Deleting Agent: ${agentId}...`);
138
+ try {
139
+ const res = await fetch(`${API_URL}/agents/${agentId}`, {
140
+ method: "DELETE",
141
+ headers: { "Content-Type": "application/json" }
142
+ });
143
+ if (!res.ok) throw new Error(res.statusText);
144
+ console.log(`> Agent \x1B[31mdeleted\x1B[0m: ${agentId}`);
145
+ } catch (e) {
146
+ console.error(`> Failed to delete agent:`, e);
147
+ }
148
+ }
149
+ async function chatWithAgent(agentId) {
150
+ if (!agentId) {
151
+ console.error("Error: Agent ID required");
152
+ return;
153
+ }
154
+ console.log(`
155
+ \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\x1B[0m`);
156
+ console.log(`\x1B[36m\u2551 ForbocAI Agent Chat \u2551\x1B[0m`);
157
+ console.log(`\x1B[36m\u2551 Agent: ${agentId.substring(0, 28).padEnd(28)} \u2551\x1B[0m`);
158
+ console.log(`\x1B[36m\u2551 Type 'exit' to quit \u2551\x1B[0m`);
159
+ 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
+ `);
161
+ const rl = readline.createInterface({
162
+ input: process.stdin,
163
+ output: process.stdout
164
+ });
165
+ const promptUser = () => {
166
+ rl.question("\x1B[33m> You: \x1B[0m", async (input) => {
167
+ if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit") {
168
+ console.log("\n> Disconnecting from agent...");
169
+ rl.close();
170
+ return;
171
+ }
172
+ try {
173
+ const res = await fetch(`${API_URL}/agents/${agentId}/process`, {
174
+ method: "POST",
175
+ headers: { "Content-Type": "application/json" },
176
+ body: JSON.stringify({
177
+ inputText: input,
178
+ context: { source: "cli" }
179
+ })
180
+ });
181
+ if (!res.ok) throw new Error(res.statusText);
182
+ const data = await res.json();
183
+ console.log(`\x1B[32m> Agent: \x1B[0m${data.dialogue || data.response || "No response"}`);
184
+ if (data.actions && data.actions.length > 0) {
185
+ console.log(`\x1B[2m> Actions: ${data.actions.map((a) => a.type).join(", ")}\x1B[0m`);
186
+ }
187
+ console.log("");
188
+ } catch (e) {
189
+ console.error(`> Error: ${e}`);
190
+ }
191
+ promptUser();
192
+ });
193
+ };
194
+ promptUser();
195
+ }
89
196
  async function exportSoul(agentId) {
90
197
  if (!agentId) {
91
198
  console.error("Error: Agent ID required");
@@ -128,12 +235,186 @@ async function importSoul(cid) {
128
235
  console.error(`> Failed to import soul:`, e);
129
236
  }
130
237
  }
238
+ async function chatWithSoul(cid) {
239
+ if (!cid) {
240
+ console.error("Error: CID required");
241
+ return;
242
+ }
243
+ console.log(`> Waking Soul from cryo: ${cid}...`);
244
+ try {
245
+ const res = await fetch(`${API_URL}/agents/import`, {
246
+ method: "POST",
247
+ headers: { "Content-Type": "application/json" },
248
+ body: JSON.stringify({ cidRef: cid })
249
+ });
250
+ if (!res.ok) throw new Error(res.statusText);
251
+ const data = await res.json();
252
+ console.log(`> Soul awakened! Temporary Agent: ${data.agentId}`);
253
+ console.log(`> Persona: ${data.persona}
254
+ `);
255
+ await chatWithAgent(data.agentId);
256
+ } catch (e) {
257
+ console.error(`> Failed to wake soul:`, e);
258
+ }
259
+ }
260
+ async function runGhost(suite) {
261
+ const testSuite = suite || "exploration";
262
+ console.log(`> Starting Ghost QA session...`);
263
+ console.log(`> Test Suite: ${testSuite}`);
264
+ try {
265
+ const res = await fetch(`${API_URL}/ghost/run`, {
266
+ method: "POST",
267
+ headers: { "Content-Type": "application/json" },
268
+ body: JSON.stringify({
269
+ testSuite,
270
+ duration: 300
271
+ })
272
+ });
273
+ if (!res.ok) throw new Error(res.statusText);
274
+ const data = await res.json();
275
+ console.log(`> Session Started!`);
276
+ console.log(`> Session ID: \x1B[36m${data.sessionId}\x1B[0m`);
277
+ console.log(`> Status: ${data.runStatus || "running"}`);
278
+ console.log(`
279
+ > To check status: forbocai ghost status ${data.sessionId}`);
280
+ console.log(`> To get results: forbocai ghost results ${data.sessionId}`);
281
+ } catch (e) {
282
+ console.error(`> Failed to start Ghost session:`, e);
283
+ }
284
+ }
285
+ async function ghostStatus(sessionId) {
286
+ if (!sessionId) {
287
+ console.error("Error: Session ID required");
288
+ return;
289
+ }
290
+ console.log(`> Checking Ghost session: ${sessionId}...`);
291
+ try {
292
+ const res = await fetch(`${API_URL}/ghost/${sessionId}/status`, {
293
+ method: "GET",
294
+ headers: { "Content-Type": "application/json" }
295
+ });
296
+ if (!res.ok) throw new Error(res.statusText);
297
+ const data = await res.json();
298
+ const statusColor = data.ghostStatus === "completed" ? "\x1B[32m" : data.ghostStatus === "failed" ? "\x1B[31m" : "\x1B[33m";
299
+ console.log(`> Status: ${statusColor}${data.ghostStatus?.toUpperCase()}\x1B[0m`);
300
+ console.log(`> Progress: ${data.ghostProgress || 0}%`);
301
+ console.log(`> Duration: ${data.ghostDuration || 0}s`);
302
+ console.log(`> Errors: ${data.ghostErrors || 0}`);
303
+ } catch (e) {
304
+ console.error(`> Failed to get Ghost status:`, e);
305
+ }
306
+ }
307
+ async function ghostResults(sessionId) {
308
+ if (!sessionId) {
309
+ console.error("Error: Session ID required");
310
+ return;
311
+ }
312
+ console.log(`> Fetching Ghost results: ${sessionId}...`);
313
+ try {
314
+ const res = await fetch(`${API_URL}/ghost/${sessionId}/results`, {
315
+ method: "GET",
316
+ headers: { "Content-Type": "application/json" }
317
+ });
318
+ if (!res.ok) throw new Error(res.statusText);
319
+ const data = await res.json();
320
+ console.log(`
321
+ \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`);
322
+ console.log(`\u2551 Ghost QA Results \u2551`);
323
+ 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
324
+ `);
325
+ const passRate = data.resultsTotalTests > 0 ? (data.resultsPassed / data.resultsTotalTests * 100).toFixed(1) : 0;
326
+ console.log(` Total Tests: ${data.resultsTotalTests}`);
327
+ console.log(` \x1B[32mPassed: ${data.resultsPassed}\x1B[0m`);
328
+ console.log(` \x1B[31mFailed: ${data.resultsFailed}\x1B[0m`);
329
+ console.log(` Pass Rate: ${passRate}%`);
330
+ console.log(` Duration: ${data.resultsDuration}ms`);
331
+ console.log(` Coverage: ${((data.resultsCoverage || 0) * 100).toFixed(1)}%`);
332
+ if (data.resultsMetrics) {
333
+ console.log(`
334
+ Metrics:`);
335
+ for (const [key, value] of data.resultsMetrics) {
336
+ console.log(` ${key}: ${value}`);
337
+ }
338
+ }
339
+ if (data.resultsTests && data.resultsTests.length > 0) {
340
+ console.log(`
341
+ Tests:`);
342
+ data.resultsTests.forEach((test) => {
343
+ const icon = test.testPassed ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
344
+ console.log(` ${icon} ${test.testName} (${test.testDuration}ms)`);
345
+ if (test.testError) {
346
+ console.log(` \x1B[31mError: ${test.testError}\x1B[0m`);
347
+ }
348
+ });
349
+ }
350
+ } catch (e) {
351
+ console.error(`> Failed to get Ghost results:`, e);
352
+ }
353
+ }
354
+ async function listModels() {
355
+ console.log(`> Fetching available models...`);
356
+ try {
357
+ const res = await fetch(`${API_URL}/cortex/models`, {
358
+ method: "GET",
359
+ headers: { "Content-Type": "application/json" }
360
+ });
361
+ if (!res.ok) throw new Error(res.statusText);
362
+ const data = await res.json();
363
+ console.log(`
364
+ Available Models:
365
+ `);
366
+ data.forEach((model) => {
367
+ console.log(` \x1B[36m${model.id}\x1B[0m`);
368
+ console.log(` Name: ${model.name}`);
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("");
373
+ });
374
+ } catch (e) {
375
+ console.error(`> Failed to list models:`, e);
376
+ }
377
+ }
131
378
  function printUsage() {
132
- console.log("Usage:");
133
- console.log(" forbocai api status");
134
- console.log(" forbocai agent create [<persona>]");
135
- console.log(" forbocai soul export <agentId>");
136
- console.log(" forbocai soul import <cid>");
137
- console.log("\nEnvironment:");
138
- console.log(" FORBOC_API_URL Override API URL (default: render)");
379
+ console.log(`
380
+ \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 v0.1.0 \u2551
382
+ \u2551 The Neuro-Symbolic Grid Interface \u2551
383
+ \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
+
385
+ \x1B[1mUsage:\x1B[0m
386
+ forbocai <command> <subcommand> [options]
387
+
388
+ \x1B[1mAPI Commands:\x1B[0m
389
+ api status Check API connection and version
390
+
391
+ \x1B[1mAgent Commands:\x1B[0m
392
+ agent create [persona] Create a new agent
393
+ agent list List all agents
394
+ agent chat <agentId> Interactive chat with an agent
395
+ agent delete <agentId> Delete an agent
396
+
397
+ \x1B[1mSoul Commands:\x1B[0m
398
+ soul export <agentId> Export agent to IPFS
399
+ soul import <cid> Import agent from IPFS
400
+ soul chat <cid> Wake and chat with a Soul
401
+
402
+ \x1B[1mGhost Commands:\x1B[0m
403
+ ghost run [suite] Start QA test session
404
+ ghost status <id> Check session progress
405
+ ghost results <id> Get test results
406
+
407
+ \x1B[1mCortex Commands:\x1B[0m
408
+ cortex models List available SLM models
409
+
410
+ \x1B[1mEnvironment:\x1B[0m
411
+ FORBOC_API_URL Override API URL (default: render)
412
+
413
+ \x1B[1mExamples:\x1B[0m
414
+ forbocai api status
415
+ forbocai agent create "A wise old wizard"
416
+ forbocai agent chat agent_abc123
417
+ forbocai ghost run exploration
418
+ forbocai soul chat QmXyz...
419
+ `);
139
420
  }
package/dist/cli.mjs CHANGED
@@ -3,6 +3,7 @@
3
3
  // src/cli.ts
4
4
  import http from "http";
5
5
  import https from "https";
6
+ import * as readline from "readline";
6
7
  var DEFAULT_API_URL = "https://forbocai-api.onrender.com";
7
8
  var API_URL = process.env.FORBOC_API_URL || DEFAULT_API_URL;
8
9
  var args = process.argv.slice(2);
@@ -13,15 +14,32 @@ if (command === "api" && subcommand === "status") {
13
14
  checkApiStatus();
14
15
  } else if (command === "agent" && subcommand === "create") {
15
16
  createAgent(subcommand2);
17
+ } else if (command === "agent" && subcommand === "list") {
18
+ listAgents();
19
+ } else if (command === "agent" && subcommand === "chat") {
20
+ chatWithAgent(subcommand2);
21
+ } else if (command === "agent" && subcommand === "delete") {
22
+ deleteAgent(subcommand2);
16
23
  } else if (command === "soul" && subcommand === "export") {
17
24
  exportSoul(subcommand2);
18
25
  } else if (command === "soul" && subcommand === "import") {
19
26
  importSoul(subcommand2);
27
+ } else if (command === "soul" && subcommand === "chat") {
28
+ chatWithSoul(subcommand2);
29
+ } else if (command === "ghost" && subcommand === "run") {
30
+ runGhost(subcommand2);
31
+ } else if (command === "ghost" && subcommand === "status") {
32
+ ghostStatus(subcommand2);
33
+ } else if (command === "ghost" && subcommand === "results") {
34
+ ghostResults(subcommand2);
35
+ } else if (command === "cortex" && subcommand === "models") {
36
+ listModels();
20
37
  } else {
21
38
  printUsage();
22
39
  }
23
40
  function checkApiStatus() {
24
41
  console.log(`> Connecting to Neuro-Symbolic Grid...`);
42
+ console.log(`> API: ${API_URL}`);
25
43
  const client = API_URL.startsWith("https") ? https : http;
26
44
  client.get(`${API_URL}/status`, (res) => {
27
45
  let data = "";
@@ -63,6 +81,95 @@ async function createAgent(persona) {
63
81
  console.error(`> Failed to create agent:`, e);
64
82
  }
65
83
  }
84
+ async function listAgents() {
85
+ console.log(`> Listing agents...`);
86
+ try {
87
+ const res = await fetch(`${API_URL}/agents`, {
88
+ method: "GET",
89
+ headers: { "Content-Type": "application/json" }
90
+ });
91
+ if (!res.ok) throw new Error(res.statusText);
92
+ const data = await res.json();
93
+ if (data.length === 0) {
94
+ console.log(`> No agents found.`);
95
+ return;
96
+ }
97
+ console.log(`> Found ${data.length} agents:
98
+ `);
99
+ data.forEach((agent, i) => {
100
+ console.log(` ${i + 1}. \x1B[32m${agent.agentId}\x1B[0m`);
101
+ console.log(` Persona: ${agent.persona?.substring(0, 50)}...`);
102
+ console.log(` Mood: ${agent.mood || "unknown"}`);
103
+ console.log("");
104
+ });
105
+ } catch (e) {
106
+ console.error(`> Failed to list agents:`, e);
107
+ }
108
+ }
109
+ async function deleteAgent(agentId) {
110
+ if (!agentId) {
111
+ console.error("Error: Agent ID required");
112
+ return;
113
+ }
114
+ console.log(`> Deleting Agent: ${agentId}...`);
115
+ try {
116
+ const res = await fetch(`${API_URL}/agents/${agentId}`, {
117
+ method: "DELETE",
118
+ headers: { "Content-Type": "application/json" }
119
+ });
120
+ if (!res.ok) throw new Error(res.statusText);
121
+ console.log(`> Agent \x1B[31mdeleted\x1B[0m: ${agentId}`);
122
+ } catch (e) {
123
+ console.error(`> Failed to delete agent:`, e);
124
+ }
125
+ }
126
+ async function chatWithAgent(agentId) {
127
+ if (!agentId) {
128
+ console.error("Error: Agent ID required");
129
+ return;
130
+ }
131
+ console.log(`
132
+ \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\x1B[0m`);
133
+ console.log(`\x1B[36m\u2551 ForbocAI Agent Chat \u2551\x1B[0m`);
134
+ console.log(`\x1B[36m\u2551 Agent: ${agentId.substring(0, 28).padEnd(28)} \u2551\x1B[0m`);
135
+ console.log(`\x1B[36m\u2551 Type 'exit' to quit \u2551\x1B[0m`);
136
+ 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
137
+ `);
138
+ const rl = readline.createInterface({
139
+ input: process.stdin,
140
+ output: process.stdout
141
+ });
142
+ const promptUser = () => {
143
+ rl.question("\x1B[33m> You: \x1B[0m", async (input) => {
144
+ if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit") {
145
+ console.log("\n> Disconnecting from agent...");
146
+ rl.close();
147
+ return;
148
+ }
149
+ try {
150
+ const res = await fetch(`${API_URL}/agents/${agentId}/process`, {
151
+ method: "POST",
152
+ headers: { "Content-Type": "application/json" },
153
+ body: JSON.stringify({
154
+ inputText: input,
155
+ context: { source: "cli" }
156
+ })
157
+ });
158
+ if (!res.ok) throw new Error(res.statusText);
159
+ const data = await res.json();
160
+ console.log(`\x1B[32m> Agent: \x1B[0m${data.dialogue || data.response || "No response"}`);
161
+ if (data.actions && data.actions.length > 0) {
162
+ console.log(`\x1B[2m> Actions: ${data.actions.map((a) => a.type).join(", ")}\x1B[0m`);
163
+ }
164
+ console.log("");
165
+ } catch (e) {
166
+ console.error(`> Error: ${e}`);
167
+ }
168
+ promptUser();
169
+ });
170
+ };
171
+ promptUser();
172
+ }
66
173
  async function exportSoul(agentId) {
67
174
  if (!agentId) {
68
175
  console.error("Error: Agent ID required");
@@ -105,12 +212,186 @@ async function importSoul(cid) {
105
212
  console.error(`> Failed to import soul:`, e);
106
213
  }
107
214
  }
215
+ async function chatWithSoul(cid) {
216
+ if (!cid) {
217
+ console.error("Error: CID required");
218
+ return;
219
+ }
220
+ console.log(`> Waking Soul from cryo: ${cid}...`);
221
+ try {
222
+ const res = await fetch(`${API_URL}/agents/import`, {
223
+ method: "POST",
224
+ headers: { "Content-Type": "application/json" },
225
+ body: JSON.stringify({ cidRef: cid })
226
+ });
227
+ if (!res.ok) throw new Error(res.statusText);
228
+ const data = await res.json();
229
+ console.log(`> Soul awakened! Temporary Agent: ${data.agentId}`);
230
+ console.log(`> Persona: ${data.persona}
231
+ `);
232
+ await chatWithAgent(data.agentId);
233
+ } catch (e) {
234
+ console.error(`> Failed to wake soul:`, e);
235
+ }
236
+ }
237
+ async function runGhost(suite) {
238
+ const testSuite = suite || "exploration";
239
+ console.log(`> Starting Ghost QA session...`);
240
+ console.log(`> Test Suite: ${testSuite}`);
241
+ try {
242
+ const res = await fetch(`${API_URL}/ghost/run`, {
243
+ method: "POST",
244
+ headers: { "Content-Type": "application/json" },
245
+ body: JSON.stringify({
246
+ testSuite,
247
+ duration: 300
248
+ })
249
+ });
250
+ if (!res.ok) throw new Error(res.statusText);
251
+ const data = await res.json();
252
+ console.log(`> Session Started!`);
253
+ console.log(`> Session ID: \x1B[36m${data.sessionId}\x1B[0m`);
254
+ console.log(`> Status: ${data.runStatus || "running"}`);
255
+ console.log(`
256
+ > To check status: forbocai ghost status ${data.sessionId}`);
257
+ console.log(`> To get results: forbocai ghost results ${data.sessionId}`);
258
+ } catch (e) {
259
+ console.error(`> Failed to start Ghost session:`, e);
260
+ }
261
+ }
262
+ async function ghostStatus(sessionId) {
263
+ if (!sessionId) {
264
+ console.error("Error: Session ID required");
265
+ return;
266
+ }
267
+ console.log(`> Checking Ghost session: ${sessionId}...`);
268
+ try {
269
+ const res = await fetch(`${API_URL}/ghost/${sessionId}/status`, {
270
+ method: "GET",
271
+ headers: { "Content-Type": "application/json" }
272
+ });
273
+ if (!res.ok) throw new Error(res.statusText);
274
+ const data = await res.json();
275
+ const statusColor = data.ghostStatus === "completed" ? "\x1B[32m" : data.ghostStatus === "failed" ? "\x1B[31m" : "\x1B[33m";
276
+ console.log(`> Status: ${statusColor}${data.ghostStatus?.toUpperCase()}\x1B[0m`);
277
+ console.log(`> Progress: ${data.ghostProgress || 0}%`);
278
+ console.log(`> Duration: ${data.ghostDuration || 0}s`);
279
+ console.log(`> Errors: ${data.ghostErrors || 0}`);
280
+ } catch (e) {
281
+ console.error(`> Failed to get Ghost status:`, e);
282
+ }
283
+ }
284
+ async function ghostResults(sessionId) {
285
+ if (!sessionId) {
286
+ console.error("Error: Session ID required");
287
+ return;
288
+ }
289
+ console.log(`> Fetching Ghost results: ${sessionId}...`);
290
+ try {
291
+ const res = await fetch(`${API_URL}/ghost/${sessionId}/results`, {
292
+ method: "GET",
293
+ headers: { "Content-Type": "application/json" }
294
+ });
295
+ if (!res.ok) throw new Error(res.statusText);
296
+ const data = await res.json();
297
+ console.log(`
298
+ \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`);
299
+ console.log(`\u2551 Ghost QA Results \u2551`);
300
+ 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
301
+ `);
302
+ const passRate = data.resultsTotalTests > 0 ? (data.resultsPassed / data.resultsTotalTests * 100).toFixed(1) : 0;
303
+ console.log(` Total Tests: ${data.resultsTotalTests}`);
304
+ console.log(` \x1B[32mPassed: ${data.resultsPassed}\x1B[0m`);
305
+ console.log(` \x1B[31mFailed: ${data.resultsFailed}\x1B[0m`);
306
+ console.log(` Pass Rate: ${passRate}%`);
307
+ console.log(` Duration: ${data.resultsDuration}ms`);
308
+ console.log(` Coverage: ${((data.resultsCoverage || 0) * 100).toFixed(1)}%`);
309
+ if (data.resultsMetrics) {
310
+ console.log(`
311
+ Metrics:`);
312
+ for (const [key, value] of data.resultsMetrics) {
313
+ console.log(` ${key}: ${value}`);
314
+ }
315
+ }
316
+ if (data.resultsTests && data.resultsTests.length > 0) {
317
+ console.log(`
318
+ Tests:`);
319
+ data.resultsTests.forEach((test) => {
320
+ const icon = test.testPassed ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
321
+ console.log(` ${icon} ${test.testName} (${test.testDuration}ms)`);
322
+ if (test.testError) {
323
+ console.log(` \x1B[31mError: ${test.testError}\x1B[0m`);
324
+ }
325
+ });
326
+ }
327
+ } catch (e) {
328
+ console.error(`> Failed to get Ghost results:`, e);
329
+ }
330
+ }
331
+ async function listModels() {
332
+ console.log(`> Fetching available models...`);
333
+ try {
334
+ const res = await fetch(`${API_URL}/cortex/models`, {
335
+ method: "GET",
336
+ headers: { "Content-Type": "application/json" }
337
+ });
338
+ if (!res.ok) throw new Error(res.statusText);
339
+ const data = await res.json();
340
+ console.log(`
341
+ Available Models:
342
+ `);
343
+ data.forEach((model) => {
344
+ console.log(` \x1B[36m${model.id}\x1B[0m`);
345
+ console.log(` Name: ${model.name}`);
346
+ console.log(` Parameters: ${(model.parameters / 1e6).toFixed(0)}M`);
347
+ console.log(` Size: ${model.downloadSize}`);
348
+ console.log(` Capabilities: ${model.capabilities?.join(", ") || "N/A"}`);
349
+ console.log("");
350
+ });
351
+ } catch (e) {
352
+ console.error(`> Failed to list models:`, e);
353
+ }
354
+ }
108
355
  function printUsage() {
109
- console.log("Usage:");
110
- console.log(" forbocai api status");
111
- console.log(" forbocai agent create [<persona>]");
112
- console.log(" forbocai soul export <agentId>");
113
- console.log(" forbocai soul import <cid>");
114
- console.log("\nEnvironment:");
115
- console.log(" FORBOC_API_URL Override API URL (default: render)");
356
+ console.log(`
357
+ \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
358
+ \u2551 ForbocAI CLI v0.1.0 \u2551
359
+ \u2551 The Neuro-Symbolic Grid Interface \u2551
360
+ \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
361
+
362
+ \x1B[1mUsage:\x1B[0m
363
+ forbocai <command> <subcommand> [options]
364
+
365
+ \x1B[1mAPI Commands:\x1B[0m
366
+ api status Check API connection and version
367
+
368
+ \x1B[1mAgent Commands:\x1B[0m
369
+ agent create [persona] Create a new agent
370
+ agent list List all agents
371
+ agent chat <agentId> Interactive chat with an agent
372
+ agent delete <agentId> Delete an agent
373
+
374
+ \x1B[1mSoul Commands:\x1B[0m
375
+ soul export <agentId> Export agent to IPFS
376
+ soul import <cid> Import agent from IPFS
377
+ soul chat <cid> Wake and chat with a Soul
378
+
379
+ \x1B[1mGhost Commands:\x1B[0m
380
+ ghost run [suite] Start QA test session
381
+ ghost status <id> Check session progress
382
+ ghost results <id> Get test results
383
+
384
+ \x1B[1mCortex Commands:\x1B[0m
385
+ cortex models List available SLM models
386
+
387
+ \x1B[1mEnvironment:\x1B[0m
388
+ FORBOC_API_URL Override API URL (default: render)
389
+
390
+ \x1B[1mExamples:\x1B[0m
391
+ forbocai api status
392
+ forbocai agent create "A wise old wizard"
393
+ forbocai agent chat agent_abc123
394
+ forbocai ghost run exploration
395
+ forbocai soul chat QmXyz...
396
+ `);
116
397
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forbocai",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "The Infrastructure Layer for Autonomous AI Characters",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",