@kweaver-ai/kweaver-sdk 0.4.1 → 0.4.2

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.
@@ -1,11 +1,15 @@
1
1
  import { createInterface } from "node:readline";
2
- import { readFileSync } from "node:fs";
2
+ import { spawnSync } from "node:child_process";
3
+ import { mkdirSync, readFileSync, readdirSync, statSync } from "node:fs";
4
+ import { resolve } from "node:path";
5
+ import { loadNetwork, allObjects, allRelations, allActions, generateChecksum } from "@kweaver-ai/bkn";
3
6
  import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
4
7
  import { listKnowledgeNetworks, getKnowledgeNetwork, createKnowledgeNetwork, updateKnowledgeNetwork, deleteKnowledgeNetwork, listObjectTypes, listRelationTypes, listActionTypes, getObjectType, createObjectTypes, updateObjectType, deleteObjectTypes, getRelationType, createRelationTypes, updateRelationType, deleteRelationTypes, buildKnowledgeNetwork, getBuildStatus, } from "../api/knowledge-networks.js";
5
8
  import { objectTypeQuery, objectTypeProperties, subgraph, actionTypeQuery, actionTypeExecute, actionExecutionGet, actionLogsList, actionLogGet, actionLogCancel, } from "../api/ontology-query.js";
6
9
  import { semanticSearch } from "../api/semantic-search.js";
7
10
  import { listTablesWithColumns } from "../api/datasources.js";
8
11
  import { createDataView } from "../api/dataviews.js";
12
+ import { downloadBkn, uploadBkn } from "../api/bkn-backend.js";
9
13
  import { formatCallOutput } from "./call.js";
10
14
  export function formatSimpleKnList(text, pretty, includeDetail = false) {
11
15
  const parsed = JSON.parse(text);
@@ -338,6 +342,92 @@ export function parseKnDeleteArgs(args) {
338
342
  }
339
343
  return { knId, businessDomain, yes };
340
344
  }
345
+ export function parseKnPushArgs(args) {
346
+ let directory = "";
347
+ let branch = "main";
348
+ let businessDomain = "bd_public";
349
+ let pretty = true;
350
+ for (let i = 0; i < args.length; i += 1) {
351
+ const arg = args[i];
352
+ if (arg === "--help" || arg === "-h") {
353
+ throw new Error("help");
354
+ }
355
+ if (arg === "--branch") {
356
+ branch = args[i + 1] ?? "main";
357
+ if (!branch || branch.startsWith("-")) {
358
+ throw new Error("Missing value for --branch");
359
+ }
360
+ i += 1;
361
+ continue;
362
+ }
363
+ if (arg === "-bd" || arg === "--biz-domain") {
364
+ businessDomain = args[i + 1] ?? "bd_public";
365
+ if (!businessDomain || businessDomain.startsWith("-")) {
366
+ throw new Error("Missing value for biz-domain flag");
367
+ }
368
+ i += 1;
369
+ continue;
370
+ }
371
+ if (arg === "--pretty") {
372
+ pretty = true;
373
+ continue;
374
+ }
375
+ if (!arg.startsWith("-") && !directory) {
376
+ directory = arg;
377
+ continue;
378
+ }
379
+ throw new Error(`Unsupported bkn push argument: ${arg}`);
380
+ }
381
+ if (!directory) {
382
+ throw new Error("Missing directory. Usage: kweaver bkn push <directory> [--branch main] [-bd value]");
383
+ }
384
+ return { directory, branch, businessDomain, pretty };
385
+ }
386
+ export function parseKnPullArgs(args) {
387
+ let knId = "";
388
+ let directory = "";
389
+ let branch = "main";
390
+ let businessDomain = "bd_public";
391
+ for (let i = 0; i < args.length; i += 1) {
392
+ const arg = args[i];
393
+ if (arg === "--help" || arg === "-h") {
394
+ throw new Error("help");
395
+ }
396
+ if (arg === "--branch") {
397
+ branch = args[i + 1] ?? "main";
398
+ if (!branch || branch.startsWith("-")) {
399
+ throw new Error("Missing value for --branch");
400
+ }
401
+ i += 1;
402
+ continue;
403
+ }
404
+ if (arg === "-bd" || arg === "--biz-domain") {
405
+ businessDomain = args[i + 1] ?? "bd_public";
406
+ if (!businessDomain || businessDomain.startsWith("-")) {
407
+ throw new Error("Missing value for biz-domain flag");
408
+ }
409
+ i += 1;
410
+ continue;
411
+ }
412
+ if (!arg.startsWith("-")) {
413
+ if (!knId) {
414
+ knId = arg;
415
+ }
416
+ else if (!directory) {
417
+ directory = arg;
418
+ }
419
+ else {
420
+ throw new Error(`Unexpected positional argument: ${arg}`);
421
+ }
422
+ continue;
423
+ }
424
+ throw new Error(`Unsupported bkn pull argument: ${arg}`);
425
+ }
426
+ if (!knId) {
427
+ throw new Error("Missing kn-id. Usage: kweaver bkn pull <kn-id> [<directory>] [--branch main] [-bd value]");
428
+ }
429
+ return { knId, directory: directory || knId, branch, businessDomain };
430
+ }
341
431
  function parseJsonObject(text, errorMessage) {
342
432
  let parsed;
343
433
  try {
@@ -443,6 +533,8 @@ Subcommands:
443
533
  update <kn-id> [options] Update a knowledge network
444
534
  delete <kn-id> Delete a knowledge network
445
535
  build <kn-id> [--wait|--no-wait] [--timeout n] Trigger full build
536
+ push <directory> [--branch main] Upload BKN directory as tar
537
+ pull <kn-id> [<directory>] [--branch main] Download BKN tar and extract
446
538
  export <kn-id> Export knowledge network (alias for get --export)
447
539
  stats <kn-id> Get statistics (alias for get --stats)
448
540
  search <kn-id> <query> [options] Semantic search within a knowledge network
@@ -452,7 +544,7 @@ Subcommands:
452
544
  object-type update <kn-id> <ot-id> [options] Update object type
453
545
  object-type delete <kn-id> <ot-ids> [-y] Delete object type(s)
454
546
  object-type query <kn-id> <ot-id> ['<json>'] Query object instances (ontology-query; supports --limit/--search-after)
455
- object-type properties <kn-id> <ot-id> '<json>' Query object properties
547
+ object-type properties <kn-id> <ot-id> '<json>' Query instance properties (json: {"_instance_identities":[{pk:val}],"properties":[...]})
456
548
  relation-type list <kn-id> List relation types (schema)
457
549
  relation-type get <kn-id> <rt-id> Get relation type details
458
550
  relation-type create <kn-id> [options] Create relation type (--name --source --target [--mapping src:tgt])
@@ -495,6 +587,12 @@ export async function runKnCommand(args) {
495
587
  if (subcommand === "build") {
496
588
  return runKnBuildCommand(rest);
497
589
  }
590
+ if (subcommand === "push") {
591
+ return runKnPushCommand(rest);
592
+ }
593
+ if (subcommand === "pull") {
594
+ return runKnPullCommand(rest);
595
+ }
498
596
  if (subcommand === "export") {
499
597
  return runKnGetCommand([...(rest[0] ? [rest[0]] : []), "--export", ...rest.slice(1)]);
500
598
  }
@@ -791,7 +889,9 @@ kweaver bkn object-type properties <kn-id> <ot-id> '<json>' [--pretty] [-bd valu
791
889
  list: List object types (schema) from ontology-manager.
792
890
  get: Get single object type details.
793
891
  create/update/delete: Schema CRUD (create requires dataview-id).
794
- query/properties: Query via ontology-query API. For query, --limit and --search-after are merged into the JSON body.`);
892
+ query/properties: Query via ontology-query API. For query, --limit and --search-after are merged into the JSON body.
893
+
894
+ properties JSON format: {"_instance_identities":[{"<primary-key>":"<value>"}],"properties":["prop1","prop2"]}`);
795
895
  return 0;
796
896
  }
797
897
  try {
@@ -896,7 +996,8 @@ query/properties: Query via ontology-query API. For query, --limit and --search-
896
996
  const parsed = parseOntologyQueryFlags(rest);
897
997
  const [knId, otId, body] = parsed.filteredArgs;
898
998
  if (!knId || !otId || !body) {
899
- console.error("Usage: kweaver bkn object-type properties <kn-id> <ot-id> '<json>' [options]");
999
+ console.error(`Usage: kweaver bkn object-type properties <kn-id> <ot-id> '<json>' [options]
1000
+ JSON: {"_instance_identities":[{"<primary-key>":"<value>"}],"properties":["prop1","prop2"]}`);
900
1001
  return 1;
901
1002
  }
902
1003
  const token = await ensureValidToken();
@@ -1189,6 +1290,17 @@ Query subgraph via ontology-query API. JSON body format see references/json-form
1189
1290
  return 1;
1190
1291
  }
1191
1292
  try {
1293
+ // Auto-detect query_type=relation_path when body contains source_object_type_id
1294
+ let queryType;
1295
+ try {
1296
+ const parsedBody = JSON.parse(body);
1297
+ if (parsedBody.source_object_type_id) {
1298
+ queryType = "relation_path";
1299
+ }
1300
+ }
1301
+ catch {
1302
+ // Not valid JSON — let the API return the error
1303
+ }
1192
1304
  const token = await ensureValidToken();
1193
1305
  const result = await subgraph({
1194
1306
  baseUrl: token.baseUrl,
@@ -1196,6 +1308,7 @@ Query subgraph via ontology-query API. JSON body format see references/json-form
1196
1308
  knId,
1197
1309
  body,
1198
1310
  businessDomain,
1311
+ queryType,
1199
1312
  });
1200
1313
  console.log(formatCallOutput(result, pretty));
1201
1314
  return 0;
@@ -2048,6 +2161,148 @@ async function runKnBuildCommand(args) {
2048
2161
  return 1;
2049
2162
  }
2050
2163
  }
2164
+ // ── push / pull (BKN tar import/export) ──────────────────────────────────────
2165
+ export function packDirectoryToTar(dirPath) {
2166
+ const absPath = resolve(dirPath);
2167
+ const entries = readdirSync(absPath);
2168
+ const args = ["cf", "-", "-C", absPath, ...entries];
2169
+ const result = spawnSync("tar", args, {
2170
+ encoding: "buffer",
2171
+ env: { ...process.env, COPYFILE_DISABLE: "1" },
2172
+ });
2173
+ if (result.error)
2174
+ throw result.error;
2175
+ if (result.status !== 0) {
2176
+ throw new Error(`tar pack failed: ${result.stderr?.toString() ?? result.status}`);
2177
+ }
2178
+ return result.stdout;
2179
+ }
2180
+ export function extractTarToDirectory(tarBuffer, dirPath) {
2181
+ const absPath = resolve(dirPath);
2182
+ mkdirSync(absPath, { recursive: true });
2183
+ const result = spawnSync("tar", ["xf", "-", "-C", absPath], {
2184
+ input: tarBuffer,
2185
+ });
2186
+ if (result.error) {
2187
+ throw result.error;
2188
+ }
2189
+ if (result.status !== 0) {
2190
+ throw new Error(`tar extract failed: ${result.stderr?.toString() ?? result.status}`);
2191
+ }
2192
+ }
2193
+ const KN_PUSH_HELP = `kweaver bkn push <directory> [options]
2194
+
2195
+ Pack a BKN directory into a tar and upload to import as a knowledge network.
2196
+
2197
+ Options:
2198
+ --branch <s> Branch name (default: main)
2199
+ -bd, --biz-domain Business domain (default: bd_public)
2200
+ --pretty Pretty-print JSON output`;
2201
+ const KN_PULL_HELP = `kweaver bkn pull <kn-id> [<directory>] [options]
2202
+
2203
+ Download a BKN tar from a knowledge network and extract to a local directory.
2204
+
2205
+ Options:
2206
+ <directory> Output directory (default: <kn-id>)
2207
+ --branch <s> Branch name (default: main)
2208
+ -bd, --biz-domain Business domain (default: bd_public)`;
2209
+ async function runKnPushCommand(args) {
2210
+ let options;
2211
+ try {
2212
+ options = parseKnPushArgs(args);
2213
+ }
2214
+ catch (error) {
2215
+ if (error instanceof Error && error.message === "help") {
2216
+ console.log(KN_PUSH_HELP);
2217
+ return 0;
2218
+ }
2219
+ console.error(formatHttpError(error));
2220
+ return 1;
2221
+ }
2222
+ const absDir = resolve(options.directory);
2223
+ try {
2224
+ const stat = statSync(absDir);
2225
+ if (!stat.isDirectory()) {
2226
+ console.error(`Not a directory: ${options.directory}`);
2227
+ return 1;
2228
+ }
2229
+ }
2230
+ catch (err) {
2231
+ if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
2232
+ console.error(`Directory not found: ${options.directory}`);
2233
+ return 1;
2234
+ }
2235
+ throw err;
2236
+ }
2237
+ try {
2238
+ const network = await loadNetwork(absDir);
2239
+ const objs = allObjects(network);
2240
+ const rels = allRelations(network);
2241
+ const acts = allActions(network);
2242
+ console.error(`Validated: ${objs.length} object types, ${rels.length} relation types, ${acts.length} action types`);
2243
+ }
2244
+ catch (error) {
2245
+ console.error(`BKN validation failed: ${error instanceof Error ? error.message : String(error)}`);
2246
+ return 1;
2247
+ }
2248
+ try {
2249
+ await generateChecksum(absDir);
2250
+ console.error("Checksum generated");
2251
+ }
2252
+ catch (error) {
2253
+ console.error(`Checksum generation failed: ${error instanceof Error ? error.message : String(error)}`);
2254
+ return 1;
2255
+ }
2256
+ try {
2257
+ const tarBuffer = packDirectoryToTar(absDir);
2258
+ const token = await ensureValidToken();
2259
+ const body = await uploadBkn({
2260
+ baseUrl: token.baseUrl,
2261
+ accessToken: token.accessToken,
2262
+ tarBuffer,
2263
+ businessDomain: options.businessDomain,
2264
+ branch: options.branch,
2265
+ });
2266
+ console.log(formatCallOutput(body, options.pretty));
2267
+ return 0;
2268
+ }
2269
+ catch (error) {
2270
+ console.error(formatHttpError(error));
2271
+ return 1;
2272
+ }
2273
+ }
2274
+ async function runKnPullCommand(args) {
2275
+ let options;
2276
+ try {
2277
+ options = parseKnPullArgs(args);
2278
+ }
2279
+ catch (error) {
2280
+ if (error instanceof Error && error.message === "help") {
2281
+ console.log(KN_PULL_HELP);
2282
+ return 0;
2283
+ }
2284
+ console.error(formatHttpError(error));
2285
+ return 1;
2286
+ }
2287
+ try {
2288
+ const token = await ensureValidToken();
2289
+ const tarBuffer = await downloadBkn({
2290
+ baseUrl: token.baseUrl,
2291
+ accessToken: token.accessToken,
2292
+ knId: options.knId,
2293
+ businessDomain: options.businessDomain,
2294
+ branch: options.branch,
2295
+ });
2296
+ const absDir = resolve(options.directory);
2297
+ extractTarToDirectory(tarBuffer, absDir);
2298
+ console.log(`Extracted to ${absDir}`);
2299
+ return 0;
2300
+ }
2301
+ catch (error) {
2302
+ console.error(formatHttpError(error));
2303
+ return 1;
2304
+ }
2305
+ }
2051
2306
  // ── search ──────────────────────────────────────────────────────────────────
2052
2307
  const KN_SEARCH_HELP = `kweaver bkn search <kn-id> <query> [--max-concepts <n>] [--mode <mode>] [--pretty] [-bd value]
2053
2308
 
@@ -42,7 +42,7 @@ export function parseCallArgs(args) {
42
42
  pretty = true;
43
43
  continue;
44
44
  }
45
- if (arg === "--verbose") {
45
+ if (arg === "-v" || arg === "--verbose") {
46
46
  verbose = true;
47
47
  continue;
48
48
  }
@@ -113,6 +113,21 @@ export function formatVerboseRequest(invocation) {
113
113
  return lines;
114
114
  }
115
115
  export async function runCallCommand(args) {
116
+ if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
117
+ console.log(`kweaver call <url> [-X METHOD] [-H "Name: value"] [-d BODY] [--pretty] [--verbose] [-bd value]
118
+
119
+ Call an API with curl-style flags and auto-injected token headers.
120
+
121
+ Options:
122
+ <url> API path (e.g. /api/ontology-manager/v1/knowledge-networks)
123
+ -X, --request HTTP method (default: GET)
124
+ -H, --header Extra header (repeatable)
125
+ -d, --data JSON request body
126
+ -bd, --biz-domain Override x-business-domain (default: bd_public)
127
+ -v, --verbose Print request info to stderr
128
+ --pretty Pretty-print JSON output (default)`);
129
+ return 0;
130
+ }
116
131
  let invocation;
117
132
  try {
118
133
  invocation = parseCallArgs(args);
@@ -123,6 +138,10 @@ export async function runCallCommand(args) {
123
138
  }
124
139
  try {
125
140
  const token = await ensureValidToken();
141
+ // Prepend baseUrl when the URL is a relative path (no scheme)
142
+ if (invocation.url.startsWith("/")) {
143
+ invocation.url = token.baseUrl.replace(/\/+$/, "") + invocation.url;
144
+ }
126
145
  injectAuthHeaders(invocation.headers, token.accessToken, invocation.businessDomain);
127
146
  if (invocation.verbose) {
128
147
  for (const line of formatVerboseRequest(invocation)) {
@@ -0,0 +1 @@
1
+ export declare function runVegaCommand(args: string[]): Promise<number>;