cograph 0.1.27 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { createInterface } from \"node:readline\";\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\nimport { Client, CographError } from \"./client.js\";\nimport { readConfig, writeConfig, configPathForDisplay } from \"./config.js\";\n\n// Read version from package.json at runtime so we never drift again.\n// dist/cli.js sits next to package.json once published; in dev (`npm link`)\n// dist/cli.js sits inside packages/cograph/dist/, so the parent dir is the\n// package root either way.\nfunction pkgVersion(): string {\n try {\n const here = dirname(fileURLToPath(import.meta.url));\n const pkg = JSON.parse(readFileSync(join(here, \"..\", \"package.json\"), \"utf-8\"));\n return typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nfunction client(): Client {\n // Honor the global flags: --tenant overrides the saved default for this\n // command; --local points at a self-hosted backend. Both fall through to\n // env / ~/.cograph/config.json when not passed.\n const g = program.opts() as { tenant?: string; local?: boolean };\n return new Client({\n ...(g.tenant ? { tenant: g.tenant } : {}),\n ...(g.local ? { baseUrl: \"http://localhost:8000\" } : {}),\n });\n}\n\nfunction printJson(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\nfunction fail(msg: string, code = 1): never {\n process.stderr.write(msg.endsWith(\"\\n\") ? msg : msg + \"\\n\");\n process.exit(code);\n}\n\nasync function withErrors<T>(fn: () => Promise<T>): Promise<T | void> {\n try {\n return await fn();\n } catch (err) {\n if (err instanceof CographError) {\n fail(`Error: ${err.message}`);\n }\n fail(`Error: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\nasync function confirm(prompt: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${prompt} [y/N] `, (ans) => {\n rl.close();\n resolve(ans.trim().toLowerCase() === \"y\");\n });\n });\n}\n\n/** Like confirm() but defaults to yes (used for the primary \"apply\" action). */\nasync function confirmYes(prompt: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${prompt} [Y/n] `, (ans) => {\n rl.close();\n const a = ans.trim().toLowerCase();\n resolve(a === \"\" || a === \"y\" || a === \"yes\");\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// CSV schema review — terminal port of the Explorer's confirm/override gate.\n// The backend applies exactly what /ingest/csv/rows is given, so the client is\n// responsible for surfacing the inferred mapping and gating held-for-review\n// type extensions before any rows are written.\n// ---------------------------------------------------------------------------\n\nconst useColor = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;\nconst sgr = (code: string) => (s: string): string =>\n useColor ? `\\x1b[${code}m${s}\\x1b[0m` : s;\nconst bold = sgr(\"1\");\nconst dim = sgr(\"2\");\n\ntype Mapping = Record<string, any>;\n\ninterface EntityView {\n name: string;\n type_name: string;\n id_column?: string | null;\n id_from?: string[] | null;\n key_strategy?: string | null;\n confidence?: number | null;\n why?: string | null;\n}\n\nfunction entityViews(m: Mapping): EntityView[] {\n if (Array.isArray(m.entities) && m.entities.length > 0) {\n return m.entities.map((e: any) => ({\n name: e.name,\n type_name: e.type_name,\n id_column: e.id_column,\n id_from: e.id_from,\n key_strategy: e.key_strategy ?? null,\n confidence: e.confidence,\n why: e.why,\n }));\n }\n return [\n {\n name: m.entity_type,\n type_name: m.entity_type,\n key_strategy: m.key_strategy ?? null,\n confidence: m.confidence,\n why: m.why,\n },\n ];\n}\n\nfunction heldTypes(m: Mapping): any[] {\n const types = m.ontology_extensions?.types;\n return Array.isArray(types) ? types.filter((t: any) => t.held_for_review) : [];\n}\n\n/** Strip response-only audit fields (violations, inference_audit, profile) and\n * keep only what /ingest/csv/rows applies. Held type extensions are dropped\n * unless explicitly approved — same gate the Explorer applies on confirm. */\nfunction buildMappingForIngest(m: Mapping, approved: Set<string>): Mapping {\n const out: Mapping = { entity_type: m.entity_type, columns: m.columns };\n if (m.entities) out.entities = m.entities;\n if (m.relationships) out.relationships = m.relationships;\n const types = m.ontology_extensions?.types;\n if (Array.isArray(types)) {\n out.ontology_extensions = {\n types: types.filter(\n (t: any) => !t.held_for_review || approved.has(t.type_name),\n ),\n };\n }\n return out;\n}\n\nfunction fmtConf(v: any): string {\n if (v == null) return \"\";\n const n = Number(v);\n if (Number.isNaN(n)) return \"\";\n return dim(` (${n.toFixed(2)}${n < 0.7 ? \" !\" : \"\"})`);\n}\n\nfunction renderMapping(\n m: Mapping,\n info: { totalRows: number; rowsProfiled: number },\n): void {\n const w = (s: string) => process.stdout.write(s);\n w(\n \"\\n\" +\n bold(\"Proposed schema\") +\n dim(\n ` (profiled ${info.rowsProfiled.toLocaleString()} of ${info.totalRows.toLocaleString()} rows)`,\n ) +\n \"\\n\",\n );\n w(dim(\"Review how the data maps to the graph before any rows are written.\") + \"\\n\\n\");\n\n const ents = entityViews(m);\n const multi = Array.isArray(m.entities) && m.entities.length > 0;\n w(bold(\"Entities & keys\") + \"\\n\");\n for (const e of ents) {\n const key = e.id_column\n ? `key: ${e.id_column}`\n : e.id_from && e.id_from.length\n ? `key: ${e.id_from.join(\" + \")}`\n : e.key_strategy === \"synthetic\"\n ? \"key: (synthetic)\"\n : \"key: —\";\n w(` • ${bold(e.type_name)} ${dim(key)}${fmtConf(e.confidence)}\\n`);\n if (e.why) w(` ${dim(e.why)}\\n`);\n const cols = (m.columns ?? []).filter((col: any) =>\n multi ? col.entity === e.name : true,\n );\n for (const col of cols) {\n const role =\n col.role === \"type_id\"\n ? \"key \"\n : col.role === \"relationship\"\n ? \"edge\"\n : \"attr\";\n let detail = \"\";\n if (col.role === \"relationship\" && col.target_type)\n detail = ` → ${col.target_type}`;\n else if (\n col.role === \"attribute\" &&\n col.attribute_name &&\n col.attribute_name !== col.column_name\n )\n detail = ` as ${col.attribute_name}`;\n const dt =\n col.datatype && col.datatype !== \"string\"\n ? \" \" + dim(`[${col.datatype}]`)\n : \"\";\n w(\n ` ${dim(\"[\" + role + \"]\")} ${col.column_name}${detail}${dt}${fmtConf(col.confidence)}\\n`,\n );\n }\n }\n\n const rels = m.relationships ?? [];\n if (rels.length) {\n w(\"\\n\" + bold(\"Edges\") + \"\\n\");\n for (const r of rels)\n w(` • ${r.subject} ${dim(r.predicate)} ${r.object}${fmtConf(r.confidence)}\\n`);\n }\n\n const vio = m.violations ?? [];\n if (vio.length) {\n w(\n \"\\n\" +\n dim(\n `Refute pass corrected ${vio.length} issue${vio.length === 1 ? \"\" : \"s\"}: ${vio\n .map((v: any) => v.template)\n .join(\", \")}`,\n ) +\n \"\\n\",\n );\n }\n}\n\n/** Interactive confirm/override gate, passed to client.ingest as\n * onSchemaInferred. Returns the mapping to ingest, or null to cancel. */\nasync function reviewMapping(\n m: Mapping,\n info: { totalRows: number; rowsProfiled: number },\n): Promise<Mapping | null> {\n renderMapping(m, info);\n const approved = new Set<string>();\n const held = heldTypes(m);\n if (held.length) {\n process.stdout.write(\n \"\\n\" +\n bold(`${held.length} new type${held.length === 1 ? \"\" : \"s\"} held for review`) +\n dim(\" — approve to create, or skip to leave for later\") +\n \"\\n\",\n );\n for (const t of held) {\n const from = t.promoted_from_attribute\n ? dim(` (from \"${t.promoted_from_attribute}\")`)\n : \"\";\n process.stdout.write(` • ${t.type_name}${from}${fmtConf(t.confidence)}\\n`);\n if (await confirm(` Approve \"${t.type_name}\"?`)) approved.add(t.type_name);\n }\n }\n process.stdout.write(\"\\n\");\n const ok = await confirmYes(\n `Apply this mapping and ingest ${info.totalRows.toLocaleString()} rows?`,\n );\n if (!ok) return null;\n return buildMappingForIngest(m, approved);\n}\n\nconst program = new Command();\nprogram\n .name(\"cograph\")\n .description(\"Cograph Knowledge Graph CLI\")\n .version(pkgVersion())\n // Default action when no subcommand is given: drop into the interactive\n // shell. So `cograph` (or `npx cograph`) Just Works for the common case;\n // subcommands like `cograph ingest <file>` still route to their own\n // actions because commander dispatches subcommands first.\n .option(\"--local\", \"Use http://localhost:8000 and skip login (self-hosted)\")\n .option(\"--no-login\", \"Skip browser login (assume open-access backend)\")\n .option(\n \"--tenant <id>\",\n \"Target a specific tenant for this command (overrides the saved default)\",\n )\n .action(async (opts: { local?: boolean; login?: boolean }) => {\n const { runShell } = await import(\"./shell.js\");\n await runShell({\n local: opts.local,\n // commander's --no-login inverts: opts.login === false when flag passed.\n noLogin: opts.login === false,\n });\n });\n\n// ---------------------------------------------------------------------------\n// kg\n// ---------------------------------------------------------------------------\n\nconst kg = program.command(\"kg\").description(\"Manage knowledge graphs\");\n\nkg.command(\"list\")\n .description(\"List knowledge graphs\")\n .action(async () => {\n await withErrors(async () => {\n const kgs = await client().listKgs();\n if (!kgs.length) {\n process.stdout.write(\n \"No knowledge graphs. Create one with: cograph kg create <name>\\n\",\n );\n return;\n }\n for (const k of kgs) {\n const name = String(k.name ?? \"?\");\n const triples = Number(k.triple_count ?? 0);\n const desc = k.description ? ` — ${k.description}` : \"\";\n const padName = name.padEnd(20, \" \");\n const padTriples = String(triples).padStart(6, \" \");\n process.stdout.write(` ${padName} ${padTriples} triples${desc}\\n`);\n }\n });\n });\n\nkg.command(\"create <name>\")\n .description(\"Create a knowledge graph\")\n .option(\"-d, --description <text>\", \"Description\")\n .action(async (name: string, opts: { description?: string }) => {\n await withErrors(async () => {\n const created = await client().createKg(name, opts.description);\n process.stdout.write(`Created knowledge graph: ${created.name ?? name}\\n`);\n });\n });\n\nkg.command(\"delete <name>\")\n .description(\"Delete a knowledge graph\")\n .action(async (name: string) => {\n await withErrors(async () => {\n await client().deleteKg(name);\n process.stdout.write(`Deleted knowledge graph: ${name}\\n`);\n });\n });\n\n// ---------------------------------------------------------------------------\n// tenant\n// ---------------------------------------------------------------------------\n\nconst tenantCmd = program\n .command(\"tenant\")\n .description(\"Show or switch the active tenant\");\n\ntenantCmd\n .command(\"current\", { isDefault: true })\n .description(\"Show the active tenant\")\n .action(() => {\n const active = client().tenant;\n const saved = readConfig().tenant;\n process.stdout.write(`Active tenant: ${bold(active)}\\n`);\n process.stdout.write(\n saved\n ? dim(` saved default in ${configPathForDisplay()}\\n`)\n : dim(` (built-in default — set one with: cograph tenant use <id>)\\n`),\n );\n });\n\ntenantCmd\n .command(\"list\")\n .description(\"List the tenants you can access\")\n .action(async () => {\n await withErrors(async () => {\n const c = client();\n let tenants: Array<{ id: string; label: string }>;\n try {\n tenants = await c.listTenants();\n } catch (err) {\n if (err instanceof CographError && err.status === 501) {\n fail(\n \"This backend doesn't support tenant management (no tenant provider configured).\",\n );\n }\n throw err;\n }\n if (!tenants.length) {\n process.stdout.write(\"No tenants found for your account.\\n\");\n return;\n }\n const active = c.tenant;\n for (const t of tenants) {\n const marker = t.id === active ? \"*\" : \" \";\n process.stdout.write(` ${marker} ${t.id.padEnd(24)} ${dim(t.label)}\\n`);\n }\n process.stdout.write(dim(`\\nSwitch with: cograph tenant use <id>\\n`));\n });\n });\n\ntenantCmd\n .command(\"use <id>\")\n .description(\"Set the active tenant (saved to ~/.cograph/config.json)\")\n .action((id: string) => {\n writeConfig({ tenant: id });\n process.stdout.write(`${bold(\"✓\")} Active tenant set to ${bold(id)}\\n`);\n process.stdout.write(dim(`Saved to ${configPathForDisplay()}\\n`));\n });\n\n// ---------------------------------------------------------------------------\n// ingest\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"ingest [file]\")\n .description(\"Ingest data from a file or --text\")\n .option(\"-t, --text <text>\", \"Inline text to ingest\")\n .option(\"--kg <name>\", \"Target knowledge graph name\")\n .option(\n \"-f, --format <fmt>\",\n \"Override format detection (text|csv|json)\",\n )\n .option(\n \"-y, --yes\",\n \"Skip the CSV schema review and apply the inferred mapping non-interactively\",\n )\n .action(\n async (\n file: string | undefined,\n opts: { text?: string; kg?: string; format?: string; yes?: boolean },\n ) => {\n await withErrors(async () => {\n const c = client();\n if (opts.text) {\n process.stdout.write(\n `Ingesting text (${opts.text.length.toLocaleString()} chars)...\\n`,\n );\n const result = await c.ingest(opts.text, {\n kg: opts.kg,\n contentType: opts.format ?? \"text\",\n });\n printIngestResult(result);\n return;\n }\n if (!file) {\n fail(\"Provide a file or --text\");\n }\n // For CSV, interpose the same schema review/confirm gate the Explorer\n // shows. Interactive on a TTY unless --yes; otherwise apply the\n // inferred mapping as-is (held type extensions auto-approved, matching\n // the prior non-interactive behavior). Hook is ignored for text/json.\n const interactive =\n Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY) && !opts.yes;\n const onSchemaInferred = interactive\n ? reviewMapping\n : (m: Mapping) =>\n Promise.resolve(\n buildMappingForIngest(\n m,\n new Set(heldTypes(m).map((t: any) => t.type_name)),\n ),\n );\n // ingest() handles file reading + format detection + CSV two-step flow.\n process.stdout.write(`Ingesting ${file}...\\n`);\n const result = await c.ingest(file, {\n kg: opts.kg,\n contentType: opts.format,\n onSchemaInferred,\n });\n if ((result as Record<string, unknown>).cancelled) {\n process.stdout.write(\"Cancelled — nothing was written.\\n\");\n return;\n }\n printIngestResult(result);\n });\n },\n );\n\nfunction printIngestResult(result: Record<string, unknown>): void {\n const num = (k: string) => Number(result[k] ?? 0);\n process.stdout.write(` Entities extracted: ${num(\"entities_extracted\")}\\n`);\n process.stdout.write(` Entities resolved: ${num(\"entities_resolved\")}\\n`);\n process.stdout.write(` Triples inserted: ${num(\"triples_inserted\")}\\n`);\n const types = result.types_created;\n if (Array.isArray(types) && types.length) {\n process.stdout.write(` Types created: ${types.join(\", \")}\\n`);\n }\n const rejections = result.rejections;\n if (Array.isArray(rejections) && rejections.length) {\n process.stdout.write(` Rejections: ${rejections.length}\\n`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// ask\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"ask <question>\")\n .description(\"Ask a natural language question\")\n .option(\"--kg <name>\", \"Knowledge graph to query\")\n .option(\"-d, --debug\", \"Show SPARQL and latency breakdown\")\n .option(\"-m, --model <model>\", \"Override query model\")\n .action(\n async (\n question: string,\n opts: { kg?: string; debug?: boolean; model?: string },\n ) => {\n await withErrors(async () => {\n if (opts.model) process.stdout.write(`Model: ${opts.model}\\n`);\n process.stdout.write(`Q: ${question}\\n`);\n process.stdout.write(\"Generating answer...\\n\");\n const t0 = Date.now();\n const result = await client().ask(question, {\n kg: opts.kg,\n model: opts.model,\n });\n const roundtripMs = Date.now() - t0;\n process.stdout.write(`\\nA: ${result.answer ?? \"No answer\"}\\n`);\n if (opts.debug) {\n process.stdout.write(`\\nSPARQL:\\n${result.sparql ?? \"\"}\\n`);\n const timing = (result.timing ?? {}) as Record<string, unknown>;\n if (Object.keys(timing).length) {\n process.stdout.write(`\\n${\"─\".repeat(40)}\\n`);\n process.stdout.write(\n `${\"Stage\".padEnd(25)} ${\"Time\".padStart(10)}\\n`,\n );\n process.stdout.write(`${\"─\".repeat(40)}\\n`);\n for (const [key, val] of Object.entries(timing)) {\n if (key === \"attempts\") {\n process.stdout.write(\n `${\"Attempts\".padEnd(25)} ${String(val).padStart(10)}\\n`,\n );\n } else if (typeof val === \"string\") {\n const label = key\n .replace(/_/g, \" \")\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n process.stdout.write(\n `${label.padEnd(25)} ${val.padStart(10)}\\n`,\n );\n } else {\n const label = key\n .replace(/_ms$/, \"\")\n .replace(/_/g, \" \")\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n const num = typeof val === \"number\" ? val : Number(val);\n process.stdout.write(\n `${label.padEnd(25)} ${num.toFixed(1).padStart(8)}ms\\n`,\n );\n }\n }\n process.stdout.write(`${\"─\".repeat(40)}\\n`);\n process.stdout.write(\n `${\"Client roundtrip\".padEnd(25)} ${roundtripMs.toFixed(1).padStart(8)}ms\\n`,\n );\n }\n }\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n// ontology\n// ---------------------------------------------------------------------------\n\nconst onto = program.command(\"ontology\").description(\"View ontology\");\n\nonto\n .command(\"types\")\n .description(\"List ontology types\")\n .action(async () => {\n await withErrors(async () => {\n const types = await client().ontologyTypes();\n if (!types.length) {\n process.stdout.write(\"No ontology types defined.\\n\");\n return;\n }\n for (const t of types) {\n const parent = t.parent_type\n ? ` (subClassOf ${t.parent_type})`\n : \"\";\n const desc = t.description ? ` — ${t.description}` : \"\";\n process.stdout.write(` ${t.name}${parent}${desc}\\n`);\n const attrs = (t.attributes ?? []) as Array<Record<string, unknown>>;\n for (const a of attrs) {\n process.stdout.write(\n ` .${a.name} (${a.datatype ?? \"string\"})\\n`,\n );\n }\n }\n });\n });\n\n// ---------------------------------------------------------------------------\n// er — entity resolution\n// ---------------------------------------------------------------------------\n\nconst er = program.command(\"er\").description(\"Entity resolution\");\n\ner.command(\"rebuild\")\n .description(\n \"Second pass: collapse intra-batch entity fragments in an ingested KG\",\n )\n .requiredOption(\"--kg <name>\", \"Knowledge graph to rebuild\")\n .action(async (opts: { kg: string }) => {\n await withErrors(async () => {\n process.stdout.write(`Rebuilding entity resolution for ${opts.kg}…\\n`);\n const report = await client().erRebuild(opts.kg);\n const types = (report.types ?? []) as Array<Record<string, unknown>>;\n for (const t of types) {\n const name = String(t.type ?? \"?\").padEnd(16, \" \");\n process.stdout.write(\n ` ${name} ${t.entities_before} → ${t.entities_after}` +\n ` (−${t.fragments_absorbed} fragments across ${t.clusters_merged} clusters)\\n`,\n );\n }\n process.stdout.write(\n `Done. ${report.fragments_absorbed_total ?? 0} fragments absorbed.\\n`,\n );\n });\n });\n\n// ---------------------------------------------------------------------------\n// enrich\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"enrich\")\n .description(\"Agentic enrichment — fill an attribute from web sources, with citations\")\n .requiredOption(\"--kg <name>\", \"Knowledge graph\")\n .requiredOption(\"--type <Type>\", \"Entity type to enrich\")\n .requiredOption(\"--attribute <attr>\", \"Attribute to fill (e.g. reviews, description)\")\n .option(\"--tier <tier>\", \"lite | base | core | pro (paid adapters live in core/pro)\", \"core\")\n .option(\"--limit <n>\", \"Max entities to enrich\", \"3\")\n .option(\"--apply\", \"Write results to the graph (with provenance), not just stage\")\n .action(\n async (opts: {\n kg: string;\n type: string;\n attribute: string;\n tier: string;\n limit: string;\n apply?: boolean;\n }) => {\n await withErrors(async () => {\n const c = client();\n process.stdout.write(\n `Enriching ${opts.type}.${opts.attribute} in ${opts.kg} (tier ${opts.tier})…\\n`,\n );\n const created = await c.enrichRun({\n kg_name: opts.kg,\n type_name: opts.type,\n attributes: [opts.attribute],\n tier: opts.tier as \"lite\" | \"base\" | \"core\" | \"pro\",\n limit: Number(opts.limit),\n conflict_policy: opts.apply ? \"overwrite\" : \"stage\",\n confidence_min: 0.1,\n });\n const terminal = [\"applied\", \"review\", \"failed\", \"cancelled\"];\n let job = await c.enrichJob(created.job_id);\n for (let i = 0; i < 40 && !terminal.includes(job.status); i++) {\n await new Promise((r) => setTimeout(r, 2000));\n job = await c.enrichJob(created.job_id);\n }\n const filled = (job.results ?? []).filter((r) => r.verdict);\n if (!filled.length) {\n process.stdout.write(\"No enrichment results (no source returned a value).\\n\");\n return;\n }\n for (const r of filled) {\n const v = r.verdict!;\n process.stdout.write(`\\n ${r.entity_uri.split(\"/\").pop()}\\n`);\n process.stdout.write(` ${r.attribute}: ${v.value}\\n`);\n process.stdout.write(\n ` source: ${v.source}${v.source_url ? \" \" + v.source_url : \"\"}\\n`,\n );\n if (v.reasoning) process.stdout.write(` ${v.reasoning}\\n`);\n }\n process.stdout.write(\n `\\n${opts.apply ? \"Applied to the graph (value + provenance triples).\" : \"Staged for review — re-run with --apply to write.\"}\\n`,\n );\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n// vis\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"vis <type>\")\n .description(\"Visualise a type — instance count, attribute coverage, top relations\")\n .option(\"--kg <name>\", \"Knowledge graph to inspect\")\n .action(async (typeName: string, opts: { kg?: string }) => {\n await withErrors(async () => {\n const c = client();\n\n // Resolve KG: use --kg flag, or pick first available KG.\n let kg = opts.kg;\n if (!kg) {\n const kgs = await c.listKgs();\n if (!kgs.length) {\n fail(\"No knowledge graphs found. Run 'cograph ingest' first.\");\n }\n kg = String(kgs[0].name ?? \"\");\n }\n\n let summary: import(\"./client.js\").TypeSummary;\n try {\n summary = await c.typeSummary(kg, typeName);\n } catch {\n fail(`Type '${typeName}' not found in KG '${kg}'.`);\n }\n\n const { entity_count, attributes, relationships, description, parent_type } = summary;\n const header = `${typeName}${parent_type ? ` (subClassOf ${parent_type})` : \"\"} — ${entity_count.toLocaleString()} instances`;\n process.stdout.write(`\\n${header}\\n${\"─\".repeat(header.length)}\\n`);\n if (description) process.stdout.write(`${description}\\n`);\n\n // Attributes table\n if (attributes.length) {\n process.stdout.write(`\\nAttributes (${attributes.length}):\\n`);\n const sorted = [...attributes].sort((a, b) => b.coverage_pct - a.coverage_pct);\n for (const a of sorted.slice(0, 10)) {\n const bar = \"█\".repeat(Math.round(a.coverage_pct / 10));\n const pct = `${a.coverage_pct}%`.padStart(6);\n process.stdout.write(` ${a.name.padEnd(24)} ${pct} ${bar}\\n`);\n }\n if (attributes.length > 10) {\n process.stdout.write(` … and ${attributes.length - 10} more\\n`);\n }\n }\n\n // Relations table\n if (relationships.length) {\n process.stdout.write(`\\nRelationships (${relationships.length}):\\n`);\n for (const r of relationships.slice(0, 8)) {\n const target = r.target_type ? ` → ${r.target_type}` : \"\";\n const pct = `${r.coverage_pct}%`.padStart(6);\n const avg = r.avg_degree ? ` (avg ${r.avg_degree})` : \"\";\n process.stdout.write(` ${(r.name + target).padEnd(36)} ${pct}${avg}\\n`);\n }\n }\n\n const explorerUrl = `https://cograph.cloud/dashboard/explore/${encodeURIComponent(typeName)}?kg=${encodeURIComponent(kg)}`;\n process.stdout.write(`\\n→ Open visually at ${explorerUrl}\\n`);\n process.stdout.write(\" (Sign in for interactive viz, search, and click-to-enrich.)\\n\\n\");\n });\n });\n\n// ---------------------------------------------------------------------------\n// clear\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"clear\")\n .description(\"Clear data\")\n .option(\"--kg <name>\", \"Clear a specific knowledge graph\")\n .option(\n \"--include-ontology\",\n \"Also clear the ontology (only meaningful when --kg is omitted)\",\n false,\n )\n .option(\"-y, --yes\", \"Skip confirmation\", false)\n .action(\n async (opts: { kg?: string; includeOntology?: boolean; yes?: boolean }) => {\n await withErrors(async () => {\n let msg: string;\n if (opts.kg) {\n msg = `Clear KG '${opts.kg}'?`;\n } else if (opts.includeOntology) {\n msg = \"Clear EVERYTHING including ontology?\";\n } else {\n msg = \"Clear all instance data (ontology preserved)?\";\n }\n\n if (!opts.yes) {\n const ok = await confirm(msg);\n if (!ok) {\n process.stdout.write(\"Cancelled.\\n\");\n return;\n }\n }\n\n const c = client();\n if (opts.kg) {\n await c.deleteKg(opts.kg);\n process.stdout.write(`Cleared KG: ${opts.kg}\\n`);\n return;\n }\n\n // Bulk-clear via /query + DELETE /triples — same loop the Python CLI uses.\n const tenant = c.tenant;\n const baseUrl = `${c.baseUrl}/graphs/${tenant}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (c.apiKey) headers[\"X-API-Key\"] = c.apiKey;\n\n const filters = opts.includeOntology\n ? \"\"\n : `FILTER(CONTAINS(STR(?s), '/entities/') || CONTAINS(STR(?s), '/onto/') || CONTAINS(STR(?s), '/kgs/'))`;\n const query = `SELECT ?s ?p ?o FROM <https://cograph.tech/graphs/${tenant}> WHERE { ?s ?p ?o . ${filters} } LIMIT 1000`;\n\n process.stdout.write(\"Clearing...\\n\");\n let deleted = 0;\n for (let i = 0; i < 50; i++) {\n const fetchRes = await fetch(`${baseUrl}/query`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ query }),\n });\n if (!fetchRes.ok) break;\n const data = (await fetchRes.json()) as {\n bindings?: Array<Record<string, unknown>>;\n };\n const bindings = data.bindings ?? [];\n if (!bindings.length) break;\n const triples = bindings\n .filter((b) => b.s)\n .map((b) => ({\n subject: b.s,\n predicate: b.p,\n object: b.o,\n }));\n for (let j = 0; j < triples.length; j += 100) {\n await fetch(`${baseUrl}/triples`, {\n method: \"DELETE\",\n headers,\n body: JSON.stringify({ triples: triples.slice(j, j + 100) }),\n });\n }\n deleted += triples.length;\n }\n process.stdout.write(`Deleted ${deleted} triples\\n`);\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n// login\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"login\")\n .description(\"Sign in via your browser and save an API key\")\n .action(async () => {\n const { runLogin } = await import(\"./login.js\");\n await runLogin();\n });\n\n// ---------------------------------------------------------------------------\n// shell\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"shell\")\n .description(\"Start an interactive REPL\")\n .option(\"--kg <name>\", \"Knowledge graph to use\")\n .option(\"--local\", \"Use http://localhost:8000 and skip login (self-hosted)\")\n .option(\"--no-login\", \"Skip browser login (assume open-access backend)\")\n .action(\n async (opts: { kg?: string; local?: boolean; login?: boolean }) => {\n // Parent program also accepts --local/--no-login (so `cograph --local`\n // works without a subcommand). When commander parses\n // `cograph shell --local`, the parent sees --local first and the\n // subcommand never gets it — so merge from program.opts() too.\n const parentOpts = program.opts() as {\n local?: boolean;\n login?: boolean;\n };\n const { runShell } = await import(\"./shell.js\");\n await runShell({\n kg: opts.kg,\n local: opts.local || parentOpts.local,\n noLogin: opts.login === false || parentOpts.login === false,\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n\nprogram.parseAsync(process.argv).catch((err) => {\n fail(`Error: ${err instanceof Error ? err.message : String(err)}`);\n});\n\n// silence unused import warning if ever needed\nvoid printJson;\n"],"mappings":";;;;;;;;;;;;AAAA,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AAQxB,SAAS,aAAqB;AAC5B,MAAI;AACF,UAAM,OAAO,QAAQ,cAAc,YAAY,GAAG,CAAC;AACnD,UAAM,MAAM,KAAK,MAAM,aAAa,KAAK,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC;AAC9E,WAAO,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU;AAAA,EACzD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,SAAiB;AAIxB,QAAM,IAAI,QAAQ,KAAK;AACvB,SAAO,IAAI,OAAO;AAAA,IAChB,GAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,IAAI,CAAC;AAAA,IACvC,GAAI,EAAE,QAAQ,EAAE,SAAS,wBAAwB,IAAI,CAAC;AAAA,EACxD,CAAC;AACH;AAMA,SAAS,KAAK,KAAa,OAAO,GAAU;AAC1C,UAAQ,OAAO,MAAM,IAAI,SAAS,IAAI,IAAI,MAAM,MAAM,IAAI;AAC1D,UAAQ,KAAK,IAAI;AACnB;AAEA,eAAe,WAAc,IAAyC;AACpE,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,SAAS,KAAK;AACZ,QAAI,eAAe,cAAc;AAC/B,WAAK,UAAU,IAAI,OAAO,EAAE;AAAA,IAC9B;AACA,SAAK,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,EACnE;AACF;AAEA,eAAe,QAAQ,QAAkC;AACvD,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,OAAG,SAAS,GAAG,MAAM,WAAW,CAAC,QAAQ;AACvC,SAAG,MAAM;AACT,cAAQ,IAAI,KAAK,EAAE,YAAY,MAAM,GAAG;AAAA,IAC1C,CAAC;AAAA,EACH,CAAC;AACH;AAGA,eAAe,WAAW,QAAkC;AAC1D,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,OAAG,SAAS,GAAG,MAAM,WAAW,CAAC,QAAQ;AACvC,SAAG,MAAM;AACT,YAAM,IAAI,IAAI,KAAK,EAAE,YAAY;AACjC,cAAQ,MAAM,MAAM,MAAM,OAAO,MAAM,KAAK;AAAA,IAC9C,CAAC;AAAA,EACH,CAAC;AACH;AASA,IAAM,WAAW,QAAQ,QAAQ,OAAO,KAAK,KAAK,CAAC,QAAQ,IAAI;AAC/D,IAAM,MAAM,CAAC,SAAiB,CAAC,MAC7B,WAAW,QAAQ,IAAI,IAAI,CAAC,YAAY;AAC1C,IAAM,OAAO,IAAI,GAAG;AACpB,IAAM,MAAM,IAAI,GAAG;AAcnB,SAAS,YAAY,GAA0B;AAC7C,MAAI,MAAM,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,SAAS,GAAG;AACtD,WAAO,EAAE,SAAS,IAAI,CAAC,OAAY;AAAA,MACjC,MAAM,EAAE;AAAA,MACR,WAAW,EAAE;AAAA,MACb,WAAW,EAAE;AAAA,MACb,SAAS,EAAE;AAAA,MACX,cAAc,EAAE,gBAAgB;AAAA,MAChC,YAAY,EAAE;AAAA,MACd,KAAK,EAAE;AAAA,IACT,EAAE;AAAA,EACJ;AACA,SAAO;AAAA,IACL;AAAA,MACE,MAAM,EAAE;AAAA,MACR,WAAW,EAAE;AAAA,MACb,cAAc,EAAE,gBAAgB;AAAA,MAChC,YAAY,EAAE;AAAA,MACd,KAAK,EAAE;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,UAAU,GAAmB;AACpC,QAAM,QAAQ,EAAE,qBAAqB;AACrC,SAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,CAAC,MAAW,EAAE,eAAe,IAAI,CAAC;AAC/E;AAKA,SAAS,sBAAsB,GAAY,UAAgC;AACzE,QAAM,MAAe,EAAE,aAAa,EAAE,aAAa,SAAS,EAAE,QAAQ;AACtE,MAAI,EAAE,SAAU,KAAI,WAAW,EAAE;AACjC,MAAI,EAAE,cAAe,KAAI,gBAAgB,EAAE;AAC3C,QAAM,QAAQ,EAAE,qBAAqB;AACrC,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,QAAI,sBAAsB;AAAA,MACxB,OAAO,MAAM;AAAA,QACX,CAAC,MAAW,CAAC,EAAE,mBAAmB,SAAS,IAAI,EAAE,SAAS;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,GAAgB;AAC/B,MAAI,KAAK,KAAM,QAAO;AACtB,QAAM,IAAI,OAAO,CAAC;AAClB,MAAI,OAAO,MAAM,CAAC,EAAG,QAAO;AAC5B,SAAO,IAAI,KAAK,EAAE,QAAQ,CAAC,CAAC,GAAG,IAAI,MAAM,OAAO,EAAE,GAAG;AACvD;AAEA,SAAS,cACP,GACA,MACM;AACN,QAAM,IAAI,CAAC,MAAc,QAAQ,OAAO,MAAM,CAAC;AAC/C;AAAA,IACE,OACE,KAAK,iBAAiB,IACtB;AAAA,MACE,eAAe,KAAK,aAAa,eAAe,CAAC,OAAO,KAAK,UAAU,eAAe,CAAC;AAAA,IACzF,IACA;AAAA,EACJ;AACA,IAAE,IAAI,oEAAoE,IAAI,MAAM;AAEpF,QAAM,OAAO,YAAY,CAAC;AAC1B,QAAM,QAAQ,MAAM,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,SAAS;AAC/D,IAAE,KAAK,iBAAiB,IAAI,IAAI;AAChC,aAAW,KAAK,MAAM;AACpB,UAAM,MAAM,EAAE,YACV,QAAQ,EAAE,SAAS,KACnB,EAAE,WAAW,EAAE,QAAQ,SACrB,QAAQ,EAAE,QAAQ,KAAK,KAAK,CAAC,KAC7B,EAAE,iBAAiB,cACjB,qBACA;AACR,MAAE,YAAO,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,EAAE,UAAU,CAAC;AAAA,CAAI;AACnE,QAAI,EAAE,IAAK,GAAE,SAAS,IAAI,EAAE,GAAG,CAAC;AAAA,CAAI;AACpC,UAAM,QAAQ,EAAE,WAAW,CAAC,GAAG;AAAA,MAAO,CAAC,QACrC,QAAQ,IAAI,WAAW,EAAE,OAAO;AAAA,IAClC;AACA,eAAW,OAAO,MAAM;AACtB,YAAM,OACJ,IAAI,SAAS,YACT,SACA,IAAI,SAAS,iBACX,SACA;AACR,UAAI,SAAS;AACb,UAAI,IAAI,SAAS,kBAAkB,IAAI;AACrC,iBAAS,WAAM,IAAI,WAAW;AAAA,eAE9B,IAAI,SAAS,eACb,IAAI,kBACJ,IAAI,mBAAmB,IAAI;AAE3B,iBAAS,OAAO,IAAI,cAAc;AACpC,YAAM,KACJ,IAAI,YAAY,IAAI,aAAa,WAC7B,MAAM,IAAI,IAAI,IAAI,QAAQ,GAAG,IAC7B;AACN;AAAA,QACE,SAAS,IAAI,MAAM,OAAO,GAAG,CAAC,IAAI,IAAI,WAAW,GAAG,MAAM,GAAG,EAAE,GAAG,QAAQ,IAAI,UAAU,CAAC;AAAA;AAAA,MAC3F;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO,EAAE,iBAAiB,CAAC;AACjC,MAAI,KAAK,QAAQ;AACf,MAAE,OAAO,KAAK,OAAO,IAAI,IAAI;AAC7B,eAAW,KAAK;AACd,QAAE,YAAO,EAAE,OAAO,IAAI,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,UAAU,CAAC;AAAA,CAAI;AAAA,EAClF;AAEA,QAAM,MAAM,EAAE,cAAc,CAAC;AAC7B,MAAI,IAAI,QAAQ;AACd;AAAA,MACE,OACE;AAAA,QACE,yBAAyB,IAAI,MAAM,SAAS,IAAI,WAAW,IAAI,KAAK,GAAG,KAAK,IACzE,IAAI,CAAC,MAAW,EAAE,QAAQ,EAC1B,KAAK,IAAI,CAAC;AAAA,MACf,IACA;AAAA,IACJ;AAAA,EACF;AACF;AAIA,eAAe,cACb,GACA,MACyB;AACzB,gBAAc,GAAG,IAAI;AACrB,QAAM,WAAW,oBAAI,IAAY;AACjC,QAAM,OAAO,UAAU,CAAC;AACxB,MAAI,KAAK,QAAQ;AACf,YAAQ,OAAO;AAAA,MACb,OACE,KAAK,GAAG,KAAK,MAAM,YAAY,KAAK,WAAW,IAAI,KAAK,GAAG,kBAAkB,IAC7E,IAAI,uDAAkD,IACtD;AAAA,IACJ;AACA,eAAW,KAAK,MAAM;AACpB,YAAM,OAAO,EAAE,0BACX,IAAI,WAAW,EAAE,uBAAuB,IAAI,IAC5C;AACJ,cAAQ,OAAO,MAAM,YAAO,EAAE,SAAS,GAAG,IAAI,GAAG,QAAQ,EAAE,UAAU,CAAC;AAAA,CAAI;AAC1E,UAAI,MAAM,QAAQ,gBAAgB,EAAE,SAAS,IAAI,EAAG,UAAS,IAAI,EAAE,SAAS;AAAA,IAC9E;AAAA,EACF;AACA,UAAQ,OAAO,MAAM,IAAI;AACzB,QAAM,KAAK,MAAM;AAAA,IACf,iCAAiC,KAAK,UAAU,eAAe,CAAC;AAAA,EAClE;AACA,MAAI,CAAC,GAAI,QAAO;AAChB,SAAO,sBAAsB,GAAG,QAAQ;AAC1C;AAEA,IAAM,UAAU,IAAI,QAAQ;AAC5B,QACG,KAAK,SAAS,EACd,YAAY,6BAA6B,EACzC,QAAQ,WAAW,CAAC,EAKpB,OAAO,WAAW,wDAAwD,EAC1E,OAAO,cAAc,iDAAiD,EACtE;AAAA,EACC;AAAA,EACA;AACF,EACC,OAAO,OAAO,SAA+C;AAC5D,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,qBAAY;AAC9C,QAAM,SAAS;AAAA,IACb,OAAO,KAAK;AAAA;AAAA,IAEZ,SAAS,KAAK,UAAU;AAAA,EAC1B,CAAC;AACH,CAAC;AAMH,IAAM,KAAK,QAAQ,QAAQ,IAAI,EAAE,YAAY,yBAAyB;AAEtE,GAAG,QAAQ,MAAM,EACd,YAAY,uBAAuB,EACnC,OAAO,YAAY;AAClB,QAAM,WAAW,YAAY;AAC3B,UAAM,MAAM,MAAM,OAAO,EAAE,QAAQ;AACnC,QAAI,CAAC,IAAI,QAAQ;AACf,cAAQ,OAAO;AAAA,QACb;AAAA,MACF;AACA;AAAA,IACF;AACA,eAAW,KAAK,KAAK;AACnB,YAAM,OAAO,OAAO,EAAE,QAAQ,GAAG;AACjC,YAAM,UAAU,OAAO,EAAE,gBAAgB,CAAC;AAC1C,YAAM,OAAO,EAAE,cAAc,WAAM,EAAE,WAAW,KAAK;AACrD,YAAM,UAAU,KAAK,OAAO,IAAI,GAAG;AACnC,YAAM,aAAa,OAAO,OAAO,EAAE,SAAS,GAAG,GAAG;AAClD,cAAQ,OAAO,MAAM,KAAK,OAAO,IAAI,UAAU,WAAW,IAAI;AAAA,CAAI;AAAA,IACpE;AAAA,EACF,CAAC;AACH,CAAC;AAEH,GAAG,QAAQ,eAAe,EACvB,YAAY,0BAA0B,EACtC,OAAO,4BAA4B,aAAa,EAChD,OAAO,OAAO,MAAc,SAAmC;AAC9D,QAAM,WAAW,YAAY;AAC3B,UAAM,UAAU,MAAM,OAAO,EAAE,SAAS,MAAM,KAAK,WAAW;AAC9D,YAAQ,OAAO,MAAM,4BAA4B,QAAQ,QAAQ,IAAI;AAAA,CAAI;AAAA,EAC3E,CAAC;AACH,CAAC;AAEH,GAAG,QAAQ,eAAe,EACvB,YAAY,0BAA0B,EACtC,OAAO,OAAO,SAAiB;AAC9B,QAAM,WAAW,YAAY;AAC3B,UAAM,OAAO,EAAE,SAAS,IAAI;AAC5B,YAAQ,OAAO,MAAM,4BAA4B,IAAI;AAAA,CAAI;AAAA,EAC3D,CAAC;AACH,CAAC;AAMH,IAAM,YAAY,QACf,QAAQ,QAAQ,EAChB,YAAY,kCAAkC;AAEjD,UACG,QAAQ,WAAW,EAAE,WAAW,KAAK,CAAC,EACtC,YAAY,wBAAwB,EACpC,OAAO,MAAM;AACZ,QAAM,SAAS,OAAO,EAAE;AACxB,QAAM,QAAQ,WAAW,EAAE;AAC3B,UAAQ,OAAO,MAAM,kBAAkB,KAAK,MAAM,CAAC;AAAA,CAAI;AACvD,UAAQ,OAAO;AAAA,IACb,QACI,IAAI,sBAAsB,qBAAqB,CAAC;AAAA,CAAI,IACpD,IAAI;AAAA,CAAgE;AAAA,EAC1E;AACF,CAAC;AAEH,UACG,QAAQ,MAAM,EACd,YAAY,iCAAiC,EAC7C,OAAO,YAAY;AAClB,QAAM,WAAW,YAAY;AAC3B,UAAM,IAAI,OAAO;AACjB,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,EAAE,YAAY;AAAA,IAChC,SAAS,KAAK;AACZ,UAAI,eAAe,gBAAgB,IAAI,WAAW,KAAK;AACrD;AAAA,UACE;AAAA,QACF;AAAA,MACF;AACA,YAAM;AAAA,IACR;AACA,QAAI,CAAC,QAAQ,QAAQ;AACnB,cAAQ,OAAO,MAAM,sCAAsC;AAC3D;AAAA,IACF;AACA,UAAM,SAAS,EAAE;AACjB,eAAW,KAAK,SAAS;AACvB,YAAM,SAAS,EAAE,OAAO,SAAS,MAAM;AACvC,cAAQ,OAAO,MAAM,KAAK,MAAM,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC,IAAI,IAAI,EAAE,KAAK,CAAC;AAAA,CAAI;AAAA,IACzE;AACA,YAAQ,OAAO,MAAM,IAAI;AAAA;AAAA,CAA0C,CAAC;AAAA,EACtE,CAAC;AACH,CAAC;AAEH,UACG,QAAQ,UAAU,EAClB,YAAY,yDAAyD,EACrE,OAAO,CAAC,OAAe;AACtB,cAAY,EAAE,QAAQ,GAAG,CAAC;AAC1B,UAAQ,OAAO,MAAM,GAAG,KAAK,QAAG,CAAC,yBAAyB,KAAK,EAAE,CAAC;AAAA,CAAI;AACtE,UAAQ,OAAO,MAAM,IAAI,YAAY,qBAAqB,CAAC;AAAA,CAAI,CAAC;AAClE,CAAC;AAMH,QACG,QAAQ,eAAe,EACvB,YAAY,mCAAmC,EAC/C,OAAO,qBAAqB,uBAAuB,EACnD,OAAO,eAAe,6BAA6B,EACnD;AAAA,EACC;AAAA,EACA;AACF,EACC;AAAA,EACC;AAAA,EACA;AACF,EACC;AAAA,EACC,OACE,MACA,SACG;AACH,UAAM,WAAW,YAAY;AAC3B,YAAM,IAAI,OAAO;AACjB,UAAI,KAAK,MAAM;AACb,gBAAQ,OAAO;AAAA,UACb,mBAAmB,KAAK,KAAK,OAAO,eAAe,CAAC;AAAA;AAAA,QACtD;AACA,cAAMA,UAAS,MAAM,EAAE,OAAO,KAAK,MAAM;AAAA,UACvC,IAAI,KAAK;AAAA,UACT,aAAa,KAAK,UAAU;AAAA,QAC9B,CAAC;AACD,0BAAkBA,OAAM;AACxB;AAAA,MACF;AACA,UAAI,CAAC,MAAM;AACT,aAAK,0BAA0B;AAAA,MACjC;AAKA,YAAM,cACJ,QAAQ,QAAQ,MAAM,KAAK,KAAK,QAAQ,QAAQ,OAAO,KAAK,KAAK,CAAC,KAAK;AACzE,YAAM,mBAAmB,cACrB,gBACA,CAAC,MACC,QAAQ;AAAA,QACN;AAAA,UACE;AAAA,UACA,IAAI,IAAI,UAAU,CAAC,EAAE,IAAI,CAAC,MAAW,EAAE,SAAS,CAAC;AAAA,QACnD;AAAA,MACF;AAEN,cAAQ,OAAO,MAAM,aAAa,IAAI;AAAA,CAAO;AAC7C,YAAM,SAAS,MAAM,EAAE,OAAO,MAAM;AAAA,QAClC,IAAI,KAAK;AAAA,QACT,aAAa,KAAK;AAAA,QAClB;AAAA,MACF,CAAC;AACD,UAAK,OAAmC,WAAW;AACjD,gBAAQ,OAAO,MAAM,yCAAoC;AACzD;AAAA,MACF;AACA,wBAAkB,MAAM;AAAA,IAC1B,CAAC;AAAA,EACH;AACF;AAEF,SAAS,kBAAkB,QAAuC;AAChE,QAAM,MAAM,CAAC,MAAc,OAAO,OAAO,CAAC,KAAK,CAAC;AAChD,UAAQ,OAAO,MAAM,yBAAyB,IAAI,oBAAoB,CAAC;AAAA,CAAI;AAC3E,UAAQ,OAAO,MAAM,yBAAyB,IAAI,mBAAmB,CAAC;AAAA,CAAI;AAC1E,UAAQ,OAAO,MAAM,yBAAyB,IAAI,kBAAkB,CAAC;AAAA,CAAI;AACzE,QAAM,QAAQ,OAAO;AACrB,MAAI,MAAM,QAAQ,KAAK,KAAK,MAAM,QAAQ;AACxC,YAAQ,OAAO,MAAM,yBAAyB,MAAM,KAAK,IAAI,CAAC;AAAA,CAAI;AAAA,EACpE;AACA,QAAM,aAAa,OAAO;AAC1B,MAAI,MAAM,QAAQ,UAAU,KAAK,WAAW,QAAQ;AAClD,YAAQ,OAAO,MAAM,yBAAyB,WAAW,MAAM;AAAA,CAAI;AAAA,EACrE;AACF;AAMA,QACG,QAAQ,gBAAgB,EACxB,YAAY,iCAAiC,EAC7C,OAAO,eAAe,0BAA0B,EAChD,OAAO,eAAe,mCAAmC,EACzD,OAAO,uBAAuB,sBAAsB,EACpD;AAAA,EACC,OACE,UACA,SACG;AACH,UAAM,WAAW,YAAY;AAC3B,UAAI,KAAK,MAAO,SAAQ,OAAO,MAAM,UAAU,KAAK,KAAK;AAAA,CAAI;AAC7D,cAAQ,OAAO,MAAM,MAAM,QAAQ;AAAA,CAAI;AACvC,cAAQ,OAAO,MAAM,wBAAwB;AAC7C,YAAM,KAAK,KAAK,IAAI;AACpB,YAAM,SAAS,MAAM,OAAO,EAAE,IAAI,UAAU;AAAA,QAC1C,IAAI,KAAK;AAAA,QACT,OAAO,KAAK;AAAA,MACd,CAAC;AACD,YAAM,cAAc,KAAK,IAAI,IAAI;AACjC,cAAQ,OAAO,MAAM;AAAA,KAAQ,OAAO,UAAU,WAAW;AAAA,CAAI;AAC7D,UAAI,KAAK,OAAO;AACd,gBAAQ,OAAO,MAAM;AAAA;AAAA,EAAc,OAAO,UAAU,EAAE;AAAA,CAAI;AAC1D,cAAM,SAAU,OAAO,UAAU,CAAC;AAClC,YAAI,OAAO,KAAK,MAAM,EAAE,QAAQ;AAC9B,kBAAQ,OAAO,MAAM;AAAA,EAAK,SAAI,OAAO,EAAE,CAAC;AAAA,CAAI;AAC5C,kBAAQ,OAAO;AAAA,YACb,GAAG,QAAQ,OAAO,EAAE,CAAC,IAAI,OAAO,SAAS,EAAE,CAAC;AAAA;AAAA,UAC9C;AACA,kBAAQ,OAAO,MAAM,GAAG,SAAI,OAAO,EAAE,CAAC;AAAA,CAAI;AAC1C,qBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC/C,gBAAI,QAAQ,YAAY;AACtB,sBAAQ,OAAO;AAAA,gBACb,GAAG,WAAW,OAAO,EAAE,CAAC,IAAI,OAAO,GAAG,EAAE,SAAS,EAAE,CAAC;AAAA;AAAA,cACtD;AAAA,YACF,WAAW,OAAO,QAAQ,UAAU;AAClC,oBAAM,QAAQ,IACX,QAAQ,MAAM,GAAG,EACjB,QAAQ,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC;AAC1C,sBAAQ,OAAO;AAAA,gBACb,GAAG,MAAM,OAAO,EAAE,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC;AAAA;AAAA,cACzC;AAAA,YACF,OAAO;AACL,oBAAM,QAAQ,IACX,QAAQ,QAAQ,EAAE,EAClB,QAAQ,MAAM,GAAG,EACjB,QAAQ,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC;AAC1C,oBAAM,MAAM,OAAO,QAAQ,WAAW,MAAM,OAAO,GAAG;AACtD,sBAAQ,OAAO;AAAA,gBACb,GAAG,MAAM,OAAO,EAAE,CAAC,IAAI,IAAI,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC;AAAA;AAAA,cACnD;AAAA,YACF;AAAA,UACF;AACA,kBAAQ,OAAO,MAAM,GAAG,SAAI,OAAO,EAAE,CAAC;AAAA,CAAI;AAC1C,kBAAQ,OAAO;AAAA,YACb,GAAG,mBAAmB,OAAO,EAAE,CAAC,IAAI,YAAY,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC;AAAA;AAAA,UACxE;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAMF,IAAM,OAAO,QAAQ,QAAQ,UAAU,EAAE,YAAY,eAAe;AAEpE,KACG,QAAQ,OAAO,EACf,YAAY,qBAAqB,EACjC,OAAO,YAAY;AAClB,QAAM,WAAW,YAAY;AAC3B,UAAM,QAAQ,MAAM,OAAO,EAAE,cAAc;AAC3C,QAAI,CAAC,MAAM,QAAQ;AACjB,cAAQ,OAAO,MAAM,8BAA8B;AACnD;AAAA,IACF;AACA,eAAW,KAAK,OAAO;AACrB,YAAM,SAAS,EAAE,cACb,gBAAgB,EAAE,WAAW,MAC7B;AACJ,YAAM,OAAO,EAAE,cAAc,WAAM,EAAE,WAAW,KAAK;AACrD,cAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI;AAAA,CAAI;AACpD,YAAM,QAAS,EAAE,cAAc,CAAC;AAChC,iBAAW,KAAK,OAAO;AACrB,gBAAQ,OAAO;AAAA,UACb,QAAQ,EAAE,IAAI,KAAK,EAAE,YAAY,QAAQ;AAAA;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH,CAAC;AAMH,IAAM,KAAK,QAAQ,QAAQ,IAAI,EAAE,YAAY,mBAAmB;AAEhE,GAAG,QAAQ,SAAS,EACjB;AAAA,EACC;AACF,EACC,eAAe,eAAe,4BAA4B,EAC1D,OAAO,OAAO,SAAyB;AACtC,QAAM,WAAW,YAAY;AAC3B,YAAQ,OAAO,MAAM,oCAAoC,KAAK,EAAE;AAAA,CAAK;AACrE,UAAM,SAAS,MAAM,OAAO,EAAE,UAAU,KAAK,EAAE;AAC/C,UAAM,QAAS,OAAO,SAAS,CAAC;AAChC,eAAW,KAAK,OAAO;AACrB,YAAM,OAAO,OAAO,EAAE,QAAQ,GAAG,EAAE,OAAO,IAAI,GAAG;AACjD,cAAQ,OAAO;AAAA,QACb,KAAK,IAAI,IAAI,EAAE,eAAe,WAAM,EAAE,cAAc,YAC3C,EAAE,kBAAkB,qBAAqB,EAAE,eAAe;AAAA;AAAA,MACrE;AAAA,IACF;AACA,YAAQ,OAAO;AAAA,MACb,SAAS,OAAO,4BAA4B,CAAC;AAAA;AAAA,IAC/C;AAAA,EACF,CAAC;AACH,CAAC;AAMH,QACG,QAAQ,QAAQ,EAChB,YAAY,8EAAyE,EACrF,eAAe,eAAe,iBAAiB,EAC/C,eAAe,iBAAiB,uBAAuB,EACvD,eAAe,sBAAsB,+CAA+C,EACpF,OAAO,iBAAiB,6DAA6D,MAAM,EAC3F,OAAO,eAAe,0BAA0B,GAAG,EACnD,OAAO,WAAW,8DAA8D,EAChF;AAAA,EACC,OAAO,SAOD;AACJ,UAAM,WAAW,YAAY;AAC3B,YAAM,IAAI,OAAO;AACjB,cAAQ,OAAO;AAAA,QACb,aAAa,KAAK,IAAI,IAAI,KAAK,SAAS,OAAO,KAAK,EAAE,UAAU,KAAK,IAAI;AAAA;AAAA,MAC3E;AACA,YAAM,UAAU,MAAM,EAAE,UAAU;AAAA,QAChC,SAAS,KAAK;AAAA,QACd,WAAW,KAAK;AAAA,QAChB,YAAY,CAAC,KAAK,SAAS;AAAA,QAC3B,MAAM,KAAK;AAAA,QACX,OAAO,OAAO,KAAK,KAAK;AAAA,QACxB,iBAAiB,KAAK,QAAQ,cAAc;AAAA,QAC5C,gBAAgB;AAAA,MAClB,CAAC;AACD,YAAM,WAAW,CAAC,WAAW,UAAU,UAAU,WAAW;AAC5D,UAAI,MAAM,MAAM,EAAE,UAAU,QAAQ,MAAM;AAC1C,eAAS,IAAI,GAAG,IAAI,MAAM,CAAC,SAAS,SAAS,IAAI,MAAM,GAAG,KAAK;AAC7D,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAI,CAAC;AAC5C,cAAM,MAAM,EAAE,UAAU,QAAQ,MAAM;AAAA,MACxC;AACA,YAAM,UAAU,IAAI,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO;AAC1D,UAAI,CAAC,OAAO,QAAQ;AAClB,gBAAQ,OAAO,MAAM,uDAAuD;AAC5E;AAAA,MACF;AACA,iBAAW,KAAK,QAAQ;AACtB,cAAM,IAAI,EAAE;AACZ,gBAAQ,OAAO,MAAM;AAAA,IAAO,EAAE,WAAW,MAAM,GAAG,EAAE,IAAI,CAAC;AAAA,CAAI;AAC7D,gBAAQ,OAAO,MAAM,OAAO,EAAE,SAAS,KAAK,EAAE,KAAK;AAAA,CAAI;AACvD,gBAAQ,OAAO;AAAA,UACb,eAAe,EAAE,MAAM,GAAG,EAAE,aAAa,OAAO,EAAE,aAAa,EAAE;AAAA;AAAA,QACnE;AACA,YAAI,EAAE,UAAW,SAAQ,OAAO,MAAM,OAAO,EAAE,SAAS;AAAA,CAAI;AAAA,MAC9D;AACA,cAAQ,OAAO;AAAA,QACb;AAAA,EAAK,KAAK,QAAQ,uDAAuD,wDAAmD;AAAA;AAAA,MAC9H;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAMF,QACG,QAAQ,YAAY,EACpB,YAAY,2EAAsE,EAClF,OAAO,eAAe,4BAA4B,EAClD,OAAO,OAAO,UAAkB,SAA0B;AACzD,QAAM,WAAW,YAAY;AAC3B,UAAM,IAAI,OAAO;AAGjB,QAAIC,MAAK,KAAK;AACd,QAAI,CAACA,KAAI;AACP,YAAM,MAAM,MAAM,EAAE,QAAQ;AAC5B,UAAI,CAAC,IAAI,QAAQ;AACf,aAAK,wDAAwD;AAAA,MAC/D;AACA,MAAAA,MAAK,OAAO,IAAI,CAAC,EAAE,QAAQ,EAAE;AAAA,IAC/B;AAEA,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,EAAE,YAAYA,KAAI,QAAQ;AAAA,IAC5C,QAAQ;AACN,WAAK,SAAS,QAAQ,sBAAsBA,GAAE,IAAI;AAAA,IACpD;AAEA,UAAM,EAAE,cAAc,YAAY,eAAe,aAAa,YAAY,IAAI;AAC9E,UAAM,SAAS,GAAG,QAAQ,GAAG,cAAc,gBAAgB,WAAW,MAAM,EAAE,WAAM,aAAa,eAAe,CAAC;AACjH,YAAQ,OAAO,MAAM;AAAA,EAAK,MAAM;AAAA,EAAK,SAAI,OAAO,OAAO,MAAM,CAAC;AAAA,CAAI;AAClE,QAAI,YAAa,SAAQ,OAAO,MAAM,GAAG,WAAW;AAAA,CAAI;AAGxD,QAAI,WAAW,QAAQ;AACrB,cAAQ,OAAO,MAAM;AAAA,cAAiB,WAAW,MAAM;AAAA,CAAM;AAC7D,YAAM,SAAS,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,eAAe,EAAE,YAAY;AAC7E,iBAAW,KAAK,OAAO,MAAM,GAAG,EAAE,GAAG;AACnC,cAAM,MAAM,SAAI,OAAO,KAAK,MAAM,EAAE,eAAe,EAAE,CAAC;AACtD,cAAM,MAAM,GAAG,EAAE,YAAY,IAAI,SAAS,CAAC;AAC3C,gBAAQ,OAAO,MAAM,KAAK,EAAE,KAAK,OAAO,EAAE,CAAC,IAAI,GAAG,KAAK,GAAG;AAAA,CAAI;AAAA,MAChE;AACA,UAAI,WAAW,SAAS,IAAI;AAC1B,gBAAQ,OAAO,MAAM,gBAAW,WAAW,SAAS,EAAE;AAAA,CAAS;AAAA,MACjE;AAAA,IACF;AAGA,QAAI,cAAc,QAAQ;AACxB,cAAQ,OAAO,MAAM;AAAA,iBAAoB,cAAc,MAAM;AAAA,CAAM;AACnE,iBAAW,KAAK,cAAc,MAAM,GAAG,CAAC,GAAG;AACzC,cAAM,SAAS,EAAE,cAAc,WAAM,EAAE,WAAW,KAAK;AACvD,cAAM,MAAM,GAAG,EAAE,YAAY,IAAI,SAAS,CAAC;AAC3C,cAAM,MAAM,EAAE,aAAa,SAAS,EAAE,UAAU,MAAM;AACtD,gBAAQ,OAAO,MAAM,MAAM,EAAE,OAAO,QAAQ,OAAO,EAAE,CAAC,IAAI,GAAG,GAAG,GAAG;AAAA,CAAI;AAAA,MACzE;AAAA,IACF;AAEA,UAAM,cAAc,2CAA2C,mBAAmB,QAAQ,CAAC,OAAO,mBAAmBA,GAAE,CAAC;AACxH,YAAQ,OAAO,MAAM;AAAA,0BAAwB,WAAW;AAAA,CAAI;AAC5D,YAAQ,OAAO,MAAM,mEAAmE;AAAA,EAC1F,CAAC;AACH,CAAC;AAMH,QACG,QAAQ,OAAO,EACf,YAAY,YAAY,EACxB,OAAO,eAAe,kCAAkC,EACxD;AAAA,EACC;AAAA,EACA;AAAA,EACA;AACF,EACC,OAAO,aAAa,qBAAqB,KAAK,EAC9C;AAAA,EACC,OAAO,SAAoE;AACzE,UAAM,WAAW,YAAY;AAC3B,UAAI;AACJ,UAAI,KAAK,IAAI;AACX,cAAM,aAAa,KAAK,EAAE;AAAA,MAC5B,WAAW,KAAK,iBAAiB;AAC/B,cAAM;AAAA,MACR,OAAO;AACL,cAAM;AAAA,MACR;AAEA,UAAI,CAAC,KAAK,KAAK;AACb,cAAM,KAAK,MAAM,QAAQ,GAAG;AAC5B,YAAI,CAAC,IAAI;AACP,kBAAQ,OAAO,MAAM,cAAc;AACnC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,IAAI,OAAO;AACjB,UAAI,KAAK,IAAI;AACX,cAAM,EAAE,SAAS,KAAK,EAAE;AACxB,gBAAQ,OAAO,MAAM,eAAe,KAAK,EAAE;AAAA,CAAI;AAC/C;AAAA,MACF;AAGA,YAAM,SAAS,EAAE;AACjB,YAAM,UAAU,GAAG,EAAE,OAAO,WAAW,MAAM;AAC7C,YAAM,UAAkC;AAAA,QACtC,gBAAgB;AAAA,MAClB;AACA,UAAI,EAAE,OAAQ,SAAQ,WAAW,IAAI,EAAE;AAEvC,YAAM,UAAU,KAAK,kBACjB,KACA;AACJ,YAAM,QAAQ,qDAAqD,MAAM,wBAAwB,OAAO;AAExG,cAAQ,OAAO,MAAM,eAAe;AACpC,UAAI,UAAU;AACd,eAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,cAAM,WAAW,MAAM,MAAM,GAAG,OAAO,UAAU;AAAA,UAC/C,QAAQ;AAAA,UACR;AAAA,UACA,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;AAAA,QAChC,CAAC;AACD,YAAI,CAAC,SAAS,GAAI;AAClB,cAAM,OAAQ,MAAM,SAAS,KAAK;AAGlC,cAAM,WAAW,KAAK,YAAY,CAAC;AACnC,YAAI,CAAC,SAAS,OAAQ;AACtB,cAAM,UAAU,SACb,OAAO,CAAC,MAAM,EAAE,CAAC,EACjB,IAAI,CAAC,OAAO;AAAA,UACX,SAAS,EAAE;AAAA,UACX,WAAW,EAAE;AAAA,UACb,QAAQ,EAAE;AAAA,QACZ,EAAE;AACJ,iBAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,KAAK;AAC5C,gBAAM,MAAM,GAAG,OAAO,YAAY;AAAA,YAChC,QAAQ;AAAA,YACR;AAAA,YACA,MAAM,KAAK,UAAU,EAAE,SAAS,QAAQ,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA,UAC7D,CAAC;AAAA,QACH;AACA,mBAAW,QAAQ;AAAA,MACrB;AACA,cAAQ,OAAO,MAAM,WAAW,OAAO;AAAA,CAAY;AAAA,IACrD,CAAC;AAAA,EACH;AACF;AAMF,QACG,QAAQ,OAAO,EACf,YAAY,8CAA8C,EAC1D,OAAO,YAAY;AAClB,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,qBAAY;AAC9C,QAAM,SAAS;AACjB,CAAC;AAMH,QACG,QAAQ,OAAO,EACf,YAAY,2BAA2B,EACvC,OAAO,eAAe,wBAAwB,EAC9C,OAAO,WAAW,wDAAwD,EAC1E,OAAO,cAAc,iDAAiD,EACtE;AAAA,EACC,OAAO,SAA4D;AAKjE,UAAM,aAAa,QAAQ,KAAK;AAIhC,UAAM,EAAE,SAAS,IAAI,MAAM,OAAO,qBAAY;AAC9C,UAAM,SAAS;AAAA,MACb,IAAI,KAAK;AAAA,MACT,OAAO,KAAK,SAAS,WAAW;AAAA,MAChC,SAAS,KAAK,UAAU,SAAS,WAAW,UAAU;AAAA,IACxD,CAAC;AAAA,EACH;AACF;AAIF,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,QAAQ;AAC9C,OAAK,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AACnE,CAAC;","names":["result","kg"]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { createInterface } from \"node:readline\";\nimport { readFileSync, realpathSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\nimport { Client, CographError } from \"./client.js\";\nimport { renderAgentResult } from \"./agentRender.js\";\nimport { readConfig, writeConfig, configPathForDisplay } from \"./config.js\";\n\n// Read version from package.json at runtime so we never drift again.\n// dist/cli.js sits next to package.json once published; in dev (`npm link`)\n// dist/cli.js sits inside packages/cograph/dist/, so the parent dir is the\n// package root either way.\nfunction pkgVersion(): string {\n try {\n const here = dirname(fileURLToPath(import.meta.url));\n const pkg = JSON.parse(readFileSync(join(here, \"..\", \"package.json\"), \"utf-8\"));\n return typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nfunction client(): Client {\n // Honor the global flags: --tenant overrides the saved default for this\n // command; --local points at a self-hosted backend. Both fall through to\n // env / ~/.cograph/config.json when not passed.\n const g = program.opts() as { tenant?: string; local?: boolean };\n return new Client({\n ...(g.tenant ? { tenant: g.tenant } : {}),\n ...(g.local ? { baseUrl: \"http://localhost:8000\" } : {}),\n });\n}\n\nfunction printJson(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\nfunction fail(msg: string, code = 1): never {\n process.stderr.write(msg.endsWith(\"\\n\") ? msg : msg + \"\\n\");\n process.exit(code);\n}\n\nasync function withErrors<T>(fn: () => Promise<T>): Promise<T | void> {\n try {\n return await fn();\n } catch (err) {\n if (err instanceof CographError) {\n fail(`Error: ${err.message}`);\n }\n fail(`Error: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\nasync function confirm(prompt: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${prompt} [y/N] `, (ans) => {\n rl.close();\n resolve(ans.trim().toLowerCase() === \"y\");\n });\n });\n}\n\n/** Like confirm() but defaults to yes (used for the primary \"apply\" action). */\nasync function confirmYes(prompt: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${prompt} [Y/n] `, (ans) => {\n rl.close();\n const a = ans.trim().toLowerCase();\n resolve(a === \"\" || a === \"y\" || a === \"yes\");\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// CSV schema review — terminal port of the Explorer's confirm/override gate.\n// The backend applies exactly what /ingest/csv/rows is given, so the client is\n// responsible for surfacing the inferred mapping and gating held-for-review\n// type extensions before any rows are written.\n// ---------------------------------------------------------------------------\n\nconst useColor = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;\nconst sgr = (code: string) => (s: string): string =>\n useColor ? `\\x1b[${code}m${s}\\x1b[0m` : s;\nconst bold = sgr(\"1\");\nconst dim = sgr(\"2\");\n\ntype Mapping = Record<string, any>;\n\ninterface EntityView {\n name: string;\n type_name: string;\n id_column?: string | null;\n id_from?: string[] | null;\n key_strategy?: string | null;\n confidence?: number | null;\n why?: string | null;\n}\n\nfunction entityViews(m: Mapping): EntityView[] {\n if (Array.isArray(m.entities) && m.entities.length > 0) {\n return m.entities.map((e: any) => ({\n name: e.name,\n type_name: e.type_name,\n id_column: e.id_column,\n id_from: e.id_from,\n key_strategy: e.key_strategy ?? null,\n confidence: e.confidence,\n why: e.why,\n }));\n }\n return [\n {\n name: m.entity_type,\n type_name: m.entity_type,\n key_strategy: m.key_strategy ?? null,\n confidence: m.confidence,\n why: m.why,\n },\n ];\n}\n\nfunction heldTypes(m: Mapping): any[] {\n const types = m.ontology_extensions?.types;\n return Array.isArray(types) ? types.filter((t: any) => t.held_for_review) : [];\n}\n\n/** Strip response-only audit fields (violations, inference_audit, profile) and\n * keep only what /ingest/csv/rows applies. Held type extensions are dropped\n * unless explicitly approved — same gate the Explorer applies on confirm. */\nfunction buildMappingForIngest(m: Mapping, approved: Set<string>): Mapping {\n const out: Mapping = { entity_type: m.entity_type, columns: m.columns };\n if (m.entities) out.entities = m.entities;\n if (m.relationships) out.relationships = m.relationships;\n const types = m.ontology_extensions?.types;\n if (Array.isArray(types)) {\n out.ontology_extensions = {\n types: types.filter(\n (t: any) => !t.held_for_review || approved.has(t.type_name),\n ),\n };\n }\n return out;\n}\n\nfunction fmtConf(v: any): string {\n if (v == null) return \"\";\n const n = Number(v);\n if (Number.isNaN(n)) return \"\";\n return dim(` (${n.toFixed(2)}${n < 0.7 ? \" !\" : \"\"})`);\n}\n\nfunction renderMapping(\n m: Mapping,\n info: { totalRows: number; rowsProfiled: number },\n): void {\n const w = (s: string) => process.stdout.write(s);\n w(\n \"\\n\" +\n bold(\"Proposed schema\") +\n dim(\n ` (profiled ${info.rowsProfiled.toLocaleString()} of ${info.totalRows.toLocaleString()} rows)`,\n ) +\n \"\\n\",\n );\n w(dim(\"Review how the data maps to the graph before any rows are written.\") + \"\\n\\n\");\n\n const ents = entityViews(m);\n const multi = Array.isArray(m.entities) && m.entities.length > 0;\n w(bold(\"Entities & keys\") + \"\\n\");\n for (const e of ents) {\n const key = e.id_column\n ? `key: ${e.id_column}`\n : e.id_from && e.id_from.length\n ? `key: ${e.id_from.join(\" + \")}`\n : e.key_strategy === \"synthetic\"\n ? \"key: (synthetic)\"\n : \"key: —\";\n w(` • ${bold(e.type_name)} ${dim(key)}${fmtConf(e.confidence)}\\n`);\n if (e.why) w(` ${dim(e.why)}\\n`);\n const cols = (m.columns ?? []).filter((col: any) =>\n multi ? col.entity === e.name : true,\n );\n for (const col of cols) {\n const role =\n col.role === \"type_id\"\n ? \"key \"\n : col.role === \"relationship\"\n ? \"edge\"\n : \"attr\";\n let detail = \"\";\n if (col.role === \"relationship\" && col.target_type)\n detail = ` → ${col.target_type}`;\n else if (\n col.role === \"attribute\" &&\n col.attribute_name &&\n col.attribute_name !== col.column_name\n )\n detail = ` as ${col.attribute_name}`;\n const dt =\n col.datatype && col.datatype !== \"string\"\n ? \" \" + dim(`[${col.datatype}]`)\n : \"\";\n w(\n ` ${dim(\"[\" + role + \"]\")} ${col.column_name}${detail}${dt}${fmtConf(col.confidence)}\\n`,\n );\n }\n }\n\n const rels = m.relationships ?? [];\n if (rels.length) {\n w(\"\\n\" + bold(\"Edges\") + \"\\n\");\n for (const r of rels)\n w(` • ${r.subject} ${dim(r.predicate)} ${r.object}${fmtConf(r.confidence)}\\n`);\n }\n\n const vio = m.violations ?? [];\n if (vio.length) {\n w(\n \"\\n\" +\n dim(\n `Refute pass corrected ${vio.length} issue${vio.length === 1 ? \"\" : \"s\"}: ${vio\n .map((v: any) => v.template)\n .join(\", \")}`,\n ) +\n \"\\n\",\n );\n }\n}\n\n/** Interactive confirm/override gate, passed to client.ingest as\n * onSchemaInferred. Returns the mapping to ingest, or null to cancel. */\nasync function reviewMapping(\n m: Mapping,\n info: { totalRows: number; rowsProfiled: number },\n): Promise<Mapping | null> {\n renderMapping(m, info);\n const approved = new Set<string>();\n const held = heldTypes(m);\n if (held.length) {\n process.stdout.write(\n \"\\n\" +\n bold(`${held.length} new type${held.length === 1 ? \"\" : \"s\"} held for review`) +\n dim(\" — approve to create, or skip to leave for later\") +\n \"\\n\",\n );\n for (const t of held) {\n const from = t.promoted_from_attribute\n ? dim(` (from \"${t.promoted_from_attribute}\")`)\n : \"\";\n process.stdout.write(` • ${t.type_name}${from}${fmtConf(t.confidence)}\\n`);\n if (await confirm(` Approve \"${t.type_name}\"?`)) approved.add(t.type_name);\n }\n }\n process.stdout.write(\"\\n\");\n const ok = await confirmYes(\n `Apply this mapping and ingest ${info.totalRows.toLocaleString()} rows?`,\n );\n if (!ok) return null;\n return buildMappingForIngest(m, approved);\n}\n\nconst program = new Command();\nprogram\n .name(\"cograph\")\n .description(\"Cograph Knowledge Graph CLI\")\n .version(pkgVersion())\n // Default action when no subcommand is given: drop into the interactive\n // shell. So `cograph` (or `npx cograph`) Just Works for the common case;\n // subcommands like `cograph ingest <file>` still route to their own\n // actions because commander dispatches subcommands first.\n .option(\"--local\", \"Use http://localhost:8000 and skip login (self-hosted)\")\n .option(\"--no-login\", \"Skip browser login (assume open-access backend)\")\n .option(\n \"--tenant <id>\",\n \"Target a specific tenant for this command (overrides the saved default)\",\n )\n .action(async (opts: { local?: boolean; login?: boolean }) => {\n const { runShell } = await import(\"./shell.js\");\n await runShell({\n local: opts.local,\n // commander's --no-login inverts: opts.login === false when flag passed.\n noLogin: opts.login === false,\n });\n });\n\n// ---------------------------------------------------------------------------\n// kg\n// ---------------------------------------------------------------------------\n\nconst kg = program.command(\"kg\").description(\"Manage knowledge graphs\");\n\nkg.command(\"list\")\n .description(\"List knowledge graphs\")\n .action(async () => {\n await withErrors(async () => {\n const kgs = await client().listKgs();\n if (!kgs.length) {\n process.stdout.write(\n \"No knowledge graphs. Create one with: cograph kg create <name>\\n\",\n );\n return;\n }\n for (const k of kgs) {\n const name = String(k.name ?? \"?\");\n const triples = Number(k.triple_count ?? 0);\n const desc = k.description ? ` — ${k.description}` : \"\";\n const padName = name.padEnd(20, \" \");\n const padTriples = String(triples).padStart(6, \" \");\n process.stdout.write(` ${padName} ${padTriples} triples${desc}\\n`);\n }\n });\n });\n\nkg.command(\"create <name>\")\n .description(\"Create a knowledge graph\")\n .option(\"-d, --description <text>\", \"Description\")\n .action(async (name: string, opts: { description?: string }) => {\n await withErrors(async () => {\n const created = await client().createKg(name, opts.description);\n process.stdout.write(`Created knowledge graph: ${created.name ?? name}\\n`);\n });\n });\n\nkg.command(\"delete <name>\")\n .description(\"Delete a knowledge graph\")\n .action(async (name: string) => {\n await withErrors(async () => {\n await client().deleteKg(name);\n process.stdout.write(`Deleted knowledge graph: ${name}\\n`);\n });\n });\n\n// ---------------------------------------------------------------------------\n// tenant\n// ---------------------------------------------------------------------------\n\nconst tenantCmd = program\n .command(\"tenant\")\n .description(\"Show or switch the active tenant\");\n\ntenantCmd\n .command(\"current\", { isDefault: true })\n .description(\"Show the active tenant\")\n .action(() => {\n const active = client().tenant;\n const saved = readConfig().tenant;\n process.stdout.write(`Active tenant: ${bold(active)}\\n`);\n process.stdout.write(\n saved\n ? dim(` saved default in ${configPathForDisplay()}\\n`)\n : dim(` (built-in default — set one with: cograph tenant use <id>)\\n`),\n );\n });\n\ntenantCmd\n .command(\"list\")\n .description(\"List the tenants you can access\")\n .action(async () => {\n await withErrors(async () => {\n const c = client();\n let tenants: Array<{ id: string; label: string }>;\n try {\n tenants = await c.listTenants();\n } catch (err) {\n if (err instanceof CographError && err.status === 501) {\n fail(\n \"This backend doesn't support tenant management (no tenant provider configured).\",\n );\n }\n throw err;\n }\n if (!tenants.length) {\n process.stdout.write(\"No tenants found for your account.\\n\");\n return;\n }\n const active = c.tenant;\n for (const t of tenants) {\n const marker = t.id === active ? \"*\" : \" \";\n process.stdout.write(` ${marker} ${t.id.padEnd(24)} ${dim(t.label)}\\n`);\n }\n process.stdout.write(dim(`\\nSwitch with: cograph tenant use <id>\\n`));\n });\n });\n\ntenantCmd\n .command(\"use <id>\")\n .description(\"Set the active tenant (saved to ~/.cograph/config.json)\")\n .action((id: string) => {\n writeConfig({ tenant: id });\n process.stdout.write(`${bold(\"✓\")} Active tenant set to ${bold(id)}\\n`);\n process.stdout.write(dim(`Saved to ${configPathForDisplay()}\\n`));\n });\n\n// ---------------------------------------------------------------------------\n// ingest\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"ingest [file]\")\n .description(\"Ingest data from a file or --text\")\n .option(\"-t, --text <text>\", \"Inline text to ingest\")\n .option(\"--kg <name>\", \"Target knowledge graph name\")\n .option(\n \"-f, --format <fmt>\",\n \"Override format detection (text|csv|json)\",\n )\n .option(\n \"-y, --yes\",\n \"Skip the CSV schema review and apply the inferred mapping non-interactively\",\n )\n .action(\n async (\n file: string | undefined,\n opts: { text?: string; kg?: string; format?: string; yes?: boolean },\n ) => {\n await withErrors(async () => {\n const c = client();\n if (opts.text) {\n process.stdout.write(\n `Ingesting text (${opts.text.length.toLocaleString()} chars)...\\n`,\n );\n const result = await c.ingest(opts.text, {\n kg: opts.kg,\n contentType: opts.format ?? \"text\",\n });\n printIngestResult(result);\n return;\n }\n if (!file) {\n fail(\"Provide a file or --text\");\n }\n // For CSV, interpose the same schema review/confirm gate the Explorer\n // shows. Interactive on a TTY unless --yes; otherwise apply the\n // inferred mapping as-is (held type extensions auto-approved, matching\n // the prior non-interactive behavior). Hook is ignored for text/json.\n const interactive =\n Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY) && !opts.yes;\n const onSchemaInferred = interactive\n ? reviewMapping\n : (m: Mapping) =>\n Promise.resolve(\n buildMappingForIngest(\n m,\n new Set(heldTypes(m).map((t: any) => t.type_name)),\n ),\n );\n // ingest() handles file reading + format detection + CSV two-step flow.\n process.stdout.write(`Ingesting ${file}...\\n`);\n const result = await c.ingest(file, {\n kg: opts.kg,\n contentType: opts.format,\n onSchemaInferred,\n });\n if ((result as Record<string, unknown>).cancelled) {\n process.stdout.write(\"Cancelled — nothing was written.\\n\");\n return;\n }\n printIngestResult(result);\n });\n },\n );\n\nfunction printIngestResult(result: Record<string, unknown>): void {\n const num = (k: string) => Number(result[k] ?? 0);\n process.stdout.write(` Entities extracted: ${num(\"entities_extracted\")}\\n`);\n process.stdout.write(` Entities resolved: ${num(\"entities_resolved\")}\\n`);\n process.stdout.write(` Triples inserted: ${num(\"triples_inserted\")}\\n`);\n const types = result.types_created;\n if (Array.isArray(types) && types.length) {\n process.stdout.write(` Types created: ${types.join(\", \")}\\n`);\n }\n const rejections = result.rejections;\n if (Array.isArray(rejections) && rejections.length) {\n process.stdout.write(` Rejections: ${rejections.length}\\n`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// ask\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"ask <question>\")\n .description(\"Ask a natural language question\")\n .option(\"--kg <name>\", \"Knowledge graph to query\")\n .option(\"-d, --debug\", \"Show SPARQL and latency breakdown\")\n .option(\"-m, --model <model>\", \"Override query model\")\n .action(\n async (\n question: string,\n opts: { kg?: string; debug?: boolean; model?: string },\n ) => {\n await withErrors(async () => {\n if (opts.model) process.stdout.write(`Model: ${opts.model}\\n`);\n process.stdout.write(`Q: ${question}\\n`);\n process.stdout.write(\"Generating answer...\\n\");\n const t0 = Date.now();\n const result = await client().ask(question, {\n kg: opts.kg,\n model: opts.model,\n });\n const roundtripMs = Date.now() - t0;\n process.stdout.write(`\\nA: ${result.answer ?? \"No answer\"}\\n`);\n if (opts.debug) {\n process.stdout.write(`\\nSPARQL:\\n${result.sparql ?? \"\"}\\n`);\n const timing = (result.timing ?? {}) as Record<string, unknown>;\n if (Object.keys(timing).length) {\n process.stdout.write(`\\n${\"─\".repeat(40)}\\n`);\n process.stdout.write(\n `${\"Stage\".padEnd(25)} ${\"Time\".padStart(10)}\\n`,\n );\n process.stdout.write(`${\"─\".repeat(40)}\\n`);\n for (const [key, val] of Object.entries(timing)) {\n if (key === \"attempts\") {\n process.stdout.write(\n `${\"Attempts\".padEnd(25)} ${String(val).padStart(10)}\\n`,\n );\n } else if (typeof val === \"string\") {\n const label = key\n .replace(/_/g, \" \")\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n process.stdout.write(\n `${label.padEnd(25)} ${val.padStart(10)}\\n`,\n );\n } else {\n const label = key\n .replace(/_ms$/, \"\")\n .replace(/_/g, \" \")\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n const num = typeof val === \"number\" ? val : Number(val);\n process.stdout.write(\n `${label.padEnd(25)} ${num.toFixed(1).padStart(8)}ms\\n`,\n );\n }\n }\n process.stdout.write(`${\"─\".repeat(40)}\\n`);\n process.stdout.write(\n `${\"Client roundtrip\".padEnd(25)} ${roundtripMs.toFixed(1).padStart(8)}ms\\n`,\n );\n }\n }\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n// agent — unified Ask-AI agent (POST /graphs/{tenant}/agent)\n// ---------------------------------------------------------------------------\n//\n// The ONE command that reaches the unified agent the web app + MCP already use:\n// it classifies intent server-side (question | enrich | clean | dedup |\n// ontology) and either answers, asks a clarifying question, or proposes a plan\n// to confirm. The discrete commands (ask/enrich/er/ontology) stay as\n// convenient shortcuts; migrating them onto the agent is a deliberate non-goal.\n//\n// Confirm flow (non-interactive): a returned plan is NOT executed automatically.\n// Either re-run with --confirm <plan_id> (the only mutating path), or pass --yes\n// to confirm-and-execute in the same invocation.\n\n/**\n * Core of the `agent` command — extracted so it's unit-testable with a mocked\n * {@link Client} (the commander action below just builds a real client and\n * delegates). Drives the three non-interactive paths:\n * - `--confirm <id>` → execute that plan directly, render the result.\n * - default → one agent turn, render it; if it's a plan, either\n * confirm-and-execute (`--yes`) or print a confirm hint.\n *\n * Exported for tests; not part of the published SDK surface (cli.ts is the bin\n * entry, not in `package.json#exports`).\n */\nexport async function runAgentCommand(\n c: Client,\n message: string,\n opts: { kg?: string; type?: string; yes?: boolean; confirm?: string },\n): Promise<void> {\n // KG resolution mirrors `ask`: an explicit --kg wins, else the SDK's\n // saved/default kg (passing undefined lets the backend use its default).\n const context = { kgName: opts.kg, typeName: opts.type };\n\n // --confirm path: execute the named plan directly and render the result.\n if (opts.confirm) {\n const result = await c.agent({ confirmPlanId: opts.confirm, ...context });\n renderAgentResult(result);\n return;\n }\n\n const result = await c.agent({ message, ...context });\n renderAgentResult(result);\n\n // A plan is the only kind that awaits a follow-up. With --yes we confirm\n // immediately; otherwise we print how to confirm it later.\n if (result.kind === \"plan\") {\n const planId =\n typeof result.plan_id === \"string\" ? result.plan_id : undefined;\n if (!planId) return;\n if (opts.yes) {\n const executed = await c.agent({ confirmPlanId: planId, ...context });\n renderAgentResult(executed);\n } else {\n const flags = [\n opts.kg ? `--kg ${opts.kg}` : \"\",\n opts.type ? `--type ${opts.type}` : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n const hint = `cograph agent --confirm ${planId}${flags ? \" \" + flags : \"\"} ${JSON.stringify(message)}`;\n process.stdout.write(\n `${dim(\"Confirm & run:\")} ${hint}\\n` +\n `${dim(\" or re-run with --yes to execute now.\")}\\n`,\n );\n }\n }\n}\n\nprogram\n .command(\"agent <message>\")\n .description(\"Talk to the unified Ask-AI agent (answers, plans, and runs actions)\")\n .option(\"--kg <name>\", \"Knowledge graph to operate within\")\n .option(\"--type <Type>\", \"Active type scope (for enrich/clean/dedup planning)\")\n .option(\n \"-y, --yes\",\n \"Auto-confirm and execute a returned plan in the same run\",\n )\n .option(\n \"--confirm <planId>\",\n \"Execute a specific previously-proposed plan id (skips planning)\",\n )\n .action(\n async (\n message: string,\n opts: { kg?: string; type?: string; yes?: boolean; confirm?: string },\n ) => {\n await withErrors(() => runAgentCommand(client(), message, opts));\n },\n );\n\n// ---------------------------------------------------------------------------\n// ontology\n// ---------------------------------------------------------------------------\n\nconst onto = program.command(\"ontology\").description(\"View ontology\");\n\nonto\n .command(\"types\")\n .description(\"List ontology types\")\n .action(async () => {\n await withErrors(async () => {\n const types = await client().ontologyTypes();\n if (!types.length) {\n process.stdout.write(\"No ontology types defined.\\n\");\n return;\n }\n for (const t of types) {\n const parent = t.parent_type\n ? ` (subClassOf ${t.parent_type})`\n : \"\";\n const desc = t.description ? ` — ${t.description}` : \"\";\n process.stdout.write(` ${t.name}${parent}${desc}\\n`);\n const attrs = (t.attributes ?? []) as Array<Record<string, unknown>>;\n for (const a of attrs) {\n process.stdout.write(\n ` .${a.name} (${a.datatype ?? \"string\"})\\n`,\n );\n }\n }\n });\n });\n\n// ---------------------------------------------------------------------------\n// er — entity resolution\n// ---------------------------------------------------------------------------\n\nconst er = program.command(\"er\").description(\"Entity resolution\");\n\ner.command(\"rebuild\")\n .description(\n \"Second pass: collapse intra-batch entity fragments in an ingested KG\",\n )\n .requiredOption(\"--kg <name>\", \"Knowledge graph to rebuild\")\n .action(async (opts: { kg: string }) => {\n await withErrors(async () => {\n process.stdout.write(`Rebuilding entity resolution for ${opts.kg}…\\n`);\n const report = await client().erRebuild(opts.kg);\n const types = (report.types ?? []) as Array<Record<string, unknown>>;\n for (const t of types) {\n const name = String(t.type ?? \"?\").padEnd(16, \" \");\n process.stdout.write(\n ` ${name} ${t.entities_before} → ${t.entities_after}` +\n ` (−${t.fragments_absorbed} fragments across ${t.clusters_merged} clusters)\\n`,\n );\n }\n process.stdout.write(\n `Done. ${report.fragments_absorbed_total ?? 0} fragments absorbed.\\n`,\n );\n });\n });\n\n// ---------------------------------------------------------------------------\n// enrich\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"enrich\")\n .description(\"Agentic enrichment — fill an attribute from web sources, with citations\")\n .requiredOption(\"--kg <name>\", \"Knowledge graph\")\n .requiredOption(\"--type <Type>\", \"Entity type to enrich\")\n .requiredOption(\"--attribute <attr>\", \"Attribute to fill (e.g. reviews, description)\")\n .option(\"--tier <tier>\", \"lite | base | core | pro (paid adapters live in core/pro)\", \"core\")\n .option(\"--limit <n>\", \"Max entities to enrich\", \"3\")\n .option(\"--apply\", \"Write results to the graph (with provenance), not just stage\")\n .action(\n async (opts: {\n kg: string;\n type: string;\n attribute: string;\n tier: string;\n limit: string;\n apply?: boolean;\n }) => {\n await withErrors(async () => {\n const c = client();\n process.stdout.write(\n `Enriching ${opts.type}.${opts.attribute} in ${opts.kg} (tier ${opts.tier})…\\n`,\n );\n const created = await c.enrichRun({\n kg_name: opts.kg,\n type_name: opts.type,\n attributes: [opts.attribute],\n tier: opts.tier as \"lite\" | \"base\" | \"core\" | \"pro\",\n limit: Number(opts.limit),\n conflict_policy: opts.apply ? \"overwrite\" : \"stage\",\n confidence_min: 0.1,\n });\n const terminal = [\"applied\", \"review\", \"failed\", \"cancelled\"];\n let job = await c.enrichJob(created.job_id);\n for (let i = 0; i < 40 && !terminal.includes(job.status); i++) {\n await new Promise((r) => setTimeout(r, 2000));\n job = await c.enrichJob(created.job_id);\n }\n const filled = (job.results ?? []).filter((r) => r.verdict);\n if (!filled.length) {\n process.stdout.write(\"No enrichment results (no source returned a value).\\n\");\n return;\n }\n for (const r of filled) {\n const v = r.verdict!;\n process.stdout.write(`\\n ${r.entity_uri.split(\"/\").pop()}\\n`);\n process.stdout.write(` ${r.attribute}: ${v.value}\\n`);\n process.stdout.write(\n ` source: ${v.source}${v.source_url ? \" \" + v.source_url : \"\"}\\n`,\n );\n if (v.reasoning) process.stdout.write(` ${v.reasoning}\\n`);\n }\n process.stdout.write(\n `\\n${opts.apply ? \"Applied to the graph (value + provenance triples).\" : \"Staged for review — re-run with --apply to write.\"}\\n`,\n );\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n// vis\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"vis <type>\")\n .description(\"Visualise a type — instance count, attribute coverage, top relations\")\n .option(\"--kg <name>\", \"Knowledge graph to inspect\")\n .action(async (typeName: string, opts: { kg?: string }) => {\n await withErrors(async () => {\n const c = client();\n\n // Resolve KG: use --kg flag, or pick first available KG.\n let kg = opts.kg;\n if (!kg) {\n const kgs = await c.listKgs();\n if (!kgs.length) {\n fail(\"No knowledge graphs found. Run 'cograph ingest' first.\");\n }\n kg = String(kgs[0].name ?? \"\");\n }\n\n let summary: import(\"./client.js\").TypeSummary;\n try {\n summary = await c.typeSummary(kg, typeName);\n } catch {\n fail(`Type '${typeName}' not found in KG '${kg}'.`);\n }\n\n const { entity_count, attributes, relationships, description, parent_type } = summary;\n const header = `${typeName}${parent_type ? ` (subClassOf ${parent_type})` : \"\"} — ${entity_count.toLocaleString()} instances`;\n process.stdout.write(`\\n${header}\\n${\"─\".repeat(header.length)}\\n`);\n if (description) process.stdout.write(`${description}\\n`);\n\n // Attributes table\n if (attributes.length) {\n process.stdout.write(`\\nAttributes (${attributes.length}):\\n`);\n const sorted = [...attributes].sort((a, b) => b.coverage_pct - a.coverage_pct);\n for (const a of sorted.slice(0, 10)) {\n const bar = \"█\".repeat(Math.round(a.coverage_pct / 10));\n const pct = `${a.coverage_pct}%`.padStart(6);\n process.stdout.write(` ${a.name.padEnd(24)} ${pct} ${bar}\\n`);\n }\n if (attributes.length > 10) {\n process.stdout.write(` … and ${attributes.length - 10} more\\n`);\n }\n }\n\n // Relations table\n if (relationships.length) {\n process.stdout.write(`\\nRelationships (${relationships.length}):\\n`);\n for (const r of relationships.slice(0, 8)) {\n const target = r.target_type ? ` → ${r.target_type}` : \"\";\n const pct = `${r.coverage_pct}%`.padStart(6);\n const avg = r.avg_degree ? ` (avg ${r.avg_degree})` : \"\";\n process.stdout.write(` ${(r.name + target).padEnd(36)} ${pct}${avg}\\n`);\n }\n }\n\n const explorerUrl = `https://cograph.cloud/dashboard/explore/${encodeURIComponent(typeName)}?kg=${encodeURIComponent(kg)}`;\n process.stdout.write(`\\n→ Open visually at ${explorerUrl}\\n`);\n process.stdout.write(\" (Sign in for interactive viz, search, and click-to-enrich.)\\n\\n\");\n });\n });\n\n// ---------------------------------------------------------------------------\n// clear\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"clear\")\n .description(\"Clear data\")\n .option(\"--kg <name>\", \"Clear a specific knowledge graph\")\n .option(\n \"--include-ontology\",\n \"Also clear the ontology (only meaningful when --kg is omitted)\",\n false,\n )\n .option(\"-y, --yes\", \"Skip confirmation\", false)\n .action(\n async (opts: { kg?: string; includeOntology?: boolean; yes?: boolean }) => {\n await withErrors(async () => {\n let msg: string;\n if (opts.kg) {\n msg = `Clear KG '${opts.kg}'?`;\n } else if (opts.includeOntology) {\n msg = \"Clear EVERYTHING including ontology?\";\n } else {\n msg = \"Clear all instance data (ontology preserved)?\";\n }\n\n if (!opts.yes) {\n const ok = await confirm(msg);\n if (!ok) {\n process.stdout.write(\"Cancelled.\\n\");\n return;\n }\n }\n\n const c = client();\n if (opts.kg) {\n await c.deleteKg(opts.kg);\n process.stdout.write(`Cleared KG: ${opts.kg}\\n`);\n return;\n }\n\n // Bulk-clear via /query + DELETE /triples — same loop the Python CLI uses.\n const tenant = c.tenant;\n const baseUrl = `${c.baseUrl}/graphs/${tenant}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (c.apiKey) headers[\"X-API-Key\"] = c.apiKey;\n\n const filters = opts.includeOntology\n ? \"\"\n : `FILTER(CONTAINS(STR(?s), '/entities/') || CONTAINS(STR(?s), '/onto/') || CONTAINS(STR(?s), '/kgs/'))`;\n const query = `SELECT ?s ?p ?o FROM <https://cograph.tech/graphs/${tenant}> WHERE { ?s ?p ?o . ${filters} } LIMIT 1000`;\n\n process.stdout.write(\"Clearing...\\n\");\n let deleted = 0;\n for (let i = 0; i < 50; i++) {\n const fetchRes = await fetch(`${baseUrl}/query`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ query }),\n });\n if (!fetchRes.ok) break;\n const data = (await fetchRes.json()) as {\n bindings?: Array<Record<string, unknown>>;\n };\n const bindings = data.bindings ?? [];\n if (!bindings.length) break;\n const triples = bindings\n .filter((b) => b.s)\n .map((b) => ({\n subject: b.s,\n predicate: b.p,\n object: b.o,\n }));\n for (let j = 0; j < triples.length; j += 100) {\n await fetch(`${baseUrl}/triples`, {\n method: \"DELETE\",\n headers,\n body: JSON.stringify({ triples: triples.slice(j, j + 100) }),\n });\n }\n deleted += triples.length;\n }\n process.stdout.write(`Deleted ${deleted} triples\\n`);\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n// login\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"login\")\n .description(\"Sign in via your browser and save an API key\")\n .action(async () => {\n const { runLogin } = await import(\"./login.js\");\n await runLogin();\n });\n\n// ---------------------------------------------------------------------------\n// shell\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"shell\")\n .description(\"Start an interactive REPL\")\n .option(\"--kg <name>\", \"Knowledge graph to use\")\n .option(\"--local\", \"Use http://localhost:8000 and skip login (self-hosted)\")\n .option(\"--no-login\", \"Skip browser login (assume open-access backend)\")\n .action(\n async (opts: { kg?: string; local?: boolean; login?: boolean }) => {\n // Parent program also accepts --local/--no-login (so `cograph --local`\n // works without a subcommand). When commander parses\n // `cograph shell --local`, the parent sees --local first and the\n // subcommand never gets it — so merge from program.opts() too.\n const parentOpts = program.opts() as {\n local?: boolean;\n login?: boolean;\n };\n const { runShell } = await import(\"./shell.js\");\n await runShell({\n kg: opts.kg,\n local: opts.local || parentOpts.local,\n noLogin: opts.login === false || parentOpts.login === false,\n });\n },\n );\n\n// ---------------------------------------------------------------------------\n\n/** True when this module is the process entry point (run as `cograph …`), not\n * when it's imported (e.g. by the unit tests that exercise `runAgentCommand`).\n * Guards the auto-parse so importing the module has no side effects.\n *\n * npm installs the `bin` as a SYMLINK (node_modules/.bin/cograph →\n * dist/cli.js). Node sets import.meta.url to the *realpath* of the entry file\n * while process.argv[1] keeps the *symlink* path, so a naive href comparison\n * never matches and the CLI silently does nothing. Resolve the symlink first:\n * compare fileURLToPath(import.meta.url) against realpathSync(process.argv[1]).\n */\nfunction isMainModule(): boolean {\n const argv1 = process.argv[1];\n if (!argv1) return false;\n try {\n return fileURLToPath(import.meta.url) === realpathSync(argv1);\n } catch {\n return false;\n }\n}\n\nif (isMainModule()) {\n program.parseAsync(process.argv).catch((err) => {\n fail(`Error: ${err instanceof Error ? err.message : String(err)}`);\n });\n}\n\n// silence unused import warning if ever needed\nvoid printJson;\n"],"mappings":"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","names":["result","kg"]}
package/dist/index.d.ts CHANGED
@@ -162,6 +162,17 @@ declare class Client {
162
162
  enrichRun(req: EnrichRequest): Promise<EnrichJobCreate>;
163
163
  /** List recent enrichment jobs for the current tenant. */
164
164
  enrichJobs(): Promise<JobSummary[]>;
165
+ /**
166
+ * List ALL of a tenant's tracked jobs — dedupe, enrichment AND reconciliation
167
+ * — newest first (`GET /graphs/{tenant}/jobs`, COG-101). This is the unified
168
+ * feed the Jobs page renders; contrast {@link enrichJobs}, which lists only
169
+ * enrichment jobs (`/enrich/jobs`). Pass `category` to filter to one kind.
170
+ * Each item carries the unified summary fields (category, trigger, last_run,
171
+ * next_run, cost(+note), status, progress_pct).
172
+ */
173
+ jobs(opts?: {
174
+ category?: JobCategory;
175
+ }): Promise<JobSummary[]>;
165
176
  /** Fetch a single enrichment job (with truncated results). */
166
177
  enrichJob(jobId: string): Promise<EnrichJob>;
167
178
  /** Fetch the conflict review queue for a job. */
@@ -297,6 +308,12 @@ interface TypeSummary {
297
308
  }
298
309
  type EnrichmentTier = "lite" | "base" | "core" | "pro";
299
310
  type JobStatus = "queued" | "running" | "review" | "applied" | "cancelled" | "failed";
311
+ /** The kind of work a tracked job performs — the unified `/jobs` feed spans all
312
+ * three. Existing enrichment jobs default to `enrichment` server-side. */
313
+ type JobCategory = "dedupe" | "enrichment" | "reconciliation";
314
+ /** How a job was kicked off. Today everything is `manual` (a user clicked an
315
+ * action); `scheduled`/`webhook` are reserved for future automation. */
316
+ type JobTrigger = "manual" | "scheduled" | "webhook";
300
317
  type ConflictPolicy = "skip" | "verify" | "overwrite" | "stage";
301
318
  type RowAction = "filled" | "verified" | "conflict" | "skipped" | "no_match";
302
319
  type ReviewDecision = "accept" | "reject" | "skip";
@@ -353,6 +370,14 @@ interface JobSummary {
353
370
  conflict_policy: ConflictPolicy;
354
371
  confidence_min: number;
355
372
  error?: string | null;
373
+ category?: JobCategory;
374
+ trigger?: JobTrigger;
375
+ last_run?: string | null;
376
+ next_run?: string | null;
377
+ cost?: number | null;
378
+ cost_note?: string | null;
379
+ /** Derived 0-100 completion percentage from progress.processed/total. */
380
+ progress_pct?: number;
356
381
  }
357
382
  interface EnrichJob extends JobSummary {
358
383
  results?: RowResult[];
@@ -482,6 +507,11 @@ declare class RawApi {
482
507
  enrichCreateJob(body: unknown, init?: RawInit): Promise<Response>;
483
508
  /** `GET /graphs/{tenant}/enrich/jobs` — list recent enrichment jobs. */
484
509
  enrichJobs(init?: RawInit): Promise<Response>;
510
+ /** `GET /graphs/{tenant}/jobs?category` — unified jobs list across ALL
511
+ * categories (dedupe + enrichment + reconciliation), newest first. */
512
+ jobs(opts?: {
513
+ category?: string;
514
+ }, init?: RawInit): Promise<Response>;
485
515
  /** `GET /graphs/{tenant}/enrich/jobs/{id}` — fetch a single job. */
486
516
  enrichJob(jobId: string, init?: RawInit): Promise<Response>;
487
517
  /** `GET /graphs/{tenant}/enrich/jobs/{id}/conflicts` — conflict review queue. */
package/dist/index.js CHANGED
@@ -205,6 +205,11 @@ var Client = class {
205
205
  pOntologyApply() {
206
206
  return `${this.base()}/ontology/apply`;
207
207
  }
208
+ /** @internal Unified jobs list (dedupe + enrichment + reconciliation),
209
+ * newest first. Optional `?category=` filter is baked into `query`. */
210
+ pJobs(query) {
211
+ return `${this.base()}/jobs${query ?? ""}`;
212
+ }
208
213
  /** @internal */
209
214
  pKgs() {
210
215
  return `${this.base()}/kgs`;
@@ -662,6 +667,24 @@ var Client = class {
662
667
  );
663
668
  return Array.isArray(data) ? data : [];
664
669
  }
670
+ /**
671
+ * List ALL of a tenant's tracked jobs — dedupe, enrichment AND reconciliation
672
+ * — newest first (`GET /graphs/{tenant}/jobs`, COG-101). This is the unified
673
+ * feed the Jobs page renders; contrast {@link enrichJobs}, which lists only
674
+ * enrichment jobs (`/enrich/jobs`). Pass `category` to filter to one kind.
675
+ * Each item carries the unified summary fields (category, trigger, last_run,
676
+ * next_run, cost(+note), status, progress_pct).
677
+ */
678
+ async jobs(opts = {}) {
679
+ const qs = opts.category ? `?category=${encodeURIComponent(opts.category)}` : "";
680
+ const data = await this.request(
681
+ "GET",
682
+ this.pJobs(qs),
683
+ void 0,
684
+ 15e3
685
+ );
686
+ return Array.isArray(data) ? data : [];
687
+ }
665
688
  /** Fetch a single enrichment job (with truncated results). */
666
689
  async enrichJob(jobId) {
667
690
  return this.request(
@@ -873,6 +896,12 @@ var RawApi = class {
873
896
  enrichJobs(init) {
874
897
  return this.client.requestRaw("GET", this.client.pEnrichJobs(), init);
875
898
  }
899
+ /** `GET /graphs/{tenant}/jobs?category` — unified jobs list across ALL
900
+ * categories (dedupe + enrichment + reconciliation), newest first. */
901
+ jobs(opts = {}, init) {
902
+ const qs = opts.category ? `?category=${encodeURIComponent(opts.category)}` : "";
903
+ return this.client.requestRaw("GET", this.client.pJobs(qs), init);
904
+ }
876
905
  /** `GET /graphs/{tenant}/enrich/jobs/{id}` — fetch a single job. */
877
906
  enrichJob(jobId, init) {
878
907
  return this.client.requestRaw("GET", this.client.pEnrichJob(jobId), init);