cograph 0.1.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/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # cograph
2
+
3
+ Node.js SDK and CLI for [Cograph](https://cograph.cloud) — turn raw data into a queryable knowledge graph.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install cograph
9
+ ```
10
+
11
+ ## SDK
12
+
13
+ ```ts
14
+ import { Client, CographError } from "cograph";
15
+
16
+ const client = new Client({ apiKey: process.env.COGRAPH_API_KEY });
17
+
18
+ await client.ingest("sales.csv", { kg: "sales" });
19
+ const result = await client.ask("What's the average deal size by region?", { kg: "sales" });
20
+ console.log(result.answer);
21
+ ```
22
+
23
+ ### Constructor
24
+
25
+ ```ts
26
+ new Client({
27
+ apiKey?: string, // env: COGRAPH_API_KEY
28
+ baseUrl?: string, // env: COGRAPH_API_URL (default: https://api.cograph.cloud)
29
+ tenant?: string, // env: COGRAPH_TENANT (default: demo-tenant)
30
+ })
31
+ ```
32
+
33
+ ### Methods
34
+
35
+ - `ingest(pathOrText, { kg?, contentType? })` — auto-detects CSV by extension and uses two-step schema/rows flow; otherwise sends raw content.
36
+ - `ask(question, { kg? })` — returns `{ answer, sparql?, ... }`.
37
+ - `listKgs()` — list knowledge graphs.
38
+ - `deleteKg(name)` — delete a knowledge graph.
39
+
40
+ All errors throw `CographError`.
41
+
42
+ ## CLI
43
+
44
+ ```bash
45
+ # List / create / delete knowledge graphs
46
+ npx cograph kg list
47
+ npx cograph kg create my-data --description "demo"
48
+ npx cograph kg delete my-data
49
+
50
+ # Ingest data
51
+ npx cograph ingest data.csv --kg my-data
52
+ npx cograph ingest --text "Alice works at Acme" --kg my-data
53
+
54
+ # Ask questions
55
+ npx cograph ask "How many companies?" --kg my-data
56
+ npx cograph ask "Top 5 deals" --kg my-data --debug
57
+
58
+ # Ontology + clear
59
+ npx cograph ontology types
60
+ npx cograph clear --kg my-data --yes
61
+ ```
62
+
63
+ ### Environment
64
+
65
+ - `COGRAPH_API_KEY` — required
66
+ - `COGRAPH_API_URL` — default `https://api.cograph.cloud`
67
+ - `COGRAPH_TENANT` — default `demo-tenant`
68
+
69
+ Legacy `OMNIX_*` vars are also accepted.
70
+
71
+ > PDF ingestion is not yet supported in the Node CLI. Use the Python CLI or POST raw bytes to the API.
72
+
73
+ ## License
74
+
75
+ MIT
package/dist/cli.js ADDED
@@ -0,0 +1,550 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { createInterface } from "readline";
5
+ import { Command } from "commander";
6
+
7
+ // src/client.ts
8
+ import { existsSync, readFileSync, statSync } from "fs";
9
+ import { extname } from "path";
10
+ var CographError = class extends Error {
11
+ status;
12
+ body;
13
+ constructor(message, opts) {
14
+ super(message);
15
+ this.name = "CographError";
16
+ this.status = opts?.status;
17
+ this.body = opts?.body;
18
+ }
19
+ };
20
+ function envVar(name, fallback) {
21
+ return process.env[`COGRAPH_${name}`] || process.env[`OMNIX_${name}`] || fallback;
22
+ }
23
+ var EXT_FORMAT = {
24
+ ".csv": "csv",
25
+ ".json": "json",
26
+ ".jsonl": "json",
27
+ ".txt": "text"
28
+ };
29
+ function parseCsv(content) {
30
+ const rows = [];
31
+ let cur = [];
32
+ let field = "";
33
+ let inQuotes = false;
34
+ for (let i = 0; i < content.length; i++) {
35
+ const ch = content[i];
36
+ if (inQuotes) {
37
+ if (ch === '"') {
38
+ if (content[i + 1] === '"') {
39
+ field += '"';
40
+ i++;
41
+ } else {
42
+ inQuotes = false;
43
+ }
44
+ } else {
45
+ field += ch;
46
+ }
47
+ } else {
48
+ if (ch === '"') {
49
+ inQuotes = true;
50
+ } else if (ch === ",") {
51
+ cur.push(field);
52
+ field = "";
53
+ } else if (ch === "\n") {
54
+ cur.push(field);
55
+ rows.push(cur);
56
+ cur = [];
57
+ field = "";
58
+ } else if (ch === "\r") {
59
+ if (content[i + 1] !== "\n") {
60
+ cur.push(field);
61
+ rows.push(cur);
62
+ cur = [];
63
+ field = "";
64
+ }
65
+ } else {
66
+ field += ch;
67
+ }
68
+ }
69
+ }
70
+ if (field.length > 0 || cur.length > 0) {
71
+ cur.push(field);
72
+ rows.push(cur);
73
+ }
74
+ if (rows.length === 0) return [];
75
+ const headers = rows[0].map((h) => h.trim());
76
+ const out = [];
77
+ for (let r = 1; r < rows.length; r++) {
78
+ const row = rows[r];
79
+ if (row.length === 1 && row[0] === "") continue;
80
+ const obj = {};
81
+ for (let c = 0; c < headers.length; c++) {
82
+ obj[headers[c]] = row[c] ?? "";
83
+ }
84
+ out.push(obj);
85
+ }
86
+ return out;
87
+ }
88
+ var Client = class {
89
+ apiKey;
90
+ baseUrl;
91
+ tenant;
92
+ constructor(opts = {}) {
93
+ this.apiKey = opts.apiKey ?? envVar("API_KEY");
94
+ const url = opts.baseUrl ?? envVar("API_URL") ?? "https://api.cograph.cloud";
95
+ this.baseUrl = url.replace(/\/+$/, "");
96
+ this.tenant = opts.tenant ?? envVar("TENANT") ?? "demo-tenant";
97
+ }
98
+ headers() {
99
+ const h = { "Content-Type": "application/json" };
100
+ if (this.apiKey) h["X-API-Key"] = this.apiKey;
101
+ return h;
102
+ }
103
+ base() {
104
+ return `${this.baseUrl}/graphs/${this.tenant}`;
105
+ }
106
+ async request(method, url, body, timeoutMs = 12e4) {
107
+ const controller = new AbortController();
108
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
109
+ let res;
110
+ try {
111
+ res = await fetch(url, {
112
+ method,
113
+ headers: this.headers(),
114
+ body: body === void 0 ? void 0 : JSON.stringify(body),
115
+ signal: controller.signal
116
+ });
117
+ } catch (err) {
118
+ clearTimeout(timer);
119
+ if (err instanceof Error && err.name === "AbortError") {
120
+ throw new CographError(`Request to ${url} timed out after ${timeoutMs}ms`);
121
+ }
122
+ throw new CographError(
123
+ `Network error contacting ${url}: ${err instanceof Error ? err.message : String(err)}`
124
+ );
125
+ }
126
+ clearTimeout(timer);
127
+ if (!res.ok) {
128
+ let text2 = "";
129
+ try {
130
+ text2 = await res.text();
131
+ } catch {
132
+ }
133
+ throw new CographError(`HTTP ${res.status}: ${text2}`, {
134
+ status: res.status,
135
+ body: text2
136
+ });
137
+ }
138
+ if (res.status === 204) return void 0;
139
+ const ct = res.headers.get("content-type") ?? "";
140
+ if (ct.includes("application/json")) {
141
+ return await res.json();
142
+ }
143
+ const text = await res.text();
144
+ try {
145
+ return JSON.parse(text);
146
+ } catch {
147
+ return text;
148
+ }
149
+ }
150
+ /**
151
+ * Ingest a file path or raw text into a knowledge graph.
152
+ *
153
+ * If `pathOrText` points to an existing file, its contents are read and the
154
+ * format is inferred from the extension (.csv, .json, .txt) unless
155
+ * `contentType` is given. CSV files use the two-step schema-inference + row
156
+ * mapping flow.
157
+ */
158
+ async ingest(pathOrText, opts = {}) {
159
+ let content;
160
+ let fmt;
161
+ let isFile = false;
162
+ try {
163
+ isFile = existsSync(pathOrText) && statSync(pathOrText).isFile();
164
+ } catch {
165
+ isFile = false;
166
+ }
167
+ if (isFile) {
168
+ const ext = extname(pathOrText).toLowerCase();
169
+ if (ext === ".pdf") {
170
+ throw new CographError(
171
+ "PDF ingest not yet supported in the Node CLI; use the Python CLI or POST raw bytes to the API."
172
+ );
173
+ }
174
+ content = readFileSync(pathOrText, "utf-8");
175
+ fmt = opts.contentType ?? EXT_FORMAT[ext] ?? "text";
176
+ if (fmt === "csv") {
177
+ return this.ingestCsv(content, opts.kg);
178
+ }
179
+ } else {
180
+ content = pathOrText;
181
+ fmt = opts.contentType ?? "text";
182
+ }
183
+ const body = {
184
+ content,
185
+ content_type: fmt,
186
+ source: "client"
187
+ };
188
+ if (opts.kg) body.kg_name = opts.kg;
189
+ return this.request("POST", `${this.base()}/ingest`, body, 12e4);
190
+ }
191
+ async ingestCsv(content, kgName) {
192
+ const rows = parseCsv(content);
193
+ if (rows.length === 0) throw new CographError("CSV is empty");
194
+ const headers = Object.keys(rows[0]);
195
+ const schemaBody = {
196
+ headers,
197
+ sample_rows: rows.slice(0, 5),
198
+ total_rows: rows.length
199
+ };
200
+ const mapping = await this.request(
201
+ "POST",
202
+ `${this.base()}/ingest/csv/schema`,
203
+ schemaBody,
204
+ 3e5
205
+ );
206
+ const batchSize = 50;
207
+ let totalEntities = 0;
208
+ let totalTriples = 0;
209
+ for (let i = 0; i < rows.length; i += batchSize) {
210
+ const batch = rows.slice(i, i + batchSize);
211
+ const body = {
212
+ mapping,
213
+ rows: batch,
214
+ source: "client"
215
+ };
216
+ if (kgName) body.kg_name = kgName;
217
+ const result = await this.request("POST", `${this.base()}/ingest/csv/rows`, body, 3e5);
218
+ totalEntities += result.entities_resolved ?? 0;
219
+ totalTriples += result.triples_inserted ?? 0;
220
+ }
221
+ return {
222
+ entities_resolved: totalEntities,
223
+ triples_inserted: totalTriples,
224
+ mapping
225
+ };
226
+ }
227
+ /** Ask a natural language question and return the parsed response. */
228
+ async ask(question, opts = {}) {
229
+ const body = { question };
230
+ if (opts.kg) body.kg_name = opts.kg;
231
+ if (opts.model) body.model = opts.model;
232
+ return this.request("POST", `${this.base()}/ask`, body, 6e4);
233
+ }
234
+ /** List all knowledge graphs for the current tenant. */
235
+ async listKgs() {
236
+ const data = await this.request(
237
+ "GET",
238
+ `${this.base()}/kgs`,
239
+ void 0,
240
+ 15e3
241
+ );
242
+ if (Array.isArray(data)) return data;
243
+ if (data && typeof data === "object" && "kgs" in data) {
244
+ const kgs = data.kgs;
245
+ if (Array.isArray(kgs)) return kgs;
246
+ }
247
+ return [];
248
+ }
249
+ /** Create a knowledge graph. */
250
+ async createKg(name, description) {
251
+ const body = { name };
252
+ if (description) body.description = description;
253
+ return this.request("POST", `${this.base()}/kgs`, body, 15e3);
254
+ }
255
+ /** Delete a knowledge graph by name. */
256
+ async deleteKg(name) {
257
+ return this.request(
258
+ "DELETE",
259
+ `${this.base()}/kgs/${encodeURIComponent(name)}`,
260
+ void 0,
261
+ 3e4
262
+ );
263
+ }
264
+ /** List ontology types. */
265
+ async ontologyTypes() {
266
+ const data = await this.request(
267
+ "GET",
268
+ `${this.base()}/ontology/types`,
269
+ void 0,
270
+ 15e3
271
+ );
272
+ return Array.isArray(data) ? data : [];
273
+ }
274
+ };
275
+
276
+ // src/cli.ts
277
+ function client() {
278
+ return new Client();
279
+ }
280
+ function fail(msg, code = 1) {
281
+ process.stderr.write(msg.endsWith("\n") ? msg : msg + "\n");
282
+ process.exit(code);
283
+ }
284
+ async function withErrors(fn) {
285
+ try {
286
+ return await fn();
287
+ } catch (err) {
288
+ if (err instanceof CographError) {
289
+ fail(`Error: ${err.message}`);
290
+ }
291
+ fail(`Error: ${err instanceof Error ? err.message : String(err)}`);
292
+ }
293
+ }
294
+ async function confirm(prompt) {
295
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
296
+ return new Promise((resolve) => {
297
+ rl.question(`${prompt} [y/N] `, (ans) => {
298
+ rl.close();
299
+ resolve(ans.trim().toLowerCase() === "y");
300
+ });
301
+ });
302
+ }
303
+ var program = new Command();
304
+ program.name("cograph").description("Cograph Knowledge Graph CLI").version("0.1.0");
305
+ var kg = program.command("kg").description("Manage knowledge graphs");
306
+ kg.command("list").description("List knowledge graphs").action(async () => {
307
+ await withErrors(async () => {
308
+ const kgs = await client().listKgs();
309
+ if (!kgs.length) {
310
+ process.stdout.write(
311
+ "No knowledge graphs. Create one with: cograph kg create <name>\n"
312
+ );
313
+ return;
314
+ }
315
+ for (const k of kgs) {
316
+ const name = String(k.name ?? "?");
317
+ const triples = Number(k.triple_count ?? 0);
318
+ const desc = k.description ? ` \u2014 ${k.description}` : "";
319
+ const padName = name.padEnd(20, " ");
320
+ const padTriples = String(triples).padStart(6, " ");
321
+ process.stdout.write(` ${padName} ${padTriples} triples${desc}
322
+ `);
323
+ }
324
+ });
325
+ });
326
+ kg.command("create <name>").description("Create a knowledge graph").option("-d, --description <text>", "Description").action(async (name, opts) => {
327
+ await withErrors(async () => {
328
+ const created = await client().createKg(name, opts.description);
329
+ process.stdout.write(`Created knowledge graph: ${created.name ?? name}
330
+ `);
331
+ });
332
+ });
333
+ kg.command("delete <name>").description("Delete a knowledge graph").action(async (name) => {
334
+ await withErrors(async () => {
335
+ await client().deleteKg(name);
336
+ process.stdout.write(`Deleted knowledge graph: ${name}
337
+ `);
338
+ });
339
+ });
340
+ program.command("ingest [file]").description("Ingest data from a file or --text").option("-t, --text <text>", "Inline text to ingest").option("--kg <name>", "Target knowledge graph name").option(
341
+ "-f, --format <fmt>",
342
+ "Override format detection (text|csv|json)"
343
+ ).action(
344
+ async (file, opts) => {
345
+ await withErrors(async () => {
346
+ const c = client();
347
+ if (opts.text) {
348
+ process.stdout.write(
349
+ `Ingesting text (${opts.text.length.toLocaleString()} chars)...
350
+ `
351
+ );
352
+ const result2 = await c.ingest(opts.text, {
353
+ kg: opts.kg,
354
+ contentType: opts.format ?? "text"
355
+ });
356
+ printIngestResult(result2);
357
+ return;
358
+ }
359
+ if (!file) {
360
+ fail("Provide a file or --text");
361
+ }
362
+ process.stdout.write(`Ingesting ${file}...
363
+ `);
364
+ const result = await c.ingest(file, {
365
+ kg: opts.kg,
366
+ contentType: opts.format
367
+ });
368
+ printIngestResult(result);
369
+ });
370
+ }
371
+ );
372
+ function printIngestResult(result) {
373
+ const num = (k) => Number(result[k] ?? 0);
374
+ process.stdout.write(` Entities extracted: ${num("entities_extracted")}
375
+ `);
376
+ process.stdout.write(` Entities resolved: ${num("entities_resolved")}
377
+ `);
378
+ process.stdout.write(` Triples inserted: ${num("triples_inserted")}
379
+ `);
380
+ const types = result.types_created;
381
+ if (Array.isArray(types) && types.length) {
382
+ process.stdout.write(` Types created: ${types.join(", ")}
383
+ `);
384
+ }
385
+ const rejections = result.rejections;
386
+ if (Array.isArray(rejections) && rejections.length) {
387
+ process.stdout.write(` Rejections: ${rejections.length}
388
+ `);
389
+ }
390
+ }
391
+ program.command("ask <question>").description("Ask a natural language question").option("--kg <name>", "Knowledge graph to query").option("-d, --debug", "Show SPARQL and latency breakdown").option("-m, --model <model>", "Override query model").action(
392
+ async (question, opts) => {
393
+ await withErrors(async () => {
394
+ if (opts.model) process.stdout.write(`Model: ${opts.model}
395
+ `);
396
+ process.stdout.write(`Q: ${question}
397
+ `);
398
+ process.stdout.write("Generating answer...\n");
399
+ const t0 = Date.now();
400
+ const result = await client().ask(question, {
401
+ kg: opts.kg,
402
+ model: opts.model
403
+ });
404
+ const roundtripMs = Date.now() - t0;
405
+ process.stdout.write(`
406
+ A: ${result.answer ?? "No answer"}
407
+ `);
408
+ if (opts.debug) {
409
+ process.stdout.write(`
410
+ SPARQL:
411
+ ${result.sparql ?? ""}
412
+ `);
413
+ const timing = result.timing ?? {};
414
+ if (Object.keys(timing).length) {
415
+ process.stdout.write(`
416
+ ${"\u2500".repeat(40)}
417
+ `);
418
+ process.stdout.write(
419
+ `${"Stage".padEnd(25)} ${"Time".padStart(10)}
420
+ `
421
+ );
422
+ process.stdout.write(`${"\u2500".repeat(40)}
423
+ `);
424
+ for (const [key, val] of Object.entries(timing)) {
425
+ if (key === "attempts") {
426
+ process.stdout.write(
427
+ `${"Attempts".padEnd(25)} ${String(val).padStart(10)}
428
+ `
429
+ );
430
+ } else if (typeof val === "string") {
431
+ const label = key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
432
+ process.stdout.write(
433
+ `${label.padEnd(25)} ${val.padStart(10)}
434
+ `
435
+ );
436
+ } else {
437
+ const label = key.replace(/_ms$/, "").replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
438
+ const num = typeof val === "number" ? val : Number(val);
439
+ process.stdout.write(
440
+ `${label.padEnd(25)} ${num.toFixed(1).padStart(8)}ms
441
+ `
442
+ );
443
+ }
444
+ }
445
+ process.stdout.write(`${"\u2500".repeat(40)}
446
+ `);
447
+ process.stdout.write(
448
+ `${"Client roundtrip".padEnd(25)} ${roundtripMs.toFixed(1).padStart(8)}ms
449
+ `
450
+ );
451
+ }
452
+ }
453
+ });
454
+ }
455
+ );
456
+ var onto = program.command("ontology").description("View ontology");
457
+ onto.command("types").description("List ontology types").action(async () => {
458
+ await withErrors(async () => {
459
+ const types = await client().ontologyTypes();
460
+ if (!types.length) {
461
+ process.stdout.write("No ontology types defined.\n");
462
+ return;
463
+ }
464
+ for (const t of types) {
465
+ const parent = t.parent_type ? ` (subClassOf ${t.parent_type})` : "";
466
+ const desc = t.description ? ` \u2014 ${t.description}` : "";
467
+ process.stdout.write(` ${t.name}${parent}${desc}
468
+ `);
469
+ const attrs = t.attributes ?? [];
470
+ for (const a of attrs) {
471
+ process.stdout.write(
472
+ ` .${a.name} (${a.datatype ?? "string"})
473
+ `
474
+ );
475
+ }
476
+ }
477
+ });
478
+ });
479
+ program.command("clear").description("Clear data").option("--kg <name>", "Clear a specific knowledge graph").option(
480
+ "--include-ontology",
481
+ "Also clear the ontology (only meaningful when --kg is omitted)",
482
+ false
483
+ ).option("-y, --yes", "Skip confirmation", false).action(
484
+ async (opts) => {
485
+ await withErrors(async () => {
486
+ let msg;
487
+ if (opts.kg) {
488
+ msg = `Clear KG '${opts.kg}'?`;
489
+ } else if (opts.includeOntology) {
490
+ msg = "Clear EVERYTHING including ontology?";
491
+ } else {
492
+ msg = "Clear all instance data (ontology preserved)?";
493
+ }
494
+ if (!opts.yes) {
495
+ const ok = await confirm(msg);
496
+ if (!ok) {
497
+ process.stdout.write("Cancelled.\n");
498
+ return;
499
+ }
500
+ }
501
+ const c = client();
502
+ if (opts.kg) {
503
+ await c.deleteKg(opts.kg);
504
+ process.stdout.write(`Cleared KG: ${opts.kg}
505
+ `);
506
+ return;
507
+ }
508
+ const tenant = c.tenant;
509
+ const baseUrl = `${c.baseUrl}/graphs/${tenant}`;
510
+ const headers = {
511
+ "Content-Type": "application/json"
512
+ };
513
+ if (c.apiKey) headers["X-API-Key"] = c.apiKey;
514
+ const filters = opts.includeOntology ? "" : `FILTER(CONTAINS(STR(?s), '/entities/') || CONTAINS(STR(?s), '/onto/') || CONTAINS(STR(?s), '/kgs/'))`;
515
+ const query = `SELECT ?s ?p ?o FROM <https://omnix.dev/graphs/${tenant}> WHERE { ?s ?p ?o . ${filters} } LIMIT 1000`;
516
+ process.stdout.write("Clearing...\n");
517
+ let deleted = 0;
518
+ for (let i = 0; i < 50; i++) {
519
+ const fetchRes = await fetch(`${baseUrl}/query`, {
520
+ method: "POST",
521
+ headers,
522
+ body: JSON.stringify({ query })
523
+ });
524
+ if (!fetchRes.ok) break;
525
+ const data = await fetchRes.json();
526
+ const bindings = data.bindings ?? [];
527
+ if (!bindings.length) break;
528
+ const triples = bindings.filter((b) => b.s).map((b) => ({
529
+ subject: b.s,
530
+ predicate: b.p,
531
+ object: b.o
532
+ }));
533
+ for (let j = 0; j < triples.length; j += 100) {
534
+ await fetch(`${baseUrl}/triples`, {
535
+ method: "DELETE",
536
+ headers,
537
+ body: JSON.stringify({ triples: triples.slice(j, j + 100) })
538
+ });
539
+ }
540
+ deleted += triples.length;
541
+ }
542
+ process.stdout.write(`Deleted ${deleted} triples
543
+ `);
544
+ });
545
+ }
546
+ );
547
+ program.parseAsync(process.argv).catch((err) => {
548
+ fail(`Error: ${err instanceof Error ? err.message : String(err)}`);
549
+ });
550
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/client.ts"],"sourcesContent":["import { createInterface } from \"node:readline\";\nimport { Command } from \"commander\";\nimport { Client, CographError } from \"./client.js\";\n\nfunction client(): Client {\n return new Client();\n}\n\nfunction printJson(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\nfunction fail(msg: string, code = 1): never {\n process.stderr.write(msg.endsWith(\"\\n\") ? msg : msg + \"\\n\");\n process.exit(code);\n}\n\nasync function withErrors<T>(fn: () => Promise<T>): Promise<T | void> {\n try {\n return await fn();\n } catch (err) {\n if (err instanceof CographError) {\n fail(`Error: ${err.message}`);\n }\n fail(`Error: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\nasync function confirm(prompt: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${prompt} [y/N] `, (ans) => {\n rl.close();\n resolve(ans.trim().toLowerCase() === \"y\");\n });\n });\n}\n\nconst program = new Command();\nprogram\n .name(\"cograph\")\n .description(\"Cograph Knowledge Graph CLI\")\n .version(\"0.1.0\");\n\n// ---------------------------------------------------------------------------\n// kg\n// ---------------------------------------------------------------------------\n\nconst kg = program.command(\"kg\").description(\"Manage knowledge graphs\");\n\nkg.command(\"list\")\n .description(\"List knowledge graphs\")\n .action(async () => {\n await withErrors(async () => {\n const kgs = await client().listKgs();\n if (!kgs.length) {\n process.stdout.write(\n \"No knowledge graphs. Create one with: cograph kg create <name>\\n\",\n );\n return;\n }\n for (const k of kgs) {\n const name = String(k.name ?? \"?\");\n const triples = Number(k.triple_count ?? 0);\n const desc = k.description ? ` — ${k.description}` : \"\";\n const padName = name.padEnd(20, \" \");\n const padTriples = String(triples).padStart(6, \" \");\n process.stdout.write(` ${padName} ${padTriples} triples${desc}\\n`);\n }\n });\n });\n\nkg.command(\"create <name>\")\n .description(\"Create a knowledge graph\")\n .option(\"-d, --description <text>\", \"Description\")\n .action(async (name: string, opts: { description?: string }) => {\n await withErrors(async () => {\n const created = await client().createKg(name, opts.description);\n process.stdout.write(`Created knowledge graph: ${created.name ?? name}\\n`);\n });\n });\n\nkg.command(\"delete <name>\")\n .description(\"Delete a knowledge graph\")\n .action(async (name: string) => {\n await withErrors(async () => {\n await client().deleteKg(name);\n process.stdout.write(`Deleted knowledge graph: ${name}\\n`);\n });\n });\n\n// ---------------------------------------------------------------------------\n// ingest\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"ingest [file]\")\n .description(\"Ingest data from a file or --text\")\n .option(\"-t, --text <text>\", \"Inline text to ingest\")\n .option(\"--kg <name>\", \"Target knowledge graph name\")\n .option(\n \"-f, --format <fmt>\",\n \"Override format detection (text|csv|json)\",\n )\n .action(\n async (\n file: string | undefined,\n opts: { text?: string; kg?: string; format?: string },\n ) => {\n await withErrors(async () => {\n const c = client();\n if (opts.text) {\n process.stdout.write(\n `Ingesting text (${opts.text.length.toLocaleString()} chars)...\\n`,\n );\n const result = await c.ingest(opts.text, {\n kg: opts.kg,\n contentType: opts.format ?? \"text\",\n });\n printIngestResult(result);\n return;\n }\n if (!file) {\n fail(\"Provide a file or --text\");\n }\n // ingest() handles file reading + format detection + CSV two-step flow.\n process.stdout.write(`Ingesting ${file}...\\n`);\n const result = await c.ingest(file, {\n kg: opts.kg,\n contentType: opts.format,\n });\n printIngestResult(result);\n });\n },\n );\n\nfunction printIngestResult(result: Record<string, unknown>): void {\n const num = (k: string) => Number(result[k] ?? 0);\n process.stdout.write(` Entities extracted: ${num(\"entities_extracted\")}\\n`);\n process.stdout.write(` Entities resolved: ${num(\"entities_resolved\")}\\n`);\n process.stdout.write(` Triples inserted: ${num(\"triples_inserted\")}\\n`);\n const types = result.types_created;\n if (Array.isArray(types) && types.length) {\n process.stdout.write(` Types created: ${types.join(\", \")}\\n`);\n }\n const rejections = result.rejections;\n if (Array.isArray(rejections) && rejections.length) {\n process.stdout.write(` Rejections: ${rejections.length}\\n`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// ask\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"ask <question>\")\n .description(\"Ask a natural language question\")\n .option(\"--kg <name>\", \"Knowledge graph to query\")\n .option(\"-d, --debug\", \"Show SPARQL and latency breakdown\")\n .option(\"-m, --model <model>\", \"Override query model\")\n .action(\n async (\n question: string,\n opts: { kg?: string; debug?: boolean; model?: string },\n ) => {\n await withErrors(async () => {\n if (opts.model) process.stdout.write(`Model: ${opts.model}\\n`);\n process.stdout.write(`Q: ${question}\\n`);\n process.stdout.write(\"Generating answer...\\n\");\n const t0 = Date.now();\n const result = await client().ask(question, {\n kg: opts.kg,\n model: opts.model,\n });\n const roundtripMs = Date.now() - t0;\n process.stdout.write(`\\nA: ${result.answer ?? \"No answer\"}\\n`);\n if (opts.debug) {\n process.stdout.write(`\\nSPARQL:\\n${result.sparql ?? \"\"}\\n`);\n const timing = (result.timing ?? {}) as Record<string, unknown>;\n if (Object.keys(timing).length) {\n process.stdout.write(`\\n${\"─\".repeat(40)}\\n`);\n process.stdout.write(\n `${\"Stage\".padEnd(25)} ${\"Time\".padStart(10)}\\n`,\n );\n process.stdout.write(`${\"─\".repeat(40)}\\n`);\n for (const [key, val] of Object.entries(timing)) {\n if (key === \"attempts\") {\n process.stdout.write(\n `${\"Attempts\".padEnd(25)} ${String(val).padStart(10)}\\n`,\n );\n } else if (typeof val === \"string\") {\n const label = key\n .replace(/_/g, \" \")\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n process.stdout.write(\n `${label.padEnd(25)} ${val.padStart(10)}\\n`,\n );\n } else {\n const label = key\n .replace(/_ms$/, \"\")\n .replace(/_/g, \" \")\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n const num = typeof val === \"number\" ? val : Number(val);\n process.stdout.write(\n `${label.padEnd(25)} ${num.toFixed(1).padStart(8)}ms\\n`,\n );\n }\n }\n process.stdout.write(`${\"─\".repeat(40)}\\n`);\n process.stdout.write(\n `${\"Client roundtrip\".padEnd(25)} ${roundtripMs.toFixed(1).padStart(8)}ms\\n`,\n );\n }\n }\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n// ontology\n// ---------------------------------------------------------------------------\n\nconst onto = program.command(\"ontology\").description(\"View ontology\");\n\nonto\n .command(\"types\")\n .description(\"List ontology types\")\n .action(async () => {\n await withErrors(async () => {\n const types = await client().ontologyTypes();\n if (!types.length) {\n process.stdout.write(\"No ontology types defined.\\n\");\n return;\n }\n for (const t of types) {\n const parent = t.parent_type\n ? ` (subClassOf ${t.parent_type})`\n : \"\";\n const desc = t.description ? ` — ${t.description}` : \"\";\n process.stdout.write(` ${t.name}${parent}${desc}\\n`);\n const attrs = (t.attributes ?? []) as Array<Record<string, unknown>>;\n for (const a of attrs) {\n process.stdout.write(\n ` .${a.name} (${a.datatype ?? \"string\"})\\n`,\n );\n }\n }\n });\n });\n\n// ---------------------------------------------------------------------------\n// clear\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"clear\")\n .description(\"Clear data\")\n .option(\"--kg <name>\", \"Clear a specific knowledge graph\")\n .option(\n \"--include-ontology\",\n \"Also clear the ontology (only meaningful when --kg is omitted)\",\n false,\n )\n .option(\"-y, --yes\", \"Skip confirmation\", false)\n .action(\n async (opts: { kg?: string; includeOntology?: boolean; yes?: boolean }) => {\n await withErrors(async () => {\n let msg: string;\n if (opts.kg) {\n msg = `Clear KG '${opts.kg}'?`;\n } else if (opts.includeOntology) {\n msg = \"Clear EVERYTHING including ontology?\";\n } else {\n msg = \"Clear all instance data (ontology preserved)?\";\n }\n\n if (!opts.yes) {\n const ok = await confirm(msg);\n if (!ok) {\n process.stdout.write(\"Cancelled.\\n\");\n return;\n }\n }\n\n const c = client();\n if (opts.kg) {\n await c.deleteKg(opts.kg);\n process.stdout.write(`Cleared KG: ${opts.kg}\\n`);\n return;\n }\n\n // Bulk-clear via /query + DELETE /triples — same loop the Python CLI uses.\n const tenant = c.tenant;\n const baseUrl = `${c.baseUrl}/graphs/${tenant}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (c.apiKey) headers[\"X-API-Key\"] = c.apiKey;\n\n const filters = opts.includeOntology\n ? \"\"\n : `FILTER(CONTAINS(STR(?s), '/entities/') || CONTAINS(STR(?s), '/onto/') || CONTAINS(STR(?s), '/kgs/'))`;\n const query = `SELECT ?s ?p ?o FROM <https://omnix.dev/graphs/${tenant}> WHERE { ?s ?p ?o . ${filters} } LIMIT 1000`;\n\n process.stdout.write(\"Clearing...\\n\");\n let deleted = 0;\n for (let i = 0; i < 50; i++) {\n const fetchRes = await fetch(`${baseUrl}/query`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ query }),\n });\n if (!fetchRes.ok) break;\n const data = (await fetchRes.json()) as {\n bindings?: Array<Record<string, unknown>>;\n };\n const bindings = data.bindings ?? [];\n if (!bindings.length) break;\n const triples = bindings\n .filter((b) => b.s)\n .map((b) => ({\n subject: b.s,\n predicate: b.p,\n object: b.o,\n }));\n for (let j = 0; j < triples.length; j += 100) {\n await fetch(`${baseUrl}/triples`, {\n method: \"DELETE\",\n headers,\n body: JSON.stringify({ triples: triples.slice(j, j + 100) }),\n });\n }\n deleted += triples.length;\n }\n process.stdout.write(`Deleted ${deleted} triples\\n`);\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n\nprogram.parseAsync(process.argv).catch((err) => {\n fail(`Error: ${err instanceof Error ? err.message : String(err)}`);\n});\n\n// silence unused import warning if ever needed\nvoid printJson;\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { extname } from \"node:path\";\n\nexport class CographError extends Error {\n status?: number;\n body?: string;\n\n constructor(message: string, opts?: { status?: number; body?: string }) {\n super(message);\n this.name = \"CographError\";\n this.status = opts?.status;\n this.body = opts?.body;\n }\n}\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n tenant?: string;\n}\n\nexport interface IngestOptions {\n kg?: string;\n contentType?: \"text\" | \"csv\" | \"json\" | string;\n}\n\nexport interface AskOptions {\n kg?: string;\n model?: string;\n}\n\nfunction envVar(name: string, fallback?: string): string | undefined {\n // Prefer COGRAPH_, fall back to OMNIX_ so old configs keep working.\n return (\n process.env[`COGRAPH_${name}`] ||\n process.env[`OMNIX_${name}`] ||\n fallback\n );\n}\n\nconst EXT_FORMAT: Record<string, string> = {\n \".csv\": \"csv\",\n \".json\": \"json\",\n \".jsonl\": \"json\",\n \".txt\": \"text\",\n};\n\n/**\n * Parse a CSV string into an array of row objects.\n *\n * Minimal RFC-4180-ish parser: handles quoted fields with commas, escaped\n * quotes (`\"\"`), CRLF/LF line endings. Does not handle BOM stripping or\n * encoding detection — we assume UTF-8 text in.\n */\nexport function parseCsv(content: string): Record<string, string>[] {\n const rows: string[][] = [];\n let cur: string[] = [];\n let field = \"\";\n let inQuotes = false;\n\n for (let i = 0; i < content.length; i++) {\n const ch = content[i];\n if (inQuotes) {\n if (ch === '\"') {\n if (content[i + 1] === '\"') {\n field += '\"';\n i++;\n } else {\n inQuotes = false;\n }\n } else {\n field += ch;\n }\n } else {\n if (ch === '\"') {\n inQuotes = true;\n } else if (ch === \",\") {\n cur.push(field);\n field = \"\";\n } else if (ch === \"\\n\") {\n cur.push(field);\n rows.push(cur);\n cur = [];\n field = \"\";\n } else if (ch === \"\\r\") {\n // swallow; handled by the following \\n in CRLF, or treat lone \\r as line end\n if (content[i + 1] !== \"\\n\") {\n cur.push(field);\n rows.push(cur);\n cur = [];\n field = \"\";\n }\n } else {\n field += ch;\n }\n }\n }\n // flush trailing field/row\n if (field.length > 0 || cur.length > 0) {\n cur.push(field);\n rows.push(cur);\n }\n\n if (rows.length === 0) return [];\n const headers = rows[0]!.map((h) => h.trim());\n const out: Record<string, string>[] = [];\n for (let r = 1; r < rows.length; r++) {\n const row = rows[r]!;\n // skip blank trailing lines\n if (row.length === 1 && row[0] === \"\") continue;\n const obj: Record<string, string> = {};\n for (let c = 0; c < headers.length; c++) {\n obj[headers[c]!] = row[c] ?? \"\";\n }\n out.push(obj);\n }\n return out;\n}\n\nexport class Client {\n apiKey: string | undefined;\n baseUrl: string;\n tenant: string;\n\n constructor(opts: ClientOptions = {}) {\n this.apiKey = opts.apiKey ?? envVar(\"API_KEY\");\n const url = opts.baseUrl ?? envVar(\"API_URL\") ?? \"https://api.cograph.cloud\";\n this.baseUrl = url.replace(/\\/+$/, \"\");\n this.tenant = opts.tenant ?? envVar(\"TENANT\") ?? \"demo-tenant\";\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (this.apiKey) h[\"X-API-Key\"] = this.apiKey;\n return h;\n }\n\n private base(): string {\n return `${this.baseUrl}/graphs/${this.tenant}`;\n }\n\n private async request<T = unknown>(\n method: string,\n url: string,\n body?: unknown,\n timeoutMs: number = 120_000,\n ): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n let res: Response;\n try {\n res = await fetch(url, {\n method,\n headers: this.headers(),\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new CographError(`Request to ${url} timed out after ${timeoutMs}ms`);\n }\n throw new CographError(\n `Network error contacting ${url}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n clearTimeout(timer);\n\n if (!res.ok) {\n let text = \"\";\n try {\n text = await res.text();\n } catch {\n // ignore\n }\n throw new CographError(`HTTP ${res.status}: ${text}`, {\n status: res.status,\n body: text,\n });\n }\n\n // 204 No Content\n if (res.status === 204) return undefined as T;\n\n const ct = res.headers.get(\"content-type\") ?? \"\";\n if (ct.includes(\"application/json\")) {\n return (await res.json()) as T;\n }\n // fall back to text\n const text = await res.text();\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n }\n\n /**\n * Ingest a file path or raw text into a knowledge graph.\n *\n * If `pathOrText` points to an existing file, its contents are read and the\n * format is inferred from the extension (.csv, .json, .txt) unless\n * `contentType` is given. CSV files use the two-step schema-inference + row\n * mapping flow.\n */\n async ingest(\n pathOrText: string,\n opts: IngestOptions = {},\n ): Promise<Record<string, unknown>> {\n let content: string;\n let fmt: string;\n\n let isFile = false;\n try {\n isFile = existsSync(pathOrText) && statSync(pathOrText).isFile();\n } catch {\n isFile = false;\n }\n\n if (isFile) {\n const ext = extname(pathOrText).toLowerCase();\n if (ext === \".pdf\") {\n throw new CographError(\n \"PDF ingest not yet supported in the Node CLI; use the Python CLI or POST raw bytes to the API.\",\n );\n }\n content = readFileSync(pathOrText, \"utf-8\");\n fmt = opts.contentType ?? EXT_FORMAT[ext] ?? \"text\";\n if (fmt === \"csv\") {\n return this.ingestCsv(content, opts.kg);\n }\n } else {\n content = pathOrText;\n fmt = opts.contentType ?? \"text\";\n }\n\n const body: Record<string, unknown> = {\n content,\n content_type: fmt,\n source: \"client\",\n };\n if (opts.kg) body.kg_name = opts.kg;\n return this.request(\"POST\", `${this.base()}/ingest`, body, 120_000);\n }\n\n private async ingestCsv(\n content: string,\n kgName: string | undefined,\n ): Promise<Record<string, unknown>> {\n const rows = parseCsv(content);\n if (rows.length === 0) throw new CographError(\"CSV is empty\");\n const headers = Object.keys(rows[0]!);\n\n const schemaBody = {\n headers,\n sample_rows: rows.slice(0, 5),\n total_rows: rows.length,\n };\n const mapping = await this.request<Record<string, unknown>>(\n \"POST\",\n `${this.base()}/ingest/csv/schema`,\n schemaBody,\n 300_000,\n );\n\n const batchSize = 50;\n let totalEntities = 0;\n let totalTriples = 0;\n for (let i = 0; i < rows.length; i += batchSize) {\n const batch = rows.slice(i, i + batchSize);\n const body: Record<string, unknown> = {\n mapping,\n rows: batch,\n source: \"client\",\n };\n if (kgName) body.kg_name = kgName;\n const result = await this.request<{\n entities_resolved?: number;\n triples_inserted?: number;\n }>(\"POST\", `${this.base()}/ingest/csv/rows`, body, 300_000);\n totalEntities += result.entities_resolved ?? 0;\n totalTriples += result.triples_inserted ?? 0;\n }\n\n return {\n entities_resolved: totalEntities,\n triples_inserted: totalTriples,\n mapping,\n };\n }\n\n /** Ask a natural language question and return the parsed response. */\n async ask(\n question: string,\n opts: AskOptions = {},\n ): Promise<Record<string, unknown>> {\n const body: Record<string, unknown> = { question };\n if (opts.kg) body.kg_name = opts.kg;\n if (opts.model) body.model = opts.model;\n return this.request(\"POST\", `${this.base()}/ask`, body, 60_000);\n }\n\n /** List all knowledge graphs for the current tenant. */\n async listKgs(): Promise<Array<Record<string, unknown>>> {\n const data = await this.request<unknown>(\n \"GET\",\n `${this.base()}/kgs`,\n undefined,\n 15_000,\n );\n if (Array.isArray(data)) return data as Array<Record<string, unknown>>;\n if (data && typeof data === \"object\" && \"kgs\" in data) {\n const kgs = (data as { kgs?: unknown }).kgs;\n if (Array.isArray(kgs)) return kgs as Array<Record<string, unknown>>;\n }\n return [];\n }\n\n /** Create a knowledge graph. */\n async createKg(\n name: string,\n description?: string,\n ): Promise<Record<string, unknown>> {\n const body: Record<string, unknown> = { name };\n if (description) body.description = description;\n return this.request(\"POST\", `${this.base()}/kgs`, body, 15_000);\n }\n\n /** Delete a knowledge graph by name. */\n async deleteKg(name: string): Promise<Record<string, unknown>> {\n return this.request(\n \"DELETE\",\n `${this.base()}/kgs/${encodeURIComponent(name)}`,\n undefined,\n 30_000,\n );\n }\n\n /** List ontology types. */\n async ontologyTypes(): Promise<Array<Record<string, unknown>>> {\n const data = await this.request<unknown>(\n \"GET\",\n `${this.base()}/ontology/types`,\n undefined,\n 15_000,\n );\n return Array.isArray(data) ? (data as Array<Record<string, unknown>>) : [];\n }\n}\n"],"mappings":"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","names":["text","result"]}
@@ -0,0 +1,52 @@
1
+ declare class CographError extends Error {
2
+ status?: number;
3
+ body?: string;
4
+ constructor(message: string, opts?: {
5
+ status?: number;
6
+ body?: string;
7
+ });
8
+ }
9
+ interface ClientOptions {
10
+ apiKey?: string;
11
+ baseUrl?: string;
12
+ tenant?: string;
13
+ }
14
+ interface IngestOptions {
15
+ kg?: string;
16
+ contentType?: "text" | "csv" | "json" | string;
17
+ }
18
+ interface AskOptions {
19
+ kg?: string;
20
+ model?: string;
21
+ }
22
+ declare class Client {
23
+ apiKey: string | undefined;
24
+ baseUrl: string;
25
+ tenant: string;
26
+ constructor(opts?: ClientOptions);
27
+ private headers;
28
+ private base;
29
+ private request;
30
+ /**
31
+ * Ingest a file path or raw text into a knowledge graph.
32
+ *
33
+ * If `pathOrText` points to an existing file, its contents are read and the
34
+ * format is inferred from the extension (.csv, .json, .txt) unless
35
+ * `contentType` is given. CSV files use the two-step schema-inference + row
36
+ * mapping flow.
37
+ */
38
+ ingest(pathOrText: string, opts?: IngestOptions): Promise<Record<string, unknown>>;
39
+ private ingestCsv;
40
+ /** Ask a natural language question and return the parsed response. */
41
+ ask(question: string, opts?: AskOptions): Promise<Record<string, unknown>>;
42
+ /** List all knowledge graphs for the current tenant. */
43
+ listKgs(): Promise<Array<Record<string, unknown>>>;
44
+ /** Create a knowledge graph. */
45
+ createKg(name: string, description?: string): Promise<Record<string, unknown>>;
46
+ /** Delete a knowledge graph by name. */
47
+ deleteKg(name: string): Promise<Record<string, unknown>>;
48
+ /** List ontology types. */
49
+ ontologyTypes(): Promise<Array<Record<string, unknown>>>;
50
+ }
51
+
52
+ export { type AskOptions, Client, type ClientOptions, CographError, type IngestOptions };
package/dist/index.js ADDED
@@ -0,0 +1,273 @@
1
+ // src/client.ts
2
+ import { existsSync, readFileSync, statSync } from "fs";
3
+ import { extname } from "path";
4
+ var CographError = class extends Error {
5
+ status;
6
+ body;
7
+ constructor(message, opts) {
8
+ super(message);
9
+ this.name = "CographError";
10
+ this.status = opts?.status;
11
+ this.body = opts?.body;
12
+ }
13
+ };
14
+ function envVar(name, fallback) {
15
+ return process.env[`COGRAPH_${name}`] || process.env[`OMNIX_${name}`] || fallback;
16
+ }
17
+ var EXT_FORMAT = {
18
+ ".csv": "csv",
19
+ ".json": "json",
20
+ ".jsonl": "json",
21
+ ".txt": "text"
22
+ };
23
+ function parseCsv(content) {
24
+ const rows = [];
25
+ let cur = [];
26
+ let field = "";
27
+ let inQuotes = false;
28
+ for (let i = 0; i < content.length; i++) {
29
+ const ch = content[i];
30
+ if (inQuotes) {
31
+ if (ch === '"') {
32
+ if (content[i + 1] === '"') {
33
+ field += '"';
34
+ i++;
35
+ } else {
36
+ inQuotes = false;
37
+ }
38
+ } else {
39
+ field += ch;
40
+ }
41
+ } else {
42
+ if (ch === '"') {
43
+ inQuotes = true;
44
+ } else if (ch === ",") {
45
+ cur.push(field);
46
+ field = "";
47
+ } else if (ch === "\n") {
48
+ cur.push(field);
49
+ rows.push(cur);
50
+ cur = [];
51
+ field = "";
52
+ } else if (ch === "\r") {
53
+ if (content[i + 1] !== "\n") {
54
+ cur.push(field);
55
+ rows.push(cur);
56
+ cur = [];
57
+ field = "";
58
+ }
59
+ } else {
60
+ field += ch;
61
+ }
62
+ }
63
+ }
64
+ if (field.length > 0 || cur.length > 0) {
65
+ cur.push(field);
66
+ rows.push(cur);
67
+ }
68
+ if (rows.length === 0) return [];
69
+ const headers = rows[0].map((h) => h.trim());
70
+ const out = [];
71
+ for (let r = 1; r < rows.length; r++) {
72
+ const row = rows[r];
73
+ if (row.length === 1 && row[0] === "") continue;
74
+ const obj = {};
75
+ for (let c = 0; c < headers.length; c++) {
76
+ obj[headers[c]] = row[c] ?? "";
77
+ }
78
+ out.push(obj);
79
+ }
80
+ return out;
81
+ }
82
+ var Client = class {
83
+ apiKey;
84
+ baseUrl;
85
+ tenant;
86
+ constructor(opts = {}) {
87
+ this.apiKey = opts.apiKey ?? envVar("API_KEY");
88
+ const url = opts.baseUrl ?? envVar("API_URL") ?? "https://api.cograph.cloud";
89
+ this.baseUrl = url.replace(/\/+$/, "");
90
+ this.tenant = opts.tenant ?? envVar("TENANT") ?? "demo-tenant";
91
+ }
92
+ headers() {
93
+ const h = { "Content-Type": "application/json" };
94
+ if (this.apiKey) h["X-API-Key"] = this.apiKey;
95
+ return h;
96
+ }
97
+ base() {
98
+ return `${this.baseUrl}/graphs/${this.tenant}`;
99
+ }
100
+ async request(method, url, body, timeoutMs = 12e4) {
101
+ const controller = new AbortController();
102
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
103
+ let res;
104
+ try {
105
+ res = await fetch(url, {
106
+ method,
107
+ headers: this.headers(),
108
+ body: body === void 0 ? void 0 : JSON.stringify(body),
109
+ signal: controller.signal
110
+ });
111
+ } catch (err) {
112
+ clearTimeout(timer);
113
+ if (err instanceof Error && err.name === "AbortError") {
114
+ throw new CographError(`Request to ${url} timed out after ${timeoutMs}ms`);
115
+ }
116
+ throw new CographError(
117
+ `Network error contacting ${url}: ${err instanceof Error ? err.message : String(err)}`
118
+ );
119
+ }
120
+ clearTimeout(timer);
121
+ if (!res.ok) {
122
+ let text2 = "";
123
+ try {
124
+ text2 = await res.text();
125
+ } catch {
126
+ }
127
+ throw new CographError(`HTTP ${res.status}: ${text2}`, {
128
+ status: res.status,
129
+ body: text2
130
+ });
131
+ }
132
+ if (res.status === 204) return void 0;
133
+ const ct = res.headers.get("content-type") ?? "";
134
+ if (ct.includes("application/json")) {
135
+ return await res.json();
136
+ }
137
+ const text = await res.text();
138
+ try {
139
+ return JSON.parse(text);
140
+ } catch {
141
+ return text;
142
+ }
143
+ }
144
+ /**
145
+ * Ingest a file path or raw text into a knowledge graph.
146
+ *
147
+ * If `pathOrText` points to an existing file, its contents are read and the
148
+ * format is inferred from the extension (.csv, .json, .txt) unless
149
+ * `contentType` is given. CSV files use the two-step schema-inference + row
150
+ * mapping flow.
151
+ */
152
+ async ingest(pathOrText, opts = {}) {
153
+ let content;
154
+ let fmt;
155
+ let isFile = false;
156
+ try {
157
+ isFile = existsSync(pathOrText) && statSync(pathOrText).isFile();
158
+ } catch {
159
+ isFile = false;
160
+ }
161
+ if (isFile) {
162
+ const ext = extname(pathOrText).toLowerCase();
163
+ if (ext === ".pdf") {
164
+ throw new CographError(
165
+ "PDF ingest not yet supported in the Node CLI; use the Python CLI or POST raw bytes to the API."
166
+ );
167
+ }
168
+ content = readFileSync(pathOrText, "utf-8");
169
+ fmt = opts.contentType ?? EXT_FORMAT[ext] ?? "text";
170
+ if (fmt === "csv") {
171
+ return this.ingestCsv(content, opts.kg);
172
+ }
173
+ } else {
174
+ content = pathOrText;
175
+ fmt = opts.contentType ?? "text";
176
+ }
177
+ const body = {
178
+ content,
179
+ content_type: fmt,
180
+ source: "client"
181
+ };
182
+ if (opts.kg) body.kg_name = opts.kg;
183
+ return this.request("POST", `${this.base()}/ingest`, body, 12e4);
184
+ }
185
+ async ingestCsv(content, kgName) {
186
+ const rows = parseCsv(content);
187
+ if (rows.length === 0) throw new CographError("CSV is empty");
188
+ const headers = Object.keys(rows[0]);
189
+ const schemaBody = {
190
+ headers,
191
+ sample_rows: rows.slice(0, 5),
192
+ total_rows: rows.length
193
+ };
194
+ const mapping = await this.request(
195
+ "POST",
196
+ `${this.base()}/ingest/csv/schema`,
197
+ schemaBody,
198
+ 3e5
199
+ );
200
+ const batchSize = 50;
201
+ let totalEntities = 0;
202
+ let totalTriples = 0;
203
+ for (let i = 0; i < rows.length; i += batchSize) {
204
+ const batch = rows.slice(i, i + batchSize);
205
+ const body = {
206
+ mapping,
207
+ rows: batch,
208
+ source: "client"
209
+ };
210
+ if (kgName) body.kg_name = kgName;
211
+ const result = await this.request("POST", `${this.base()}/ingest/csv/rows`, body, 3e5);
212
+ totalEntities += result.entities_resolved ?? 0;
213
+ totalTriples += result.triples_inserted ?? 0;
214
+ }
215
+ return {
216
+ entities_resolved: totalEntities,
217
+ triples_inserted: totalTriples,
218
+ mapping
219
+ };
220
+ }
221
+ /** Ask a natural language question and return the parsed response. */
222
+ async ask(question, opts = {}) {
223
+ const body = { question };
224
+ if (opts.kg) body.kg_name = opts.kg;
225
+ if (opts.model) body.model = opts.model;
226
+ return this.request("POST", `${this.base()}/ask`, body, 6e4);
227
+ }
228
+ /** List all knowledge graphs for the current tenant. */
229
+ async listKgs() {
230
+ const data = await this.request(
231
+ "GET",
232
+ `${this.base()}/kgs`,
233
+ void 0,
234
+ 15e3
235
+ );
236
+ if (Array.isArray(data)) return data;
237
+ if (data && typeof data === "object" && "kgs" in data) {
238
+ const kgs = data.kgs;
239
+ if (Array.isArray(kgs)) return kgs;
240
+ }
241
+ return [];
242
+ }
243
+ /** Create a knowledge graph. */
244
+ async createKg(name, description) {
245
+ const body = { name };
246
+ if (description) body.description = description;
247
+ return this.request("POST", `${this.base()}/kgs`, body, 15e3);
248
+ }
249
+ /** Delete a knowledge graph by name. */
250
+ async deleteKg(name) {
251
+ return this.request(
252
+ "DELETE",
253
+ `${this.base()}/kgs/${encodeURIComponent(name)}`,
254
+ void 0,
255
+ 3e4
256
+ );
257
+ }
258
+ /** List ontology types. */
259
+ async ontologyTypes() {
260
+ const data = await this.request(
261
+ "GET",
262
+ `${this.base()}/ontology/types`,
263
+ void 0,
264
+ 15e3
265
+ );
266
+ return Array.isArray(data) ? data : [];
267
+ }
268
+ };
269
+ export {
270
+ Client,
271
+ CographError
272
+ };
273
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { extname } from \"node:path\";\n\nexport class CographError extends Error {\n status?: number;\n body?: string;\n\n constructor(message: string, opts?: { status?: number; body?: string }) {\n super(message);\n this.name = \"CographError\";\n this.status = opts?.status;\n this.body = opts?.body;\n }\n}\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n tenant?: string;\n}\n\nexport interface IngestOptions {\n kg?: string;\n contentType?: \"text\" | \"csv\" | \"json\" | string;\n}\n\nexport interface AskOptions {\n kg?: string;\n model?: string;\n}\n\nfunction envVar(name: string, fallback?: string): string | undefined {\n // Prefer COGRAPH_, fall back to OMNIX_ so old configs keep working.\n return (\n process.env[`COGRAPH_${name}`] ||\n process.env[`OMNIX_${name}`] ||\n fallback\n );\n}\n\nconst EXT_FORMAT: Record<string, string> = {\n \".csv\": \"csv\",\n \".json\": \"json\",\n \".jsonl\": \"json\",\n \".txt\": \"text\",\n};\n\n/**\n * Parse a CSV string into an array of row objects.\n *\n * Minimal RFC-4180-ish parser: handles quoted fields with commas, escaped\n * quotes (`\"\"`), CRLF/LF line endings. Does not handle BOM stripping or\n * encoding detection — we assume UTF-8 text in.\n */\nexport function parseCsv(content: string): Record<string, string>[] {\n const rows: string[][] = [];\n let cur: string[] = [];\n let field = \"\";\n let inQuotes = false;\n\n for (let i = 0; i < content.length; i++) {\n const ch = content[i];\n if (inQuotes) {\n if (ch === '\"') {\n if (content[i + 1] === '\"') {\n field += '\"';\n i++;\n } else {\n inQuotes = false;\n }\n } else {\n field += ch;\n }\n } else {\n if (ch === '\"') {\n inQuotes = true;\n } else if (ch === \",\") {\n cur.push(field);\n field = \"\";\n } else if (ch === \"\\n\") {\n cur.push(field);\n rows.push(cur);\n cur = [];\n field = \"\";\n } else if (ch === \"\\r\") {\n // swallow; handled by the following \\n in CRLF, or treat lone \\r as line end\n if (content[i + 1] !== \"\\n\") {\n cur.push(field);\n rows.push(cur);\n cur = [];\n field = \"\";\n }\n } else {\n field += ch;\n }\n }\n }\n // flush trailing field/row\n if (field.length > 0 || cur.length > 0) {\n cur.push(field);\n rows.push(cur);\n }\n\n if (rows.length === 0) return [];\n const headers = rows[0]!.map((h) => h.trim());\n const out: Record<string, string>[] = [];\n for (let r = 1; r < rows.length; r++) {\n const row = rows[r]!;\n // skip blank trailing lines\n if (row.length === 1 && row[0] === \"\") continue;\n const obj: Record<string, string> = {};\n for (let c = 0; c < headers.length; c++) {\n obj[headers[c]!] = row[c] ?? \"\";\n }\n out.push(obj);\n }\n return out;\n}\n\nexport class Client {\n apiKey: string | undefined;\n baseUrl: string;\n tenant: string;\n\n constructor(opts: ClientOptions = {}) {\n this.apiKey = opts.apiKey ?? envVar(\"API_KEY\");\n const url = opts.baseUrl ?? envVar(\"API_URL\") ?? \"https://api.cograph.cloud\";\n this.baseUrl = url.replace(/\\/+$/, \"\");\n this.tenant = opts.tenant ?? envVar(\"TENANT\") ?? \"demo-tenant\";\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (this.apiKey) h[\"X-API-Key\"] = this.apiKey;\n return h;\n }\n\n private base(): string {\n return `${this.baseUrl}/graphs/${this.tenant}`;\n }\n\n private async request<T = unknown>(\n method: string,\n url: string,\n body?: unknown,\n timeoutMs: number = 120_000,\n ): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n let res: Response;\n try {\n res = await fetch(url, {\n method,\n headers: this.headers(),\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new CographError(`Request to ${url} timed out after ${timeoutMs}ms`);\n }\n throw new CographError(\n `Network error contacting ${url}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n clearTimeout(timer);\n\n if (!res.ok) {\n let text = \"\";\n try {\n text = await res.text();\n } catch {\n // ignore\n }\n throw new CographError(`HTTP ${res.status}: ${text}`, {\n status: res.status,\n body: text,\n });\n }\n\n // 204 No Content\n if (res.status === 204) return undefined as T;\n\n const ct = res.headers.get(\"content-type\") ?? \"\";\n if (ct.includes(\"application/json\")) {\n return (await res.json()) as T;\n }\n // fall back to text\n const text = await res.text();\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n }\n\n /**\n * Ingest a file path or raw text into a knowledge graph.\n *\n * If `pathOrText` points to an existing file, its contents are read and the\n * format is inferred from the extension (.csv, .json, .txt) unless\n * `contentType` is given. CSV files use the two-step schema-inference + row\n * mapping flow.\n */\n async ingest(\n pathOrText: string,\n opts: IngestOptions = {},\n ): Promise<Record<string, unknown>> {\n let content: string;\n let fmt: string;\n\n let isFile = false;\n try {\n isFile = existsSync(pathOrText) && statSync(pathOrText).isFile();\n } catch {\n isFile = false;\n }\n\n if (isFile) {\n const ext = extname(pathOrText).toLowerCase();\n if (ext === \".pdf\") {\n throw new CographError(\n \"PDF ingest not yet supported in the Node CLI; use the Python CLI or POST raw bytes to the API.\",\n );\n }\n content = readFileSync(pathOrText, \"utf-8\");\n fmt = opts.contentType ?? EXT_FORMAT[ext] ?? \"text\";\n if (fmt === \"csv\") {\n return this.ingestCsv(content, opts.kg);\n }\n } else {\n content = pathOrText;\n fmt = opts.contentType ?? \"text\";\n }\n\n const body: Record<string, unknown> = {\n content,\n content_type: fmt,\n source: \"client\",\n };\n if (opts.kg) body.kg_name = opts.kg;\n return this.request(\"POST\", `${this.base()}/ingest`, body, 120_000);\n }\n\n private async ingestCsv(\n content: string,\n kgName: string | undefined,\n ): Promise<Record<string, unknown>> {\n const rows = parseCsv(content);\n if (rows.length === 0) throw new CographError(\"CSV is empty\");\n const headers = Object.keys(rows[0]!);\n\n const schemaBody = {\n headers,\n sample_rows: rows.slice(0, 5),\n total_rows: rows.length,\n };\n const mapping = await this.request<Record<string, unknown>>(\n \"POST\",\n `${this.base()}/ingest/csv/schema`,\n schemaBody,\n 300_000,\n );\n\n const batchSize = 50;\n let totalEntities = 0;\n let totalTriples = 0;\n for (let i = 0; i < rows.length; i += batchSize) {\n const batch = rows.slice(i, i + batchSize);\n const body: Record<string, unknown> = {\n mapping,\n rows: batch,\n source: \"client\",\n };\n if (kgName) body.kg_name = kgName;\n const result = await this.request<{\n entities_resolved?: number;\n triples_inserted?: number;\n }>(\"POST\", `${this.base()}/ingest/csv/rows`, body, 300_000);\n totalEntities += result.entities_resolved ?? 0;\n totalTriples += result.triples_inserted ?? 0;\n }\n\n return {\n entities_resolved: totalEntities,\n triples_inserted: totalTriples,\n mapping,\n };\n }\n\n /** Ask a natural language question and return the parsed response. */\n async ask(\n question: string,\n opts: AskOptions = {},\n ): Promise<Record<string, unknown>> {\n const body: Record<string, unknown> = { question };\n if (opts.kg) body.kg_name = opts.kg;\n if (opts.model) body.model = opts.model;\n return this.request(\"POST\", `${this.base()}/ask`, body, 60_000);\n }\n\n /** List all knowledge graphs for the current tenant. */\n async listKgs(): Promise<Array<Record<string, unknown>>> {\n const data = await this.request<unknown>(\n \"GET\",\n `${this.base()}/kgs`,\n undefined,\n 15_000,\n );\n if (Array.isArray(data)) return data as Array<Record<string, unknown>>;\n if (data && typeof data === \"object\" && \"kgs\" in data) {\n const kgs = (data as { kgs?: unknown }).kgs;\n if (Array.isArray(kgs)) return kgs as Array<Record<string, unknown>>;\n }\n return [];\n }\n\n /** Create a knowledge graph. */\n async createKg(\n name: string,\n description?: string,\n ): Promise<Record<string, unknown>> {\n const body: Record<string, unknown> = { name };\n if (description) body.description = description;\n return this.request(\"POST\", `${this.base()}/kgs`, body, 15_000);\n }\n\n /** Delete a knowledge graph by name. */\n async deleteKg(name: string): Promise<Record<string, unknown>> {\n return this.request(\n \"DELETE\",\n `${this.base()}/kgs/${encodeURIComponent(name)}`,\n undefined,\n 30_000,\n );\n }\n\n /** List ontology types. */\n async ontologyTypes(): Promise<Array<Record<string, unknown>>> {\n const data = await this.request<unknown>(\n \"GET\",\n `${this.base()}/ontology/types`,\n undefined,\n 15_000,\n );\n return Array.isArray(data) ? (data as Array<Record<string, unknown>>) : [];\n }\n}\n"],"mappings":"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","names":["text"]}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "cograph",
3
+ "version": "0.1.0",
4
+ "description": "Cograph SDK and CLI — knowledge graph platform for structured data",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "bin": {
15
+ "cograph": "./dist/cli.js"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "prepack": "node ../../scripts/chmod-bin.js packages/cograph/dist/cli.js"
24
+ },
25
+ "keywords": [
26
+ "knowledge-graph",
27
+ "cograph",
28
+ "sdk",
29
+ "cli",
30
+ "rdf",
31
+ "sparql",
32
+ "ontology",
33
+ "ai",
34
+ "llm"
35
+ ],
36
+ "author": "Cograph",
37
+ "license": "MIT",
38
+ "homepage": "https://cograph.cloud",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/git-moeen/cograph-oss.git",
42
+ "directory": "packages/cograph"
43
+ },
44
+ "bugs": {
45
+ "url": "https://github.com/git-moeen/cograph-oss/issues"
46
+ },
47
+ "dependencies": {
48
+ "commander": "^12.1.0"
49
+ },
50
+ "engines": {
51
+ "node": ">=20"
52
+ }
53
+ }