cograph 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/dist/chunk-7VVBEUZQ.js +48 -0
- package/dist/chunk-7VVBEUZQ.js.map +1 -0
- package/dist/chunk-YVKKUWD7.js +280 -0
- package/dist/chunk-YVKKUWD7.js.map +1 -0
- package/dist/cli.js +13 -271
- package/dist/cli.js.map +1 -1
- package/dist/index.js +33 -6
- package/dist/index.js.map +1 -1
- package/dist/login-Z3IUOAOB.js +126 -0
- package/dist/login-Z3IUOAOB.js.map +1 -0
- package/dist/shell-OM3FX2O2.js +330 -0
- package/dist/shell-OM3FX2O2.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
Client,
|
|
4
|
+
CographError
|
|
5
|
+
} from "./chunk-YVKKUWD7.js";
|
|
6
|
+
import "./chunk-7VVBEUZQ.js";
|
|
7
|
+
|
|
8
|
+
// src/shell.ts
|
|
9
|
+
import * as readline from "readline";
|
|
10
|
+
import { stdin, stdout } from "process";
|
|
11
|
+
var CYAN = "\x1B[36m";
|
|
12
|
+
var CYAN_BOLD = "\x1B[1;36m";
|
|
13
|
+
var DIM = "\x1B[2m";
|
|
14
|
+
var RED = "\x1B[31m";
|
|
15
|
+
var GREEN = "\x1B[32m";
|
|
16
|
+
var YELLOW = "\x1B[33m";
|
|
17
|
+
var BOLD = "\x1B[1m";
|
|
18
|
+
var RESET = "\x1B[0m";
|
|
19
|
+
function fmtNum(n) {
|
|
20
|
+
return n.toLocaleString("en-US");
|
|
21
|
+
}
|
|
22
|
+
function showBanner() {
|
|
23
|
+
const lines = [
|
|
24
|
+
"",
|
|
25
|
+
`${CYAN} \u2591\u2588\u2580\u2580\u2591\u2588\u2580\u2588\u2591\u2588\u2580\u2580\u2591\u2588\u2580\u2584\u2591\u2588\u2580\u2588\u2591\u2588\u2580\u2588\u2591\u2588\u2591\u2588${RESET}`,
|
|
26
|
+
`${CYAN} \u2591\u2588\u2591\u2591\u2591\u2588\u2591\u2588\u2591\u2588\u2591\u2588\u2591\u2588\u2580\u2584\u2591\u2588\u2580\u2588\u2591\u2588\u2580\u2580\u2591\u2588\u2580\u2588${RESET}`,
|
|
27
|
+
`${CYAN} \u2591\u2580\u2580\u2580\u2591\u2580\u2580\u2580\u2591\u2580\u2580\u2580\u2591\u2580\u2591\u2580\u2591\u2580\u2591\u2580\u2591\u2591\u2591\u2580\u2591\u2580${RESET}`,
|
|
28
|
+
"",
|
|
29
|
+
`${DIM} The object graph for AI agents${RESET}`,
|
|
30
|
+
""
|
|
31
|
+
];
|
|
32
|
+
for (const l of lines) stdout.write(l + "\n");
|
|
33
|
+
showCommands();
|
|
34
|
+
}
|
|
35
|
+
function showCommands() {
|
|
36
|
+
const rows = [
|
|
37
|
+
["/ingest <file> ...", "Ingest a CSV/JSON/text file"],
|
|
38
|
+
["/ask <question>", "Ask in natural language"],
|
|
39
|
+
["/status", "Show graph stats"],
|
|
40
|
+
["/reset", "Clear the current KG"],
|
|
41
|
+
["/help", "Show this command list"],
|
|
42
|
+
["/quit", "Exit"]
|
|
43
|
+
];
|
|
44
|
+
const colWidth = Math.max(...rows.map((r) => r[0].length));
|
|
45
|
+
for (const [cmd, desc] of rows) {
|
|
46
|
+
const pad = " ".repeat(colWidth - cmd.length);
|
|
47
|
+
stdout.write(` ${CYAN_BOLD}${cmd}${RESET}${pad} ${DIM}${desc}${RESET}
|
|
48
|
+
`);
|
|
49
|
+
}
|
|
50
|
+
stdout.write("\n");
|
|
51
|
+
}
|
|
52
|
+
function printError(msg) {
|
|
53
|
+
stdout.write(` ${RED}\u2717${RESET} ${msg}
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
async function fetchKg(client, name) {
|
|
57
|
+
try {
|
|
58
|
+
const kgs = await client.listKgs();
|
|
59
|
+
const found = kgs.find((k) => k.name === name);
|
|
60
|
+
if (!found) return null;
|
|
61
|
+
const tc = found.triple_count ?? 0;
|
|
62
|
+
return { name, triple_count: typeof tc === "number" ? tc : 0 };
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function ask(rl, prompt) {
|
|
68
|
+
return new Promise((resolve) => {
|
|
69
|
+
rl.question(prompt, (answer) => resolve(answer));
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function selectKg(client, rl) {
|
|
73
|
+
let kgs = [];
|
|
74
|
+
try {
|
|
75
|
+
kgs = await client.listKgs();
|
|
76
|
+
} catch (err) {
|
|
77
|
+
printError(
|
|
78
|
+
`Could not list knowledge graphs: ${err instanceof Error ? err.message : String(err)}`
|
|
79
|
+
);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (kgs.length === 0) {
|
|
83
|
+
stdout.write(
|
|
84
|
+
` ${DIM}No knowledge graphs found. Enter a name to create one on first ingest.${RESET}
|
|
85
|
+
`
|
|
86
|
+
);
|
|
87
|
+
const name = (await ask(rl, " KG name: ")).trim();
|
|
88
|
+
return name || null;
|
|
89
|
+
}
|
|
90
|
+
if (kgs.length === 1) {
|
|
91
|
+
const only = kgs[0].name;
|
|
92
|
+
if (only) {
|
|
93
|
+
stdout.write(` ${DIM}Using only available KG: ${BOLD}${only}${RESET}
|
|
94
|
+
`);
|
|
95
|
+
return only;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
stdout.write(` ${BOLD}Available knowledge graphs:${RESET}
|
|
99
|
+
`);
|
|
100
|
+
kgs.forEach((kg, i) => {
|
|
101
|
+
const n = kg.name ?? "?";
|
|
102
|
+
const tc = kg.triple_count ?? 0;
|
|
103
|
+
stdout.write(` ${CYAN}${i + 1}${RESET}. ${n} ${DIM}(${fmtNum(tc)} triples)${RESET}
|
|
104
|
+
`);
|
|
105
|
+
});
|
|
106
|
+
const pick = (await ask(rl, " Select KG [1]: ")).trim() || "1";
|
|
107
|
+
const idx = Number.parseInt(pick, 10);
|
|
108
|
+
if (Number.isFinite(idx) && idx >= 1 && idx <= kgs.length) {
|
|
109
|
+
const name = kgs[idx - 1].name;
|
|
110
|
+
if (name) return name;
|
|
111
|
+
}
|
|
112
|
+
if (pick && !/^\d+$/.test(pick)) return pick;
|
|
113
|
+
printError("Invalid selection.");
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
async function cmdIngest(client, kg, args) {
|
|
117
|
+
if (args.length === 0) {
|
|
118
|
+
stdout.write(` ${YELLOW}Usage:${RESET} /ingest <file> [<file>...]
|
|
119
|
+
`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
for (const file of args) {
|
|
123
|
+
stdout.write(` ${DIM}${file}${RESET}
|
|
124
|
+
`);
|
|
125
|
+
try {
|
|
126
|
+
const result = await client.ingest(file, { kg });
|
|
127
|
+
const ents = result.entities_resolved ?? 0;
|
|
128
|
+
const trip = result.triples_inserted ?? 0;
|
|
129
|
+
stdout.write(
|
|
130
|
+
` ${GREEN}\u2713${RESET} ${fmtNum(ents)} entities \xB7 ${fmtNum(trip)} triples
|
|
131
|
+
`
|
|
132
|
+
);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
if (err instanceof CographError) printError(err.message);
|
|
135
|
+
else printError(err instanceof Error ? err.message : String(err));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function cmdAsk(client, kg, question) {
|
|
140
|
+
const q = question.trim();
|
|
141
|
+
if (!q) {
|
|
142
|
+
stdout.write(` ${YELLOW}Usage:${RESET} /ask <your question>
|
|
143
|
+
`);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const result = await client.ask(q, { kg });
|
|
148
|
+
const answer = result.narrative_answer || result.answer || "No answer generated.";
|
|
149
|
+
stdout.write("\n");
|
|
150
|
+
stdout.write(` ${answer}
|
|
151
|
+
`);
|
|
152
|
+
stdout.write("\n");
|
|
153
|
+
} catch (err) {
|
|
154
|
+
if (err instanceof CographError) printError(err.message);
|
|
155
|
+
else printError(err instanceof Error ? err.message : String(err));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function cmdStatus(client, kg) {
|
|
159
|
+
try {
|
|
160
|
+
const info = await fetchKg(client, kg);
|
|
161
|
+
stdout.write("\n");
|
|
162
|
+
stdout.write(` ${BOLD}KG${RESET} ${kg}
|
|
163
|
+
`);
|
|
164
|
+
if (info) {
|
|
165
|
+
stdout.write(` ${BOLD}Triples${RESET} ${fmtNum(info.triple_count)}
|
|
166
|
+
`);
|
|
167
|
+
} else {
|
|
168
|
+
stdout.write(` ${BOLD}Triples${RESET} ${DIM}(empty)${RESET}
|
|
169
|
+
`);
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
const types = await client.ontologyTypes();
|
|
173
|
+
const names = types.map((t) => t.name).filter((n) => Boolean(n));
|
|
174
|
+
if (names.length > 0) {
|
|
175
|
+
stdout.write(` ${BOLD}Types${RESET} ${names.join(", ")}
|
|
176
|
+
`);
|
|
177
|
+
} else {
|
|
178
|
+
stdout.write(` ${BOLD}Types${RESET} ${DIM}(none)${RESET}
|
|
179
|
+
`);
|
|
180
|
+
}
|
|
181
|
+
} catch (err) {
|
|
182
|
+
printError(
|
|
183
|
+
`Could not list ontology types: ${err instanceof Error ? err.message : String(err)}`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
stdout.write("\n");
|
|
187
|
+
} catch (err) {
|
|
188
|
+
if (err instanceof CographError) printError(err.message);
|
|
189
|
+
else printError(err instanceof Error ? err.message : String(err));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async function cmdReset(client, kg, rl) {
|
|
193
|
+
const confirm = (await ask(rl, ` ${YELLOW}Delete KG "${kg}"?${RESET} [y/N]: `)).trim().toLowerCase();
|
|
194
|
+
if (confirm !== "y" && confirm !== "yes") {
|
|
195
|
+
stdout.write(` ${DIM}Cancelled.${RESET}
|
|
196
|
+
`);
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
await client.deleteKg(kg);
|
|
201
|
+
stdout.write(` ${GREEN}\u2713${RESET} Graph cleared.
|
|
202
|
+
`);
|
|
203
|
+
return true;
|
|
204
|
+
} catch (err) {
|
|
205
|
+
if (err instanceof CographError) printError(err.message);
|
|
206
|
+
else printError(err instanceof Error ? err.message : String(err));
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function makePrompt(triples) {
|
|
211
|
+
if (triples > 0) {
|
|
212
|
+
return ` ${CYAN_BOLD}cograph${RESET} ${DIM}[${fmtNum(triples)}]${RESET} ${CYAN_BOLD}\u25B8${RESET} `;
|
|
213
|
+
}
|
|
214
|
+
return ` ${CYAN_BOLD}cograph \u25B8${RESET} `;
|
|
215
|
+
}
|
|
216
|
+
function splitArgs(s) {
|
|
217
|
+
const out = [];
|
|
218
|
+
let cur = "";
|
|
219
|
+
let inQ = false;
|
|
220
|
+
for (let i = 0; i < s.length; i++) {
|
|
221
|
+
const c = s[i];
|
|
222
|
+
if (inQ) {
|
|
223
|
+
if (c === '"') inQ = false;
|
|
224
|
+
else cur += c;
|
|
225
|
+
} else {
|
|
226
|
+
if (c === '"') inQ = true;
|
|
227
|
+
else if (c === " " || c === " ") {
|
|
228
|
+
if (cur) {
|
|
229
|
+
out.push(cur);
|
|
230
|
+
cur = "";
|
|
231
|
+
}
|
|
232
|
+
} else cur += c;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (cur) out.push(cur);
|
|
236
|
+
return out;
|
|
237
|
+
}
|
|
238
|
+
async function runShell(opts) {
|
|
239
|
+
const client = new Client();
|
|
240
|
+
const rl = readline.createInterface({
|
|
241
|
+
input: stdin,
|
|
242
|
+
output: stdout,
|
|
243
|
+
terminal: true
|
|
244
|
+
});
|
|
245
|
+
showBanner();
|
|
246
|
+
let kg = opts.kg;
|
|
247
|
+
if (!kg) {
|
|
248
|
+
const picked = await selectKg(client, rl);
|
|
249
|
+
if (!picked) {
|
|
250
|
+
rl.close();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
kg = picked;
|
|
254
|
+
}
|
|
255
|
+
let triples = 0;
|
|
256
|
+
const info = await fetchKg(client, kg);
|
|
257
|
+
if (info && info.triple_count > 0) {
|
|
258
|
+
triples = info.triple_count;
|
|
259
|
+
stdout.write(
|
|
260
|
+
` ${DIM}Connected to${RESET} ${BOLD}${kg}${RESET}${DIM}: ${fmtNum(triples)} triples${RESET}
|
|
261
|
+
|
|
262
|
+
`
|
|
263
|
+
);
|
|
264
|
+
} else {
|
|
265
|
+
stdout.write(
|
|
266
|
+
` ${DIM}Connected \u2014 ${kg} is empty (use /ingest to add data)${RESET}
|
|
267
|
+
|
|
268
|
+
`
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
const refresh = async () => {
|
|
272
|
+
const fresh = await fetchKg(client, kg);
|
|
273
|
+
triples = fresh?.triple_count ?? 0;
|
|
274
|
+
};
|
|
275
|
+
let running = true;
|
|
276
|
+
rl.on("close", () => {
|
|
277
|
+
running = false;
|
|
278
|
+
});
|
|
279
|
+
while (running) {
|
|
280
|
+
let line;
|
|
281
|
+
try {
|
|
282
|
+
line = (await ask(rl, makePrompt(triples))).trim();
|
|
283
|
+
} catch {
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
if (!running) break;
|
|
287
|
+
if (!line) continue;
|
|
288
|
+
if (line === "/quit" || line === "/exit" || line === "/q") {
|
|
289
|
+
stdout.write(` ${DIM}Bye.${RESET}
|
|
290
|
+
`);
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
if (line === "/help") {
|
|
294
|
+
showCommands();
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
if (line.startsWith("/ingest")) {
|
|
299
|
+
const args = splitArgs(line.slice("/ingest".length).trim());
|
|
300
|
+
await cmdIngest(client, kg, args);
|
|
301
|
+
await refresh();
|
|
302
|
+
} else if (line.startsWith("/ask ")) {
|
|
303
|
+
await cmdAsk(client, kg, line.slice("/ask ".length));
|
|
304
|
+
} else if (line === "/ask") {
|
|
305
|
+
await cmdAsk(client, kg, "");
|
|
306
|
+
} else if (line === "/status") {
|
|
307
|
+
await cmdStatus(client, kg);
|
|
308
|
+
await refresh();
|
|
309
|
+
} else if (line === "/reset") {
|
|
310
|
+
const did = await cmdReset(client, kg, rl);
|
|
311
|
+
if (did) await refresh();
|
|
312
|
+
} else if (line.startsWith("/")) {
|
|
313
|
+
stdout.write(
|
|
314
|
+
` ${YELLOW}Unknown command.${RESET} Try /ingest, /ask, /status, /reset, /help, /quit
|
|
315
|
+
`
|
|
316
|
+
);
|
|
317
|
+
} else {
|
|
318
|
+
await cmdAsk(client, kg, line);
|
|
319
|
+
}
|
|
320
|
+
} catch (err) {
|
|
321
|
+
if (err instanceof CographError) printError(err.message);
|
|
322
|
+
else printError(err instanceof Error ? err.message : String(err));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
rl.close();
|
|
326
|
+
}
|
|
327
|
+
export {
|
|
328
|
+
runShell
|
|
329
|
+
};
|
|
330
|
+
//# sourceMappingURL=shell-OM3FX2O2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shell.ts"],"sourcesContent":["import * as readline from \"node:readline\";\nimport { stdin, stdout } from \"node:process\";\nimport { Client, CographError } from \"./client.js\";\n\nconst CYAN = \"\\x1b[36m\";\nconst CYAN_BOLD = \"\\x1b[1;36m\";\nconst DIM = \"\\x1b[2m\";\nconst RED = \"\\x1b[31m\";\nconst GREEN = \"\\x1b[32m\";\nconst YELLOW = \"\\x1b[33m\";\nconst BOLD = \"\\x1b[1m\";\nconst RESET = \"\\x1b[0m\";\n\nfunction fmtNum(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n\nfunction showBanner(): void {\n const lines = [\n \"\",\n `${CYAN} ░█▀▀░█▀█░█▀▀░█▀▄░█▀█░█▀█░█░█${RESET}`,\n `${CYAN} ░█░░░█░█░█░█░█▀▄░█▀█░█▀▀░█▀█${RESET}`,\n `${CYAN} ░▀▀▀░▀▀▀░▀▀▀░▀░▀░▀░▀░░░▀░▀${RESET}`,\n \"\",\n `${DIM} The object graph for AI agents${RESET}`,\n \"\",\n ];\n for (const l of lines) stdout.write(l + \"\\n\");\n showCommands();\n}\n\nfunction showCommands(): void {\n const rows: Array<[string, string]> = [\n [\"/ingest <file> ...\", \"Ingest a CSV/JSON/text file\"],\n [\"/ask <question>\", \"Ask in natural language\"],\n [\"/status\", \"Show graph stats\"],\n [\"/reset\", \"Clear the current KG\"],\n [\"/help\", \"Show this command list\"],\n [\"/quit\", \"Exit\"],\n ];\n const colWidth = Math.max(...rows.map((r) => r[0].length));\n for (const [cmd, desc] of rows) {\n const pad = \" \".repeat(colWidth - cmd.length);\n stdout.write(` ${CYAN_BOLD}${cmd}${RESET}${pad} ${DIM}${desc}${RESET}\\n`);\n }\n stdout.write(\"\\n\");\n}\n\nfunction printError(msg: string): void {\n stdout.write(` ${RED}✗${RESET} ${msg}\\n`);\n}\n\ninterface KgInfo {\n name: string;\n triple_count: number;\n}\n\nasync function fetchKg(client: Client, name: string): Promise<KgInfo | null> {\n try {\n const kgs = await client.listKgs();\n const found = kgs.find((k) => (k as { name?: string }).name === name);\n if (!found) return null;\n const tc = (found as { triple_count?: number }).triple_count ?? 0;\n return { name, triple_count: typeof tc === \"number\" ? tc : 0 };\n } catch {\n return null;\n }\n}\n\nfunction ask(rl: readline.Interface, prompt: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(prompt, (answer) => resolve(answer));\n });\n}\n\nasync function selectKg(\n client: Client,\n rl: readline.Interface,\n): Promise<string | null> {\n let kgs: Array<Record<string, unknown>> = [];\n try {\n kgs = await client.listKgs();\n } catch (err) {\n printError(\n `Could not list knowledge graphs: ${err instanceof Error ? err.message : String(err)}`,\n );\n return null;\n }\n\n if (kgs.length === 0) {\n stdout.write(\n ` ${DIM}No knowledge graphs found. Enter a name to create one on first ingest.${RESET}\\n`,\n );\n const name = (await ask(rl, \" KG name: \")).trim();\n return name || null;\n }\n\n if (kgs.length === 1) {\n const only = (kgs[0] as { name?: string }).name;\n if (only) {\n stdout.write(` ${DIM}Using only available KG: ${BOLD}${only}${RESET}\\n`);\n return only;\n }\n }\n\n stdout.write(` ${BOLD}Available knowledge graphs:${RESET}\\n`);\n kgs.forEach((kg, i) => {\n const n = (kg as { name?: string }).name ?? \"?\";\n const tc = (kg as { triple_count?: number }).triple_count ?? 0;\n stdout.write(` ${CYAN}${i + 1}${RESET}. ${n} ${DIM}(${fmtNum(tc)} triples)${RESET}\\n`);\n });\n const pick = (await ask(rl, \" Select KG [1]: \")).trim() || \"1\";\n const idx = Number.parseInt(pick, 10);\n if (Number.isFinite(idx) && idx >= 1 && idx <= kgs.length) {\n const name = (kgs[idx - 1] as { name?: string }).name;\n if (name) return name;\n }\n // Allow typing a name directly\n if (pick && !/^\\d+$/.test(pick)) return pick;\n printError(\"Invalid selection.\");\n return null;\n}\n\nasync function cmdIngest(\n client: Client,\n kg: string,\n args: string[],\n): Promise<void> {\n if (args.length === 0) {\n stdout.write(` ${YELLOW}Usage:${RESET} /ingest <file> [<file>...]\\n`);\n return;\n }\n for (const file of args) {\n stdout.write(` ${DIM}${file}${RESET}\\n`);\n try {\n const result = await client.ingest(file, { kg });\n const ents =\n (result as { entities_resolved?: number }).entities_resolved ?? 0;\n const trip =\n (result as { triples_inserted?: number }).triples_inserted ?? 0;\n stdout.write(\n ` ${GREEN}✓${RESET} ${fmtNum(ents)} entities · ${fmtNum(trip)} triples\\n`,\n );\n } catch (err) {\n if (err instanceof CographError) printError(err.message);\n else printError(err instanceof Error ? err.message : String(err));\n }\n }\n}\n\nasync function cmdAsk(\n client: Client,\n kg: string,\n question: string,\n): Promise<void> {\n const q = question.trim();\n if (!q) {\n stdout.write(` ${YELLOW}Usage:${RESET} /ask <your question>\\n`);\n return;\n }\n try {\n const result = await client.ask(q, { kg });\n const answer =\n (result as { narrative_answer?: string }).narrative_answer ||\n (result as { answer?: string }).answer ||\n \"No answer generated.\";\n stdout.write(\"\\n\");\n stdout.write(` ${answer}\\n`);\n stdout.write(\"\\n\");\n } catch (err) {\n if (err instanceof CographError) printError(err.message);\n else printError(err instanceof Error ? err.message : String(err));\n }\n}\n\nasync function cmdStatus(client: Client, kg: string): Promise<void> {\n try {\n const info = await fetchKg(client, kg);\n stdout.write(\"\\n\");\n stdout.write(` ${BOLD}KG${RESET} ${kg}\\n`);\n if (info) {\n stdout.write(` ${BOLD}Triples${RESET} ${fmtNum(info.triple_count)}\\n`);\n } else {\n stdout.write(` ${BOLD}Triples${RESET} ${DIM}(empty)${RESET}\\n`);\n }\n try {\n const types = await client.ontologyTypes();\n const names = types\n .map((t) => (t as { name?: string }).name)\n .filter((n): n is string => Boolean(n));\n if (names.length > 0) {\n stdout.write(` ${BOLD}Types${RESET} ${names.join(\", \")}\\n`);\n } else {\n stdout.write(` ${BOLD}Types${RESET} ${DIM}(none)${RESET}\\n`);\n }\n } catch (err) {\n printError(\n `Could not list ontology types: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n stdout.write(\"\\n\");\n } catch (err) {\n if (err instanceof CographError) printError(err.message);\n else printError(err instanceof Error ? err.message : String(err));\n }\n}\n\nasync function cmdReset(\n client: Client,\n kg: string,\n rl: readline.Interface,\n): Promise<boolean> {\n const confirm = (\n await ask(rl, ` ${YELLOW}Delete KG \"${kg}\"?${RESET} [y/N]: `)\n )\n .trim()\n .toLowerCase();\n if (confirm !== \"y\" && confirm !== \"yes\") {\n stdout.write(` ${DIM}Cancelled.${RESET}\\n`);\n return false;\n }\n try {\n await client.deleteKg(kg);\n stdout.write(` ${GREEN}✓${RESET} Graph cleared.\\n`);\n return true;\n } catch (err) {\n if (err instanceof CographError) printError(err.message);\n else printError(err instanceof Error ? err.message : String(err));\n return false;\n }\n}\n\nfunction makePrompt(triples: number): string {\n if (triples > 0) {\n return ` ${CYAN_BOLD}cograph${RESET} ${DIM}[${fmtNum(triples)}]${RESET} ${CYAN_BOLD}▸${RESET} `;\n }\n return ` ${CYAN_BOLD}cograph ▸${RESET} `;\n}\n\n/**\n * Split a command-line style argument string. Supports double-quoted args.\n */\nfunction splitArgs(s: string): string[] {\n const out: string[] = [];\n let cur = \"\";\n let inQ = false;\n for (let i = 0; i < s.length; i++) {\n const c = s[i];\n if (inQ) {\n if (c === '\"') inQ = false;\n else cur += c;\n } else {\n if (c === '\"') inQ = true;\n else if (c === \" \" || c === \"\\t\") {\n if (cur) {\n out.push(cur);\n cur = \"\";\n }\n } else cur += c;\n }\n }\n if (cur) out.push(cur);\n return out;\n}\n\nexport async function runShell(opts: { kg?: string }): Promise<void> {\n const client = new Client();\n const rl = readline.createInterface({\n input: stdin,\n output: stdout,\n terminal: true,\n });\n\n showBanner();\n\n let kg = opts.kg;\n if (!kg) {\n const picked = await selectKg(client, rl);\n if (!picked) {\n rl.close();\n return;\n }\n kg = picked;\n }\n\n let triples = 0;\n const info = await fetchKg(client, kg);\n if (info && info.triple_count > 0) {\n triples = info.triple_count;\n stdout.write(\n ` ${DIM}Connected to${RESET} ${BOLD}${kg}${RESET}${DIM}: ${fmtNum(triples)} triples${RESET}\\n\\n`,\n );\n } else {\n stdout.write(\n ` ${DIM}Connected — ${kg} is empty (use /ingest to add data)${RESET}\\n\\n`,\n );\n }\n\n const refresh = async (): Promise<void> => {\n const fresh = await fetchKg(client, kg!);\n triples = fresh?.triple_count ?? 0;\n };\n\n let running = true;\n rl.on(\"close\", () => {\n running = false;\n });\n\n while (running) {\n let line: string;\n try {\n line = (await ask(rl, makePrompt(triples))).trim();\n } catch {\n break;\n }\n if (!running) break;\n if (!line) continue;\n\n if (line === \"/quit\" || line === \"/exit\" || line === \"/q\") {\n stdout.write(` ${DIM}Bye.${RESET}\\n`);\n break;\n }\n\n if (line === \"/help\") {\n showCommands();\n continue;\n }\n\n try {\n if (line.startsWith(\"/ingest\")) {\n const args = splitArgs(line.slice(\"/ingest\".length).trim());\n await cmdIngest(client, kg, args);\n await refresh();\n } else if (line.startsWith(\"/ask \")) {\n await cmdAsk(client, kg, line.slice(\"/ask \".length));\n } else if (line === \"/ask\") {\n await cmdAsk(client, kg, \"\");\n } else if (line === \"/status\") {\n await cmdStatus(client, kg);\n await refresh();\n } else if (line === \"/reset\") {\n const did = await cmdReset(client, kg, rl);\n if (did) await refresh();\n } else if (line.startsWith(\"/\")) {\n stdout.write(\n ` ${YELLOW}Unknown command.${RESET} Try /ingest, /ask, /status, /reset, /help, /quit\\n`,\n );\n } else {\n // Bare line — auto-route to /ask\n await cmdAsk(client, kg, line);\n }\n } catch (err) {\n if (err instanceof CographError) printError(err.message);\n else printError(err instanceof Error ? err.message : String(err));\n }\n }\n\n rl.close();\n}\n"],"mappings":";;;;;;;;AAAA,YAAY,cAAc;AAC1B,SAAS,OAAO,cAAc;AAG9B,IAAM,OAAO;AACb,IAAM,YAAY;AAClB,IAAM,MAAM;AACZ,IAAM,MAAM;AACZ,IAAM,QAAQ;AACd,IAAM,SAAS;AACf,IAAM,OAAO;AACb,IAAM,QAAQ;AAEd,SAAS,OAAO,GAAmB;AACjC,SAAO,EAAE,eAAe,OAAO;AACjC;AAEA,SAAS,aAAmB;AAC1B,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,GAAG,IAAI,+KAAmC,KAAK;AAAA,IAC/C,GAAG,IAAI,+KAAmC,KAAK;AAAA,IAC/C,GAAG,IAAI,mKAAiC,KAAK;AAAA,IAC7C;AAAA,IACA,GAAG,GAAG,qCAAqC,KAAK;AAAA,IAChD;AAAA,EACF;AACA,aAAW,KAAK,MAAO,QAAO,MAAM,IAAI,IAAI;AAC5C,eAAa;AACf;AAEA,SAAS,eAAqB;AAC5B,QAAM,OAAgC;AAAA,IACpC,CAAC,sBAAsB,6BAA6B;AAAA,IACpD,CAAC,mBAAmB,yBAAyB;AAAA,IAC7C,CAAC,WAAW,kBAAkB;AAAA,IAC9B,CAAC,UAAU,sBAAsB;AAAA,IACjC,CAAC,SAAS,wBAAwB;AAAA,IAClC,CAAC,SAAS,MAAM;AAAA,EAClB;AACA,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC;AACzD,aAAW,CAAC,KAAK,IAAI,KAAK,MAAM;AAC9B,UAAM,MAAM,IAAI,OAAO,WAAW,IAAI,MAAM;AAC5C,WAAO,MAAM,OAAO,SAAS,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,MAAM,GAAG,GAAG,IAAI,GAAG,KAAK;AAAA,CAAI;AAAA,EAC/E;AACA,SAAO,MAAM,IAAI;AACnB;AAEA,SAAS,WAAW,KAAmB;AACrC,SAAO,MAAM,KAAK,GAAG,SAAI,KAAK,IAAI,GAAG;AAAA,CAAI;AAC3C;AAOA,eAAe,QAAQ,QAAgB,MAAsC;AAC3E,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,QAAQ;AACjC,UAAM,QAAQ,IAAI,KAAK,CAAC,MAAO,EAAwB,SAAS,IAAI;AACpE,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,KAAM,MAAoC,gBAAgB;AAChE,WAAO,EAAE,MAAM,cAAc,OAAO,OAAO,WAAW,KAAK,EAAE;AAAA,EAC/D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,IAAI,IAAwB,QAAiC;AACpE,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,OAAG,SAAS,QAAQ,CAAC,WAAW,QAAQ,MAAM,CAAC;AAAA,EACjD,CAAC;AACH;AAEA,eAAe,SACb,QACA,IACwB;AACxB,MAAI,MAAsC,CAAC;AAC3C,MAAI;AACF,UAAM,MAAM,OAAO,QAAQ;AAAA,EAC7B,SAAS,KAAK;AACZ;AAAA,MACE,oCAAoC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACtF;AACA,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,WAAW,GAAG;AACpB,WAAO;AAAA,MACL,KAAK,GAAG,yEAAyE,KAAK;AAAA;AAAA,IACxF;AACA,UAAM,QAAQ,MAAM,IAAI,IAAI,aAAa,GAAG,KAAK;AACjD,WAAO,QAAQ;AAAA,EACjB;AAEA,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,OAAQ,IAAI,CAAC,EAAwB;AAC3C,QAAI,MAAM;AACR,aAAO,MAAM,KAAK,GAAG,4BAA4B,IAAI,GAAG,IAAI,GAAG,KAAK;AAAA,CAAI;AACxE,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI,8BAA8B,KAAK;AAAA,CAAI;AAC7D,MAAI,QAAQ,CAAC,IAAI,MAAM;AACrB,UAAM,IAAK,GAAyB,QAAQ;AAC5C,UAAM,KAAM,GAAiC,gBAAgB;AAC7D,WAAO,MAAM,OAAO,IAAI,GAAG,IAAI,CAAC,GAAG,KAAK,KAAK,CAAC,IAAI,GAAG,IAAI,OAAO,EAAE,CAAC,YAAY,KAAK;AAAA,CAAI;AAAA,EAC1F,CAAC;AACD,QAAM,QAAQ,MAAM,IAAI,IAAI,mBAAmB,GAAG,KAAK,KAAK;AAC5D,QAAM,MAAM,OAAO,SAAS,MAAM,EAAE;AACpC,MAAI,OAAO,SAAS,GAAG,KAAK,OAAO,KAAK,OAAO,IAAI,QAAQ;AACzD,UAAM,OAAQ,IAAI,MAAM,CAAC,EAAwB;AACjD,QAAI,KAAM,QAAO;AAAA,EACnB;AAEA,MAAI,QAAQ,CAAC,QAAQ,KAAK,IAAI,EAAG,QAAO;AACxC,aAAW,oBAAoB;AAC/B,SAAO;AACT;AAEA,eAAe,UACb,QACA,IACA,MACe;AACf,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,MAAM,KAAK,MAAM,SAAS,KAAK;AAAA,CAA+B;AACrE;AAAA,EACF;AACA,aAAW,QAAQ,MAAM;AACvB,WAAO,MAAM,KAAK,GAAG,GAAG,IAAI,GAAG,KAAK;AAAA,CAAI;AACxC,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,OAAO,MAAM,EAAE,GAAG,CAAC;AAC/C,YAAM,OACH,OAA0C,qBAAqB;AAClE,YAAM,OACH,OAAyC,oBAAoB;AAChE,aAAO;AAAA,QACL,KAAK,KAAK,SAAI,KAAK,IAAI,OAAO,IAAI,CAAC,kBAAe,OAAO,IAAI,CAAC;AAAA;AAAA,MAChE;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,eAAe,aAAc,YAAW,IAAI,OAAO;AAAA,UAClD,YAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAClE;AAAA,EACF;AACF;AAEA,eAAe,OACb,QACA,IACA,UACe;AACf,QAAM,IAAI,SAAS,KAAK;AACxB,MAAI,CAAC,GAAG;AACN,WAAO,MAAM,KAAK,MAAM,SAAS,KAAK;AAAA,CAAyB;AAC/D;AAAA,EACF;AACA,MAAI;AACF,UAAM,SAAS,MAAM,OAAO,IAAI,GAAG,EAAE,GAAG,CAAC;AACzC,UAAM,SACH,OAAyC,oBACzC,OAA+B,UAChC;AACF,WAAO,MAAM,IAAI;AACjB,WAAO,MAAM,KAAK,MAAM;AAAA,CAAI;AAC5B,WAAO,MAAM,IAAI;AAAA,EACnB,SAAS,KAAK;AACZ,QAAI,eAAe,aAAc,YAAW,IAAI,OAAO;AAAA,QAClD,YAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EAClE;AACF;AAEA,eAAe,UAAU,QAAgB,IAA2B;AAClE,MAAI;AACF,UAAM,OAAO,MAAM,QAAQ,QAAQ,EAAE;AACrC,WAAO,MAAM,IAAI;AACjB,WAAO,MAAM,KAAK,IAAI,KAAK,KAAK,UAAU,EAAE;AAAA,CAAI;AAChD,QAAI,MAAM;AACR,aAAO,MAAM,KAAK,IAAI,UAAU,KAAK,KAAK,OAAO,KAAK,YAAY,CAAC;AAAA,CAAI;AAAA,IACzE,OAAO;AACL,aAAO,MAAM,KAAK,IAAI,UAAU,KAAK,KAAK,GAAG,UAAU,KAAK;AAAA,CAAI;AAAA,IAClE;AACA,QAAI;AACF,YAAM,QAAQ,MAAM,OAAO,cAAc;AACzC,YAAM,QAAQ,MACX,IAAI,CAAC,MAAO,EAAwB,IAAI,EACxC,OAAO,CAAC,MAAmB,QAAQ,CAAC,CAAC;AACxC,UAAI,MAAM,SAAS,GAAG;AACpB,eAAO,MAAM,KAAK,IAAI,QAAQ,KAAK,OAAO,MAAM,KAAK,IAAI,CAAC;AAAA,CAAI;AAAA,MAChE,OAAO;AACL,eAAO,MAAM,KAAK,IAAI,QAAQ,KAAK,OAAO,GAAG,SAAS,KAAK;AAAA,CAAI;AAAA,MACjE;AAAA,IACF,SAAS,KAAK;AACZ;AAAA,QACE,kCAAkC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACpF;AAAA,IACF;AACA,WAAO,MAAM,IAAI;AAAA,EACnB,SAAS,KAAK;AACZ,QAAI,eAAe,aAAc,YAAW,IAAI,OAAO;AAAA,QAClD,YAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EAClE;AACF;AAEA,eAAe,SACb,QACA,IACA,IACkB;AAClB,QAAM,WACJ,MAAM,IAAI,IAAI,KAAK,MAAM,cAAc,EAAE,KAAK,KAAK,UAAU,GAE5D,KAAK,EACL,YAAY;AACf,MAAI,YAAY,OAAO,YAAY,OAAO;AACxC,WAAO,MAAM,KAAK,GAAG,aAAa,KAAK;AAAA,CAAI;AAC3C,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,OAAO,SAAS,EAAE;AACxB,WAAO,MAAM,KAAK,KAAK,SAAI,KAAK;AAAA,CAAmB;AACnD,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QAAI,eAAe,aAAc,YAAW,IAAI,OAAO;AAAA,QAClD,YAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAChE,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WAAW,SAAyB;AAC3C,MAAI,UAAU,GAAG;AACf,WAAO,KAAK,SAAS,UAAU,KAAK,IAAI,GAAG,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,IAAI,SAAS,SAAI,KAAK;AAAA,EAC/F;AACA,SAAO,KAAK,SAAS,iBAAY,KAAK;AACxC;AAKA,SAAS,UAAU,GAAqB;AACtC,QAAM,MAAgB,CAAC;AACvB,MAAI,MAAM;AACV,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAM,IAAI,EAAE,CAAC;AACb,QAAI,KAAK;AACP,UAAI,MAAM,IAAK,OAAM;AAAA,UAChB,QAAO;AAAA,IACd,OAAO;AACL,UAAI,MAAM,IAAK,OAAM;AAAA,eACZ,MAAM,OAAO,MAAM,KAAM;AAChC,YAAI,KAAK;AACP,cAAI,KAAK,GAAG;AACZ,gBAAM;AAAA,QACR;AAAA,MACF,MAAO,QAAO;AAAA,IAChB;AAAA,EACF;AACA,MAAI,IAAK,KAAI,KAAK,GAAG;AACrB,SAAO;AACT;AAEA,eAAsB,SAAS,MAAsC;AACnE,QAAM,SAAS,IAAI,OAAO;AAC1B,QAAM,KAAc,yBAAgB;AAAA,IAClC,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AAED,aAAW;AAEX,MAAI,KAAK,KAAK;AACd,MAAI,CAAC,IAAI;AACP,UAAM,SAAS,MAAM,SAAS,QAAQ,EAAE;AACxC,QAAI,CAAC,QAAQ;AACX,SAAG,MAAM;AACT;AAAA,IACF;AACA,SAAK;AAAA,EACP;AAEA,MAAI,UAAU;AACd,QAAM,OAAO,MAAM,QAAQ,QAAQ,EAAE;AACrC,MAAI,QAAQ,KAAK,eAAe,GAAG;AACjC,cAAU,KAAK;AACf,WAAO;AAAA,MACL,KAAK,GAAG,eAAe,KAAK,IAAI,IAAI,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,KAAK,OAAO,OAAO,CAAC,WAAW,KAAK;AAAA;AAAA;AAAA,IAC7F;AAAA,EACF,OAAO;AACL,WAAO;AAAA,MACL,KAAK,GAAG,oBAAe,EAAE,sCAAsC,KAAK;AAAA;AAAA;AAAA,IACtE;AAAA,EACF;AAEA,QAAM,UAAU,YAA2B;AACzC,UAAM,QAAQ,MAAM,QAAQ,QAAQ,EAAG;AACvC,cAAU,OAAO,gBAAgB;AAAA,EACnC;AAEA,MAAI,UAAU;AACd,KAAG,GAAG,SAAS,MAAM;AACnB,cAAU;AAAA,EACZ,CAAC;AAED,SAAO,SAAS;AACd,QAAI;AACJ,QAAI;AACF,cAAQ,MAAM,IAAI,IAAI,WAAW,OAAO,CAAC,GAAG,KAAK;AAAA,IACnD,QAAQ;AACN;AAAA,IACF;AACA,QAAI,CAAC,QAAS;AACd,QAAI,CAAC,KAAM;AAEX,QAAI,SAAS,WAAW,SAAS,WAAW,SAAS,MAAM;AACzD,aAAO,MAAM,KAAK,GAAG,OAAO,KAAK;AAAA,CAAI;AACrC;AAAA,IACF;AAEA,QAAI,SAAS,SAAS;AACpB,mBAAa;AACb;AAAA,IACF;AAEA,QAAI;AACF,UAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,cAAM,OAAO,UAAU,KAAK,MAAM,UAAU,MAAM,EAAE,KAAK,CAAC;AAC1D,cAAM,UAAU,QAAQ,IAAI,IAAI;AAChC,cAAM,QAAQ;AAAA,MAChB,WAAW,KAAK,WAAW,OAAO,GAAG;AACnC,cAAM,OAAO,QAAQ,IAAI,KAAK,MAAM,QAAQ,MAAM,CAAC;AAAA,MACrD,WAAW,SAAS,QAAQ;AAC1B,cAAM,OAAO,QAAQ,IAAI,EAAE;AAAA,MAC7B,WAAW,SAAS,WAAW;AAC7B,cAAM,UAAU,QAAQ,EAAE;AAC1B,cAAM,QAAQ;AAAA,MAChB,WAAW,SAAS,UAAU;AAC5B,cAAM,MAAM,MAAM,SAAS,QAAQ,IAAI,EAAE;AACzC,YAAI,IAAK,OAAM,QAAQ;AAAA,MACzB,WAAW,KAAK,WAAW,GAAG,GAAG;AAC/B,eAAO;AAAA,UACL,KAAK,MAAM,mBAAmB,KAAK;AAAA;AAAA,QACrC;AAAA,MACF,OAAO;AAEL,cAAM,OAAO,QAAQ,IAAI,IAAI;AAAA,MAC/B;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,eAAe,aAAc,YAAW,IAAI,OAAO;AAAA,UAClD,YAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAClE;AAAA,EACF;AAEA,KAAG,MAAM;AACX;","names":[]}
|