cograph 0.1.10 → 0.1.11
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-YVKKUWD7.js → chunk-LZAJDGV4.js} +39 -8
- package/dist/chunk-LZAJDGV4.js.map +1 -0
- package/dist/cli.js +3 -3
- package/dist/index.d.ts +15 -0
- package/dist/index.js +38 -7
- package/dist/index.js.map +1 -1
- package/dist/{shell-NXM324LH.js → shell-LWIHW6C7.js} +43 -6
- package/dist/shell-LWIHW6C7.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-YVKKUWD7.js.map +0 -1
- package/dist/shell-NXM324LH.js.map +0 -1
|
@@ -174,7 +174,7 @@ var Client = class {
|
|
|
174
174
|
content = readFileSync(pathOrText, "utf-8");
|
|
175
175
|
fmt = opts.contentType ?? EXT_FORMAT[ext] ?? "text";
|
|
176
176
|
if (fmt === "csv") {
|
|
177
|
-
return this.ingestCsv(content, opts
|
|
177
|
+
return this.ingestCsv(content, opts);
|
|
178
178
|
}
|
|
179
179
|
} else {
|
|
180
180
|
content = pathOrText;
|
|
@@ -188,7 +188,10 @@ var Client = class {
|
|
|
188
188
|
if (opts.kg) body.kg_name = opts.kg;
|
|
189
189
|
return this.request("POST", `${this.base()}/ingest`, body, 12e4);
|
|
190
190
|
}
|
|
191
|
-
async ingestCsv(content,
|
|
191
|
+
async ingestCsv(content, opts) {
|
|
192
|
+
const kgName = opts.kg;
|
|
193
|
+
const batchSize = opts.batchSize ?? 200;
|
|
194
|
+
const concurrency = opts.concurrency ?? 4;
|
|
192
195
|
const rows = parseCsv(content);
|
|
193
196
|
if (rows.length === 0) throw new CographError("CSV is empty");
|
|
194
197
|
const headers = Object.keys(rows[0]);
|
|
@@ -203,11 +206,15 @@ var Client = class {
|
|
|
203
206
|
schemaBody,
|
|
204
207
|
3e5
|
|
205
208
|
);
|
|
206
|
-
const
|
|
209
|
+
const batches = [];
|
|
210
|
+
for (let i = 0; i < rows.length; i += batchSize) {
|
|
211
|
+
batches.push(rows.slice(i, i + batchSize));
|
|
212
|
+
}
|
|
207
213
|
let totalEntities = 0;
|
|
208
214
|
let totalTriples = 0;
|
|
209
|
-
|
|
210
|
-
|
|
215
|
+
let rowsProcessed = 0;
|
|
216
|
+
let nextBatch = 0;
|
|
217
|
+
const postBatch = async (batch) => {
|
|
211
218
|
const body = {
|
|
212
219
|
mapping,
|
|
213
220
|
rows: batch,
|
|
@@ -215,9 +222,33 @@ var Client = class {
|
|
|
215
222
|
};
|
|
216
223
|
if (kgName) body.kg_name = kgName;
|
|
217
224
|
const result = await this.request("POST", `${this.base()}/ingest/csv/rows`, body, 3e5);
|
|
218
|
-
|
|
219
|
-
|
|
225
|
+
return {
|
|
226
|
+
entities: result.entities_resolved ?? 0,
|
|
227
|
+
triples: result.triples_inserted ?? 0,
|
|
228
|
+
size: batch.length
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
const worker = async () => {
|
|
232
|
+
while (true) {
|
|
233
|
+
const idx = nextBatch++;
|
|
234
|
+
if (idx >= batches.length) return;
|
|
235
|
+
const r = await postBatch(batches[idx]);
|
|
236
|
+
totalEntities += r.entities;
|
|
237
|
+
totalTriples += r.triples;
|
|
238
|
+
rowsProcessed += r.size;
|
|
239
|
+
opts.onProgress?.({
|
|
240
|
+
rowsProcessed,
|
|
241
|
+
totalRows: rows.length,
|
|
242
|
+
entitiesResolved: totalEntities,
|
|
243
|
+
triplesInserted: totalTriples
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
const workers = [];
|
|
248
|
+
for (let i = 0; i < Math.min(concurrency, batches.length); i++) {
|
|
249
|
+
workers.push(worker());
|
|
220
250
|
}
|
|
251
|
+
await Promise.all(workers);
|
|
221
252
|
return {
|
|
222
253
|
entities_resolved: totalEntities,
|
|
223
254
|
triples_inserted: totalTriples,
|
|
@@ -277,4 +308,4 @@ export {
|
|
|
277
308
|
CographError,
|
|
278
309
|
Client
|
|
279
310
|
};
|
|
280
|
-
//# sourceMappingURL=chunk-
|
|
311
|
+
//# sourceMappingURL=chunk-LZAJDGV4.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\";\nimport { readConfig } from \"./config.js\";\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 /** Rows per batch for CSV ingest. Default 200. Larger = fewer round-trips\n * but higher per-request memory; 200 is a good balance for typical KGs. */\n batchSize?: number;\n /** Max number of batches in flight at once. Default 4. Higher saturates\n * the backend faster but risks 429s on large ingests. */\n concurrency?: number;\n /** Called after each batch completes during CSV ingest, in batch order.\n * Use for progress UI. Not invoked for text/json ingest. */\n onProgress?: (progress: IngestProgress) => void;\n}\n\nexport interface IngestProgress {\n rowsProcessed: number;\n totalRows: number;\n entitiesResolved: number;\n triplesInserted: number;\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 // Resolution order for each field: explicit opts → env var → ~/.cograph/config.json\n // (written by `cograph login`) → built-in default. Reading the config eagerly\n // is cheap (small JSON file) and lets users skip env vars entirely after login.\n const cfg = readConfig();\n this.apiKey = opts.apiKey ?? envVar(\"API_KEY\") ?? cfg.apiKey;\n const url =\n opts.baseUrl ?? envVar(\"API_URL\") ?? cfg.apiUrl ?? \"https://api.cograph.cloud\";\n this.baseUrl = url.replace(/\\/+$/, \"\");\n this.tenant = opts.tenant ?? envVar(\"TENANT\") ?? cfg.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);\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 opts: IngestOptions,\n ): Promise<Record<string, unknown>> {\n const kgName = opts.kg;\n const batchSize = opts.batchSize ?? 200;\n const concurrency = opts.concurrency ?? 4;\n\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 // Slice rows into batches up front so we can fire them off in a\n // bounded worker pool. Sequential 50-row batches over 891 rows took\n // ~60s end-to-end (18 round-trips); 200-row batches × 4 in flight\n // brings that to ~5s on the same backend.\n const batches: Array<Record<string, string>[]> = [];\n for (let i = 0; i < rows.length; i += batchSize) {\n batches.push(rows.slice(i, i + batchSize));\n }\n\n let totalEntities = 0;\n let totalTriples = 0;\n let rowsProcessed = 0;\n let nextBatch = 0;\n\n const postBatch = async (batch: Record<string, string>[]) => {\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 return {\n entities: result.entities_resolved ?? 0,\n triples: result.triples_inserted ?? 0,\n size: batch.length,\n };\n };\n\n const worker = async (): Promise<void> => {\n while (true) {\n const idx = nextBatch++;\n if (idx >= batches.length) return;\n const r = await postBatch(batches[idx]!);\n totalEntities += r.entities;\n totalTriples += r.triples;\n rowsProcessed += r.size;\n opts.onProgress?.({\n rowsProcessed,\n totalRows: rows.length,\n entitiesResolved: totalEntities,\n triplesInserted: totalTriples,\n });\n }\n };\n\n const workers: Array<Promise<void>> = [];\n for (let i = 0; i < Math.min(concurrency, batches.length); i++) {\n workers.push(worker());\n }\n await Promise.all(workers);\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/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
Client,
|
|
4
4
|
CographError
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LZAJDGV4.js";
|
|
6
6
|
import "./chunk-7VVBEUZQ.js";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
@@ -36,7 +36,7 @@ async function confirm(prompt) {
|
|
|
36
36
|
}
|
|
37
37
|
var program = new Command();
|
|
38
38
|
program.name("cograph").description("Cograph Knowledge Graph CLI").version("0.1.7").action(async () => {
|
|
39
|
-
const { runShell } = await import("./shell-
|
|
39
|
+
const { runShell } = await import("./shell-LWIHW6C7.js");
|
|
40
40
|
await runShell({});
|
|
41
41
|
});
|
|
42
42
|
var kg = program.command("kg").description("Manage knowledge graphs");
|
|
@@ -286,7 +286,7 @@ program.command("login").description("Sign in via your browser and save an API k
|
|
|
286
286
|
await runLogin();
|
|
287
287
|
});
|
|
288
288
|
program.command("shell").description("Start an interactive REPL").option("--kg <name>", "Knowledge graph to use").action(async (opts) => {
|
|
289
|
-
const { runShell } = await import("./shell-
|
|
289
|
+
const { runShell } = await import("./shell-LWIHW6C7.js");
|
|
290
290
|
await runShell({ kg: opts.kg });
|
|
291
291
|
});
|
|
292
292
|
program.parseAsync(process.argv).catch((err) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,21 @@ interface ClientOptions {
|
|
|
14
14
|
interface IngestOptions {
|
|
15
15
|
kg?: string;
|
|
16
16
|
contentType?: "text" | "csv" | "json" | string;
|
|
17
|
+
/** Rows per batch for CSV ingest. Default 200. Larger = fewer round-trips
|
|
18
|
+
* but higher per-request memory; 200 is a good balance for typical KGs. */
|
|
19
|
+
batchSize?: number;
|
|
20
|
+
/** Max number of batches in flight at once. Default 4. Higher saturates
|
|
21
|
+
* the backend faster but risks 429s on large ingests. */
|
|
22
|
+
concurrency?: number;
|
|
23
|
+
/** Called after each batch completes during CSV ingest, in batch order.
|
|
24
|
+
* Use for progress UI. Not invoked for text/json ingest. */
|
|
25
|
+
onProgress?: (progress: IngestProgress) => void;
|
|
26
|
+
}
|
|
27
|
+
interface IngestProgress {
|
|
28
|
+
rowsProcessed: number;
|
|
29
|
+
totalRows: number;
|
|
30
|
+
entitiesResolved: number;
|
|
31
|
+
triplesInserted: number;
|
|
17
32
|
}
|
|
18
33
|
interface AskOptions {
|
|
19
34
|
kg?: string;
|
package/dist/index.js
CHANGED
|
@@ -195,7 +195,7 @@ var Client = class {
|
|
|
195
195
|
content = readFileSync2(pathOrText, "utf-8");
|
|
196
196
|
fmt = opts.contentType ?? EXT_FORMAT[ext] ?? "text";
|
|
197
197
|
if (fmt === "csv") {
|
|
198
|
-
return this.ingestCsv(content, opts
|
|
198
|
+
return this.ingestCsv(content, opts);
|
|
199
199
|
}
|
|
200
200
|
} else {
|
|
201
201
|
content = pathOrText;
|
|
@@ -209,7 +209,10 @@ var Client = class {
|
|
|
209
209
|
if (opts.kg) body.kg_name = opts.kg;
|
|
210
210
|
return this.request("POST", `${this.base()}/ingest`, body, 12e4);
|
|
211
211
|
}
|
|
212
|
-
async ingestCsv(content,
|
|
212
|
+
async ingestCsv(content, opts) {
|
|
213
|
+
const kgName = opts.kg;
|
|
214
|
+
const batchSize = opts.batchSize ?? 200;
|
|
215
|
+
const concurrency = opts.concurrency ?? 4;
|
|
213
216
|
const rows = parseCsv(content);
|
|
214
217
|
if (rows.length === 0) throw new CographError("CSV is empty");
|
|
215
218
|
const headers = Object.keys(rows[0]);
|
|
@@ -224,11 +227,15 @@ var Client = class {
|
|
|
224
227
|
schemaBody,
|
|
225
228
|
3e5
|
|
226
229
|
);
|
|
227
|
-
const
|
|
230
|
+
const batches = [];
|
|
231
|
+
for (let i = 0; i < rows.length; i += batchSize) {
|
|
232
|
+
batches.push(rows.slice(i, i + batchSize));
|
|
233
|
+
}
|
|
228
234
|
let totalEntities = 0;
|
|
229
235
|
let totalTriples = 0;
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
let rowsProcessed = 0;
|
|
237
|
+
let nextBatch = 0;
|
|
238
|
+
const postBatch = async (batch) => {
|
|
232
239
|
const body = {
|
|
233
240
|
mapping,
|
|
234
241
|
rows: batch,
|
|
@@ -236,9 +243,33 @@ var Client = class {
|
|
|
236
243
|
};
|
|
237
244
|
if (kgName) body.kg_name = kgName;
|
|
238
245
|
const result = await this.request("POST", `${this.base()}/ingest/csv/rows`, body, 3e5);
|
|
239
|
-
|
|
240
|
-
|
|
246
|
+
return {
|
|
247
|
+
entities: result.entities_resolved ?? 0,
|
|
248
|
+
triples: result.triples_inserted ?? 0,
|
|
249
|
+
size: batch.length
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
const worker = async () => {
|
|
253
|
+
while (true) {
|
|
254
|
+
const idx = nextBatch++;
|
|
255
|
+
if (idx >= batches.length) return;
|
|
256
|
+
const r = await postBatch(batches[idx]);
|
|
257
|
+
totalEntities += r.entities;
|
|
258
|
+
totalTriples += r.triples;
|
|
259
|
+
rowsProcessed += r.size;
|
|
260
|
+
opts.onProgress?.({
|
|
261
|
+
rowsProcessed,
|
|
262
|
+
totalRows: rows.length,
|
|
263
|
+
entitiesResolved: totalEntities,
|
|
264
|
+
triplesInserted: totalTriples
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
const workers = [];
|
|
269
|
+
for (let i = 0; i < Math.min(concurrency, batches.length); i++) {
|
|
270
|
+
workers.push(worker());
|
|
241
271
|
}
|
|
272
|
+
await Promise.all(workers);
|
|
242
273
|
return {
|
|
243
274
|
entities_resolved: totalEntities,
|
|
244
275
|
triples_inserted: totalTriples,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { extname } from \"node:path\";\nimport { readConfig } from \"./config.js\";\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 // Resolution order for each field: explicit opts → env var → ~/.cograph/config.json\n // (written by `cograph login`) → built-in default. Reading the config eagerly\n // is cheap (small JSON file) and lets users skip env vars entirely after login.\n const cfg = readConfig();\n this.apiKey = opts.apiKey ?? envVar(\"API_KEY\") ?? cfg.apiKey;\n const url =\n opts.baseUrl ?? envVar(\"API_URL\") ?? cfg.apiUrl ?? \"https://api.cograph.cloud\";\n this.baseUrl = url.replace(/\\/+$/, \"\");\n this.tenant = opts.tenant ?? envVar(\"TENANT\") ?? cfg.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","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from \"node:fs\";\n\nexport interface CographConfig {\n apiKey?: string;\n apiUrl?: string;\n tenant?: string;\n email?: string;\n}\n\nfunction configDir(): string {\n return join(homedir(), \".cograph\");\n}\n\nfunction configPath(): string {\n return join(configDir(), \"config.json\");\n}\n\n/**\n * Read `~/.cograph/config.json`. Returns an empty object if the file is\n * missing or unreadable — callers should treat fields as optional.\n */\nexport function readConfig(): CographConfig {\n const path = configPath();\n if (!existsSync(path)) return {};\n try {\n const raw = readFileSync(path, \"utf-8\");\n const parsed = JSON.parse(raw) as unknown;\n if (parsed && typeof parsed === \"object\") {\n return parsed as CographConfig;\n }\n } catch {\n // Corrupt or unreadable; behave as if absent so a fresh login can rewrite.\n }\n return {};\n}\n\n/**\n * Write `~/.cograph/config.json` with `chmod 600`. Creates the directory if\n * needed. Merges with the existing config so callers can update one field\n * without clobbering the others.\n */\nexport function writeConfig(patch: CographConfig): void {\n const dir = configDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n const merged = { ...readConfig(), ...patch };\n const path = configPath();\n writeFileSync(path, JSON.stringify(merged, null, 2) + \"\\n\", \"utf-8\");\n try {\n chmodSync(path, 0o600);\n } catch {\n // best-effort; some filesystems (e.g., FAT) don't honor chmod\n }\n}\n\nexport function configPathForDisplay(): string {\n return configPath();\n}\n"],"mappings":"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","names":["existsSync","readFileSync","text","existsSync","readFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { extname } from \"node:path\";\nimport { readConfig } from \"./config.js\";\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 /** Rows per batch for CSV ingest. Default 200. Larger = fewer round-trips\n * but higher per-request memory; 200 is a good balance for typical KGs. */\n batchSize?: number;\n /** Max number of batches in flight at once. Default 4. Higher saturates\n * the backend faster but risks 429s on large ingests. */\n concurrency?: number;\n /** Called after each batch completes during CSV ingest, in batch order.\n * Use for progress UI. Not invoked for text/json ingest. */\n onProgress?: (progress: IngestProgress) => void;\n}\n\nexport interface IngestProgress {\n rowsProcessed: number;\n totalRows: number;\n entitiesResolved: number;\n triplesInserted: number;\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 // Resolution order for each field: explicit opts → env var → ~/.cograph/config.json\n // (written by `cograph login`) → built-in default. Reading the config eagerly\n // is cheap (small JSON file) and lets users skip env vars entirely after login.\n const cfg = readConfig();\n this.apiKey = opts.apiKey ?? envVar(\"API_KEY\") ?? cfg.apiKey;\n const url =\n opts.baseUrl ?? envVar(\"API_URL\") ?? cfg.apiUrl ?? \"https://api.cograph.cloud\";\n this.baseUrl = url.replace(/\\/+$/, \"\");\n this.tenant = opts.tenant ?? envVar(\"TENANT\") ?? cfg.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);\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 opts: IngestOptions,\n ): Promise<Record<string, unknown>> {\n const kgName = opts.kg;\n const batchSize = opts.batchSize ?? 200;\n const concurrency = opts.concurrency ?? 4;\n\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 // Slice rows into batches up front so we can fire them off in a\n // bounded worker pool. Sequential 50-row batches over 891 rows took\n // ~60s end-to-end (18 round-trips); 200-row batches × 4 in flight\n // brings that to ~5s on the same backend.\n const batches: Array<Record<string, string>[]> = [];\n for (let i = 0; i < rows.length; i += batchSize) {\n batches.push(rows.slice(i, i + batchSize));\n }\n\n let totalEntities = 0;\n let totalTriples = 0;\n let rowsProcessed = 0;\n let nextBatch = 0;\n\n const postBatch = async (batch: Record<string, string>[]) => {\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 return {\n entities: result.entities_resolved ?? 0,\n triples: result.triples_inserted ?? 0,\n size: batch.length,\n };\n };\n\n const worker = async (): Promise<void> => {\n while (true) {\n const idx = nextBatch++;\n if (idx >= batches.length) return;\n const r = await postBatch(batches[idx]!);\n totalEntities += r.entities;\n totalTriples += r.triples;\n rowsProcessed += r.size;\n opts.onProgress?.({\n rowsProcessed,\n totalRows: rows.length,\n entitiesResolved: totalEntities,\n triplesInserted: totalTriples,\n });\n }\n };\n\n const workers: Array<Promise<void>> = [];\n for (let i = 0; i < Math.min(concurrency, batches.length); i++) {\n workers.push(worker());\n }\n await Promise.all(workers);\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","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from \"node:fs\";\n\nexport interface CographConfig {\n apiKey?: string;\n apiUrl?: string;\n tenant?: string;\n email?: string;\n}\n\nfunction configDir(): string {\n return join(homedir(), \".cograph\");\n}\n\nfunction configPath(): string {\n return join(configDir(), \"config.json\");\n}\n\n/**\n * Read `~/.cograph/config.json`. Returns an empty object if the file is\n * missing or unreadable — callers should treat fields as optional.\n */\nexport function readConfig(): CographConfig {\n const path = configPath();\n if (!existsSync(path)) return {};\n try {\n const raw = readFileSync(path, \"utf-8\");\n const parsed = JSON.parse(raw) as unknown;\n if (parsed && typeof parsed === \"object\") {\n return parsed as CographConfig;\n }\n } catch {\n // Corrupt or unreadable; behave as if absent so a fresh login can rewrite.\n }\n return {};\n}\n\n/**\n * Write `~/.cograph/config.json` with `chmod 600`. Creates the directory if\n * needed. Merges with the existing config so callers can update one field\n * without clobbering the others.\n */\nexport function writeConfig(patch: CographConfig): void {\n const dir = configDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n const merged = { ...readConfig(), ...patch };\n const path = configPath();\n writeFileSync(path, JSON.stringify(merged, null, 2) + \"\\n\", \"utf-8\");\n try {\n chmodSync(path, 0o600);\n } catch {\n // best-effort; some filesystems (e.g., FAT) don't honor chmod\n }\n}\n\nexport function configPathForDisplay(): string {\n return configPath();\n}\n"],"mappings":"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","names":["existsSync","readFileSync","text","existsSync","readFileSync"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
Client,
|
|
4
4
|
CographError
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LZAJDGV4.js";
|
|
6
6
|
import "./chunk-7VVBEUZQ.js";
|
|
7
7
|
|
|
8
8
|
// src/shell.ts
|
|
@@ -147,6 +147,29 @@ async function selectKg(client, rl) {
|
|
|
147
147
|
printError("Invalid selection.");
|
|
148
148
|
return null;
|
|
149
149
|
}
|
|
150
|
+
function startSpinner(initial) {
|
|
151
|
+
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
152
|
+
let frame = 0;
|
|
153
|
+
let text = initial;
|
|
154
|
+
let stopped = false;
|
|
155
|
+
const draw = () => {
|
|
156
|
+
if (stopped) return;
|
|
157
|
+
stdout.write(`\r\x1B[2K ${CYAN}${frames[frame]}${RESET} ${text}`);
|
|
158
|
+
frame = (frame + 1) % frames.length;
|
|
159
|
+
};
|
|
160
|
+
draw();
|
|
161
|
+
const tick = setInterval(draw, 80);
|
|
162
|
+
return {
|
|
163
|
+
setText(t) {
|
|
164
|
+
text = t;
|
|
165
|
+
},
|
|
166
|
+
stop() {
|
|
167
|
+
stopped = true;
|
|
168
|
+
clearInterval(tick);
|
|
169
|
+
stdout.write("\r\x1B[2K");
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
150
173
|
async function cmdIngest(client, kg, args) {
|
|
151
174
|
if (args.length === 0) {
|
|
152
175
|
stdout.write(` ${YELLOW}Usage:${RESET} /ingest <file> [<file>...]
|
|
@@ -154,17 +177,31 @@ async function cmdIngest(client, kg, args) {
|
|
|
154
177
|
return;
|
|
155
178
|
}
|
|
156
179
|
for (const file of args) {
|
|
157
|
-
|
|
158
|
-
`);
|
|
180
|
+
const sp = startSpinner(`Inferring schema from ${file}...`);
|
|
159
181
|
try {
|
|
160
|
-
const result = await client.ingest(file, {
|
|
182
|
+
const result = await client.ingest(file, {
|
|
183
|
+
kg,
|
|
184
|
+
onProgress: ({
|
|
185
|
+
rowsProcessed,
|
|
186
|
+
totalRows,
|
|
187
|
+
entitiesResolved,
|
|
188
|
+
triplesInserted
|
|
189
|
+
}) => {
|
|
190
|
+
const pct = Math.round(rowsProcessed / totalRows * 100);
|
|
191
|
+
sp.setText(
|
|
192
|
+
`Ingesting ${file} ${DIM}\xB7${RESET} ${BOLD}${pct}%${RESET} ${DIM}(${fmtNum(rowsProcessed)}/${fmtNum(totalRows)} rows \xB7 ${fmtNum(entitiesResolved)} entities \xB7 ${fmtNum(triplesInserted)} triples)${RESET}`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
sp.stop();
|
|
161
197
|
const ents = result.entities_resolved ?? 0;
|
|
162
198
|
const trip = result.triples_inserted ?? 0;
|
|
163
199
|
stdout.write(
|
|
164
|
-
` ${GREEN}\u2713${RESET} ${fmtNum(ents)} entities \xB7 ${fmtNum(trip)} triples
|
|
200
|
+
` ${GREEN}\u2713${RESET} ${file} ${DIM}\xB7${RESET} ${fmtNum(ents)} entities \xB7 ${fmtNum(trip)} triples
|
|
165
201
|
`
|
|
166
202
|
);
|
|
167
203
|
} catch (err) {
|
|
204
|
+
sp.stop();
|
|
168
205
|
if (err instanceof CographError) printError(err.message);
|
|
169
206
|
else printError(err instanceof Error ? err.message : String(err));
|
|
170
207
|
}
|
|
@@ -492,4 +529,4 @@ async function runShell(opts) {
|
|
|
492
529
|
export {
|
|
493
530
|
runShell
|
|
494
531
|
};
|
|
495
|
-
//# sourceMappingURL=shell-
|
|
532
|
+
//# sourceMappingURL=shell-LWIHW6C7.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 canRenderBlockArt(): boolean {\n // Apple_Terminal (macOS Terminal.app) treats the block-shade chars (▀█░)\n // we use in the banner as East Asian Ambiguous Width = 2 cells, so each\n // 28-char banner row renders as ~56 cells and wraps mid-letter. iTerm,\n // WezTerm, Kitty, VS Code, Cursor, etc. all treat them as 1 cell and\n // render the art correctly. Skip the banner on Apple_Terminal and show\n // a plain header instead. Force on/off via COGRAPH_BANNER=on|off.\n const force = process.env.COGRAPH_BANNER;\n if (force === \"on\") return true;\n if (force === \"off\") return false;\n if (!process.stdout.isTTY) return false;\n if (process.env.TERM_PROGRAM === \"Apple_Terminal\") return false;\n return true;\n}\n\nfunction showBanner(): void {\n if (canRenderBlockArt()) {\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 } else {\n stdout.write(`\\n ${CYAN_BOLD}cograph${RESET}\\n`);\n stdout.write(` ${DIM}The object graph for AI agents${RESET}\\n\\n`);\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 [\"/kg list\", \"List your knowledge graphs\"],\n [\"/kg switch <name>\", \"Switch to a different KG\"],\n [\"/kg create <name>\", \"Create a new KG and switch to it\"],\n [\"/kg delete <name>\", \"Delete a KG (irreversible)\"],\n [\"/login\", \"Re-authenticate (browser)\"],\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 your first KG.${RESET}\\n`,\n );\n const name = (await ask(rl, \" KG name: \")).trim();\n if (!name) return null;\n // Persist immediately. Without this, the name only existed as a local\n // string until the user ran /ingest, so quitting before ingesting lost\n // the KG entirely — and the next shell session showed \"No KGs found\"\n // again.\n try {\n await client.createKg(name);\n stdout.write(` ${GREEN}✓${RESET} Created ${BOLD}${name}${RESET}\\n`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // 409 / \"already exists\" is fine — someone created it between listKgs\n // and now, or the user retried. Anything else is a real failure.\n if (!/already exists|409/i.test(msg)) {\n printError(`Could not create knowledge graph: ${msg}`);\n return null;\n }\n }\n return name;\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\n/**\n * Tiny live-line spinner. Returns handles to update the trailing text and\n * stop. We use \\r + clear-line escape so the line redraws in place.\n */\nfunction startSpinner(initial: string): {\n setText: (text: string) => void;\n stop: () => void;\n} {\n const frames = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n let frame = 0;\n let text = initial;\n let stopped = false;\n\n const draw = (): void => {\n if (stopped) return;\n // \\x1b[2K = clear entire line; \\r = carriage return\n stdout.write(`\\r\\x1b[2K ${CYAN}${frames[frame]}${RESET} ${text}`);\n frame = (frame + 1) % frames.length;\n };\n draw();\n const tick = setInterval(draw, 80);\n\n return {\n setText(t: string) {\n text = t;\n },\n stop() {\n stopped = true;\n clearInterval(tick);\n stdout.write(\"\\r\\x1b[2K\");\n },\n };\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 const sp = startSpinner(`Inferring schema from ${file}...`);\n try {\n const result = await client.ingest(file, {\n kg,\n onProgress: ({\n rowsProcessed,\n totalRows,\n entitiesResolved,\n triplesInserted,\n }) => {\n const pct = Math.round((rowsProcessed / totalRows) * 100);\n sp.setText(\n `Ingesting ${file} ${DIM}·${RESET} ${BOLD}${pct}%${RESET} ` +\n `${DIM}(${fmtNum(rowsProcessed)}/${fmtNum(totalRows)} rows · ` +\n `${fmtNum(entitiesResolved)} entities · ${fmtNum(triplesInserted)} triples)${RESET}`,\n );\n },\n });\n sp.stop();\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} ${file} ${DIM}·${RESET} ${fmtNum(ents)} entities · ${fmtNum(trip)} triples\\n`,\n );\n } catch (err) {\n sp.stop();\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(kg: string, triples: number): string {\n const kgPart = `${DIM}(${kg})${RESET}`;\n if (triples > 0) {\n return ` ${CYAN_BOLD}cograph${RESET} ${kgPart} ${DIM}[${fmtNum(triples)}]${RESET} ${CYAN_BOLD}▸${RESET} `;\n }\n return ` ${CYAN_BOLD}cograph${RESET} ${kgPart} ${CYAN_BOLD}▸${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 // `let` rather than `const` so /login can swap in a fresh Client after\n // ~/.cograph/config.json is rewritten with the new key.\n let client = new Client();\n\n // First-run ergonomics: if no API key is configured (no env var, no\n // ~/.cograph/config.json), trigger the login flow before opening the\n // shell. Saves the friend from having to know to run `cograph login`\n // first — they just run `npx cograph` and the browser pops.\n if (!client.apiKey) {\n stdout.write(\n `\\n ${DIM}Not signed in — opening your browser to log in...${RESET}\\n`,\n );\n const { runLogin } = await import(\"./login.js\");\n await runLogin();\n client = new Client();\n if (!client.apiKey) {\n // runLogin already exits the process on hard failures, so reaching\n // here means it returned without writing a key (rare). Bail rather\n // than continue into a broken shell.\n printError(\"Login did not produce an API key. Aborting.\");\n return;\n }\n }\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(kg, 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 === \"/login\") {\n const { runLogin } = await import(\"./login.js\");\n await runLogin();\n // Pick up the new key from ~/.cograph/config.json for subsequent calls.\n client = new Client();\n await refresh();\n } else if (line === \"/kg\" || line.startsWith(\"/kg \")) {\n const args = splitArgs(line.slice(\"/kg\".length).trim());\n const sub = args[0] ?? \"list\";\n const target = args.slice(1).join(\" \");\n\n if (sub === \"list\") {\n const list = await client.listKgs();\n if (!list.length) {\n stdout.write(\n ` ${DIM}No knowledge graphs yet. /kg create <name>${RESET}\\n`,\n );\n } else {\n for (const k of list) {\n const n = String((k as { name?: string }).name ?? \"?\");\n const tc = Number((k as { triple_count?: number }).triple_count ?? 0);\n const marker = n === kg ? `${CYAN_BOLD}*${RESET}` : \" \";\n stdout.write(\n ` ${marker} ${BOLD}${n}${RESET} ${DIM}(${fmtNum(tc)} triples)${RESET}\\n`,\n );\n }\n }\n } else if (sub === \"switch\") {\n if (!target) {\n stdout.write(` ${YELLOW}Usage:${RESET} /kg switch <name>\\n`);\n } else {\n const list = await client.listKgs();\n const found = list.find(\n (k) => (k as { name?: string }).name === target,\n );\n if (!found) {\n printError(`KG not found: ${target}. Try /kg list.`);\n } else {\n kg = target;\n triples = Number(\n (found as { triple_count?: number }).triple_count ?? 0,\n );\n stdout.write(\n ` ${GREEN}✓${RESET} Switched to ${BOLD}${kg}${RESET}\\n`,\n );\n }\n }\n } else if (sub === \"create\") {\n if (!target) {\n stdout.write(` ${YELLOW}Usage:${RESET} /kg create <name>\\n`);\n } else {\n try {\n await client.createKg(target);\n kg = target;\n triples = 0;\n stdout.write(\n ` ${GREEN}✓${RESET} Created and switched to ${BOLD}${kg}${RESET}\\n`,\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (/already exists|409/i.test(msg)) {\n kg = target;\n await refresh();\n stdout.write(\n ` ${DIM}${target} already exists — switched to it.${RESET}\\n`,\n );\n } else {\n printError(`Could not create: ${msg}`);\n }\n }\n }\n } else if (sub === \"delete\") {\n if (!target) {\n stdout.write(` ${YELLOW}Usage:${RESET} /kg delete <name>\\n`);\n } else {\n const isActive = target === kg;\n const tag = isActive ? \" (the active KG)\" : \"\";\n const confirm = (\n await ask(\n rl,\n ` ${YELLOW}Delete KG \"${target}\"${tag}?${RESET} [y/N]: `,\n )\n )\n .trim()\n .toLowerCase();\n if (confirm === \"y\" || confirm === \"yes\") {\n try {\n await client.deleteKg(target);\n stdout.write(` ${GREEN}✓${RESET} Deleted ${BOLD}${target}${RESET}\\n`);\n if (isActive) {\n // Active KG is gone; let the user pick (or create) a new one\n // before any further commands try to use it.\n const picked = await selectKg(client, rl);\n if (!picked) {\n running = false;\n break;\n }\n kg = picked;\n await refresh();\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n printError(`Could not delete: ${msg}`);\n }\n } else {\n stdout.write(` ${DIM}Cancelled.${RESET}\\n`);\n }\n }\n } else {\n stdout.write(\n ` ${YELLOW}Unknown /kg subcommand: ${sub}.${RESET} Try /kg list, /kg switch <name>, /kg create <name>, /kg delete <name>.\\n`,\n );\n }\n } else if (line.startsWith(\"/\")) {\n stdout.write(\n ` ${YELLOW}Unknown command.${RESET} Try /ingest, /ask, /kg, /login, /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":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { extname } from \"node:path\";\nimport { readConfig } from \"./config.js\";\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 // Resolution order for each field: explicit opts → env var → ~/.cograph/config.json\n // (written by `cograph login`) → built-in default. Reading the config eagerly\n // is cheap (small JSON file) and lets users skip env vars entirely after login.\n const cfg = readConfig();\n this.apiKey = opts.apiKey ?? envVar(\"API_KEY\") ?? cfg.apiKey;\n const url =\n opts.baseUrl ?? envVar(\"API_URL\") ?? cfg.apiUrl ?? \"https://api.cograph.cloud\";\n this.baseUrl = url.replace(/\\/+$/, \"\");\n this.tenant = opts.tenant ?? envVar(\"TENANT\") ?? cfg.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":";;;;;;AAAA,SAAS,YAAY,cAAc,gBAAgB;AACnD,SAAS,eAAe;AAGjB,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC;AAAA,EACA;AAAA,EAEA,YAAY,SAAiB,MAA2C;AACtE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS,MAAM;AACpB,SAAK,OAAO,MAAM;AAAA,EACpB;AACF;AAkBA,SAAS,OAAO,MAAc,UAAuC;AAEnE,SACE,QAAQ,IAAI,WAAW,IAAI,EAAE,KAC7B,QAAQ,IAAI,SAAS,IAAI,EAAE,KAC3B;AAEJ;AAEA,IAAM,aAAqC;AAAA,EACzC,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AACV;AASO,SAAS,SAAS,SAA2C;AAClE,QAAM,OAAmB,CAAC;AAC1B,MAAI,MAAgB,CAAC;AACrB,MAAI,QAAQ;AACZ,MAAI,WAAW;AAEf,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,KAAK,QAAQ,CAAC;AACpB,QAAI,UAAU;AACZ,UAAI,OAAO,KAAK;AACd,YAAI,QAAQ,IAAI,CAAC,MAAM,KAAK;AAC1B,mBAAS;AACT;AAAA,QACF,OAAO;AACL,qBAAW;AAAA,QACb;AAAA,MACF,OAAO;AACL,iBAAS;AAAA,MACX;AAAA,IACF,OAAO;AACL,UAAI,OAAO,KAAK;AACd,mBAAW;AAAA,MACb,WAAW,OAAO,KAAK;AACrB,YAAI,KAAK,KAAK;AACd,gBAAQ;AAAA,MACV,WAAW,OAAO,MAAM;AACtB,YAAI,KAAK,KAAK;AACd,aAAK,KAAK,GAAG;AACb,cAAM,CAAC;AACP,gBAAQ;AAAA,MACV,WAAW,OAAO,MAAM;AAEtB,YAAI,QAAQ,IAAI,CAAC,MAAM,MAAM;AAC3B,cAAI,KAAK,KAAK;AACd,eAAK,KAAK,GAAG;AACb,gBAAM,CAAC;AACP,kBAAQ;AAAA,QACV;AAAA,MACF,OAAO;AACL,iBAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAEA,MAAI,MAAM,SAAS,KAAK,IAAI,SAAS,GAAG;AACtC,QAAI,KAAK,KAAK;AACd,SAAK,KAAK,GAAG;AAAA,EACf;AAEA,MAAI,KAAK,WAAW,EAAG,QAAO,CAAC;AAC/B,QAAM,UAAU,KAAK,CAAC,EAAG,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAC5C,QAAM,MAAgC,CAAC;AACvC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAElB,QAAI,IAAI,WAAW,KAAK,IAAI,CAAC,MAAM,GAAI;AACvC,UAAM,MAA8B,CAAC;AACrC,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAI,QAAQ,CAAC,CAAE,IAAI,IAAI,CAAC,KAAK;AAAA,IAC/B;AACA,QAAI,KAAK,GAAG;AAAA,EACd;AACA,SAAO;AACT;AAEO,IAAM,SAAN,MAAa;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,OAAsB,CAAC,GAAG;AAIpC,UAAM,MAAM,WAAW;AACvB,SAAK,SAAS,KAAK,UAAU,OAAO,SAAS,KAAK,IAAI;AACtD,UAAM,MACJ,KAAK,WAAW,OAAO,SAAS,KAAK,IAAI,UAAU;AACrD,SAAK,UAAU,IAAI,QAAQ,QAAQ,EAAE;AACrC,SAAK,SAAS,KAAK,UAAU,OAAO,QAAQ,KAAK,IAAI,UAAU;AAAA,EACjE;AAAA,EAEQ,UAAkC;AACxC,UAAM,IAA4B,EAAE,gBAAgB,mBAAmB;AACvE,QAAI,KAAK,OAAQ,GAAE,WAAW,IAAI,KAAK;AACvC,WAAO;AAAA,EACT;AAAA,EAEQ,OAAe;AACrB,WAAO,GAAG,KAAK,OAAO,WAAW,KAAK,MAAM;AAAA,EAC9C;AAAA,EAEA,MAAc,QACZ,QACA,KACA,MACA,YAAoB,MACR;AACZ,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAC5D,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,MAAM,KAAK;AAAA,QACrB;AAAA,QACA,SAAS,KAAK,QAAQ;AAAA,QACtB,MAAM,SAAS,SAAY,SAAY,KAAK,UAAU,IAAI;AAAA,QAC1D,QAAQ,WAAW;AAAA,MACrB,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,mBAAa,KAAK;AAClB,UAAI,eAAe,SAAS,IAAI,SAAS,cAAc;AACrD,cAAM,IAAI,aAAa,cAAc,GAAG,oBAAoB,SAAS,IAAI;AAAA,MAC3E;AACA,YAAM,IAAI;AAAA,QACR,4BAA4B,GAAG,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACtF;AAAA,IACF;AACA,iBAAa,KAAK;AAElB,QAAI,CAAC,IAAI,IAAI;AACX,UAAIA,QAAO;AACX,UAAI;AACF,QAAAA,QAAO,MAAM,IAAI,KAAK;AAAA,MACxB,QAAQ;AAAA,MAER;AACA,YAAM,IAAI,aAAa,QAAQ,IAAI,MAAM,KAAKA,KAAI,IAAI;AAAA,QACpD,QAAQ,IAAI;AAAA,QACZ,MAAMA;AAAA,MACR,CAAC;AAAA,IACH;AAGA,QAAI,IAAI,WAAW,IAAK,QAAO;AAE/B,UAAM,KAAK,IAAI,QAAQ,IAAI,cAAc,KAAK;AAC9C,QAAI,GAAG,SAAS,kBAAkB,GAAG;AACnC,aAAQ,MAAM,IAAI,KAAK;AAAA,IACzB;AAEA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI;AACF,aAAO,KAAK,MAAM,IAAI;AAAA,IACxB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,OACJ,YACA,OAAsB,CAAC,GACW;AAClC,QAAI;AACJ,QAAI;AAEJ,QAAI,SAAS;AACb,QAAI;AACF,eAAS,WAAW,UAAU,KAAK,SAAS,UAAU,EAAE,OAAO;AAAA,IACjE,QAAQ;AACN,eAAS;AAAA,IACX;AAEA,QAAI,QAAQ;AACV,YAAM,MAAM,QAAQ,UAAU,EAAE,YAAY;AAC5C,UAAI,QAAQ,QAAQ;AAClB,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,gBAAU,aAAa,YAAY,OAAO;AAC1C,YAAM,KAAK,eAAe,WAAW,GAAG,KAAK;AAC7C,UAAI,QAAQ,OAAO;AACjB,eAAO,KAAK,UAAU,SAAS,KAAK,EAAE;AAAA,MACxC;AAAA,IACF,OAAO;AACL,gBAAU;AACV,YAAM,KAAK,eAAe;AAAA,IAC5B;AAEA,UAAM,OAAgC;AAAA,MACpC;AAAA,MACA,cAAc;AAAA,MACd,QAAQ;AAAA,IACV;AACA,QAAI,KAAK,GAAI,MAAK,UAAU,KAAK;AACjC,WAAO,KAAK,QAAQ,QAAQ,GAAG,KAAK,KAAK,CAAC,WAAW,MAAM,IAAO;AAAA,EACpE;AAAA,EAEA,MAAc,UACZ,SACA,QACkC;AAClC,UAAM,OAAO,SAAS,OAAO;AAC7B,QAAI,KAAK,WAAW,EAAG,OAAM,IAAI,aAAa,cAAc;AAC5D,UAAM,UAAU,OAAO,KAAK,KAAK,CAAC,CAAE;AAEpC,UAAM,aAAa;AAAA,MACjB;AAAA,MACA,aAAa,KAAK,MAAM,GAAG,CAAC;AAAA,MAC5B,YAAY,KAAK;AAAA,IACnB;AACA,UAAM,UAAU,MAAM,KAAK;AAAA,MACzB;AAAA,MACA,GAAG,KAAK,KAAK,CAAC;AAAA,MACd;AAAA,MACA;AAAA,IACF;AAEA,UAAM,YAAY;AAClB,QAAI,gBAAgB;AACpB,QAAI,eAAe;AACnB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,WAAW;AAC/C,YAAM,QAAQ,KAAK,MAAM,GAAG,IAAI,SAAS;AACzC,YAAM,OAAgC;AAAA,QACpC;AAAA,QACA,MAAM;AAAA,QACN,QAAQ;AAAA,MACV;AACA,UAAI,OAAQ,MAAK,UAAU;AAC3B,YAAM,SAAS,MAAM,KAAK,QAGvB,QAAQ,GAAG,KAAK,KAAK,CAAC,oBAAoB,MAAM,GAAO;AAC1D,uBAAiB,OAAO,qBAAqB;AAC7C,sBAAgB,OAAO,oBAAoB;AAAA,IAC7C;AAEA,WAAO;AAAA,MACL,mBAAmB;AAAA,MACnB,kBAAkB;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,IACJ,UACA,OAAmB,CAAC,GACc;AAClC,UAAM,OAAgC,EAAE,SAAS;AACjD,QAAI,KAAK,GAAI,MAAK,UAAU,KAAK;AACjC,QAAI,KAAK,MAAO,MAAK,QAAQ,KAAK;AAClC,WAAO,KAAK,QAAQ,QAAQ,GAAG,KAAK,KAAK,CAAC,QAAQ,MAAM,GAAM;AAAA,EAChE;AAAA;AAAA,EAGA,MAAM,UAAmD;AACvD,UAAM,OAAO,MAAM,KAAK;AAAA,MACtB;AAAA,MACA,GAAG,KAAK,KAAK,CAAC;AAAA,MACd;AAAA,MACA;AAAA,IACF;AACA,QAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,QAAI,QAAQ,OAAO,SAAS,YAAY,SAAS,MAAM;AACrD,YAAM,MAAO,KAA2B;AACxC,UAAI,MAAM,QAAQ,GAAG,EAAG,QAAO;AAAA,IACjC;AACA,WAAO,CAAC;AAAA,EACV;AAAA;AAAA,EAGA,MAAM,SACJ,MACA,aACkC;AAClC,UAAM,OAAgC,EAAE,KAAK;AAC7C,QAAI,YAAa,MAAK,cAAc;AACpC,WAAO,KAAK,QAAQ,QAAQ,GAAG,KAAK,KAAK,CAAC,QAAQ,MAAM,IAAM;AAAA,EAChE;AAAA;AAAA,EAGA,MAAM,SAAS,MAAgD;AAC7D,WAAO,KAAK;AAAA,MACV;AAAA,MACA,GAAG,KAAK,KAAK,CAAC,QAAQ,mBAAmB,IAAI,CAAC;AAAA,MAC9C;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,gBAAyD;AAC7D,UAAM,OAAO,MAAM,KAAK;AAAA,MACtB;AAAA,MACA,GAAG,KAAK,KAAK,CAAC;AAAA,MACd;AAAA,MACA;AAAA,IACF;AACA,WAAO,MAAM,QAAQ,IAAI,IAAK,OAA0C,CAAC;AAAA,EAC3E;AACF;","names":["text"]}
|
|
@@ -1 +0,0 @@
|
|
|
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 canRenderBlockArt(): boolean {\n // Apple_Terminal (macOS Terminal.app) treats the block-shade chars (▀█░)\n // we use in the banner as East Asian Ambiguous Width = 2 cells, so each\n // 28-char banner row renders as ~56 cells and wraps mid-letter. iTerm,\n // WezTerm, Kitty, VS Code, Cursor, etc. all treat them as 1 cell and\n // render the art correctly. Skip the banner on Apple_Terminal and show\n // a plain header instead. Force on/off via COGRAPH_BANNER=on|off.\n const force = process.env.COGRAPH_BANNER;\n if (force === \"on\") return true;\n if (force === \"off\") return false;\n if (!process.stdout.isTTY) return false;\n if (process.env.TERM_PROGRAM === \"Apple_Terminal\") return false;\n return true;\n}\n\nfunction showBanner(): void {\n if (canRenderBlockArt()) {\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 } else {\n stdout.write(`\\n ${CYAN_BOLD}cograph${RESET}\\n`);\n stdout.write(` ${DIM}The object graph for AI agents${RESET}\\n\\n`);\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 [\"/kg list\", \"List your knowledge graphs\"],\n [\"/kg switch <name>\", \"Switch to a different KG\"],\n [\"/kg create <name>\", \"Create a new KG and switch to it\"],\n [\"/kg delete <name>\", \"Delete a KG (irreversible)\"],\n [\"/login\", \"Re-authenticate (browser)\"],\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 your first KG.${RESET}\\n`,\n );\n const name = (await ask(rl, \" KG name: \")).trim();\n if (!name) return null;\n // Persist immediately. Without this, the name only existed as a local\n // string until the user ran /ingest, so quitting before ingesting lost\n // the KG entirely — and the next shell session showed \"No KGs found\"\n // again.\n try {\n await client.createKg(name);\n stdout.write(` ${GREEN}✓${RESET} Created ${BOLD}${name}${RESET}\\n`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // 409 / \"already exists\" is fine — someone created it between listKgs\n // and now, or the user retried. Anything else is a real failure.\n if (!/already exists|409/i.test(msg)) {\n printError(`Could not create knowledge graph: ${msg}`);\n return null;\n }\n }\n return name;\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(kg: string, triples: number): string {\n const kgPart = `${DIM}(${kg})${RESET}`;\n if (triples > 0) {\n return ` ${CYAN_BOLD}cograph${RESET} ${kgPart} ${DIM}[${fmtNum(triples)}]${RESET} ${CYAN_BOLD}▸${RESET} `;\n }\n return ` ${CYAN_BOLD}cograph${RESET} ${kgPart} ${CYAN_BOLD}▸${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 // `let` rather than `const` so /login can swap in a fresh Client after\n // ~/.cograph/config.json is rewritten with the new key.\n let client = new Client();\n\n // First-run ergonomics: if no API key is configured (no env var, no\n // ~/.cograph/config.json), trigger the login flow before opening the\n // shell. Saves the friend from having to know to run `cograph login`\n // first — they just run `npx cograph` and the browser pops.\n if (!client.apiKey) {\n stdout.write(\n `\\n ${DIM}Not signed in — opening your browser to log in...${RESET}\\n`,\n );\n const { runLogin } = await import(\"./login.js\");\n await runLogin();\n client = new Client();\n if (!client.apiKey) {\n // runLogin already exits the process on hard failures, so reaching\n // here means it returned without writing a key (rare). Bail rather\n // than continue into a broken shell.\n printError(\"Login did not produce an API key. Aborting.\");\n return;\n }\n }\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(kg, 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 === \"/login\") {\n const { runLogin } = await import(\"./login.js\");\n await runLogin();\n // Pick up the new key from ~/.cograph/config.json for subsequent calls.\n client = new Client();\n await refresh();\n } else if (line === \"/kg\" || line.startsWith(\"/kg \")) {\n const args = splitArgs(line.slice(\"/kg\".length).trim());\n const sub = args[0] ?? \"list\";\n const target = args.slice(1).join(\" \");\n\n if (sub === \"list\") {\n const list = await client.listKgs();\n if (!list.length) {\n stdout.write(\n ` ${DIM}No knowledge graphs yet. /kg create <name>${RESET}\\n`,\n );\n } else {\n for (const k of list) {\n const n = String((k as { name?: string }).name ?? \"?\");\n const tc = Number((k as { triple_count?: number }).triple_count ?? 0);\n const marker = n === kg ? `${CYAN_BOLD}*${RESET}` : \" \";\n stdout.write(\n ` ${marker} ${BOLD}${n}${RESET} ${DIM}(${fmtNum(tc)} triples)${RESET}\\n`,\n );\n }\n }\n } else if (sub === \"switch\") {\n if (!target) {\n stdout.write(` ${YELLOW}Usage:${RESET} /kg switch <name>\\n`);\n } else {\n const list = await client.listKgs();\n const found = list.find(\n (k) => (k as { name?: string }).name === target,\n );\n if (!found) {\n printError(`KG not found: ${target}. Try /kg list.`);\n } else {\n kg = target;\n triples = Number(\n (found as { triple_count?: number }).triple_count ?? 0,\n );\n stdout.write(\n ` ${GREEN}✓${RESET} Switched to ${BOLD}${kg}${RESET}\\n`,\n );\n }\n }\n } else if (sub === \"create\") {\n if (!target) {\n stdout.write(` ${YELLOW}Usage:${RESET} /kg create <name>\\n`);\n } else {\n try {\n await client.createKg(target);\n kg = target;\n triples = 0;\n stdout.write(\n ` ${GREEN}✓${RESET} Created and switched to ${BOLD}${kg}${RESET}\\n`,\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (/already exists|409/i.test(msg)) {\n kg = target;\n await refresh();\n stdout.write(\n ` ${DIM}${target} already exists — switched to it.${RESET}\\n`,\n );\n } else {\n printError(`Could not create: ${msg}`);\n }\n }\n }\n } else if (sub === \"delete\") {\n if (!target) {\n stdout.write(` ${YELLOW}Usage:${RESET} /kg delete <name>\\n`);\n } else {\n const isActive = target === kg;\n const tag = isActive ? \" (the active KG)\" : \"\";\n const confirm = (\n await ask(\n rl,\n ` ${YELLOW}Delete KG \"${target}\"${tag}?${RESET} [y/N]: `,\n )\n )\n .trim()\n .toLowerCase();\n if (confirm === \"y\" || confirm === \"yes\") {\n try {\n await client.deleteKg(target);\n stdout.write(` ${GREEN}✓${RESET} Deleted ${BOLD}${target}${RESET}\\n`);\n if (isActive) {\n // Active KG is gone; let the user pick (or create) a new one\n // before any further commands try to use it.\n const picked = await selectKg(client, rl);\n if (!picked) {\n running = false;\n break;\n }\n kg = picked;\n await refresh();\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n printError(`Could not delete: ${msg}`);\n }\n } else {\n stdout.write(` ${DIM}Cancelled.${RESET}\\n`);\n }\n }\n } else {\n stdout.write(\n ` ${YELLOW}Unknown /kg subcommand: ${sub}.${RESET} Try /kg list, /kg switch <name>, /kg create <name>, /kg delete <name>.\\n`,\n );\n }\n } else if (line.startsWith(\"/\")) {\n stdout.write(\n ` ${YELLOW}Unknown command.${RESET} Try /ingest, /ask, /kg, /login, /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":"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","names":[]}
|