@kweaver-ai/kweaver-sdk 0.4.0 → 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.
- package/README.md +139 -0
- package/README.zh.md +139 -0
- package/dist/api/agent-list.d.ts +51 -0
- package/dist/api/agent-list.js +116 -7
- package/dist/api/bkn-backend.d.ts +16 -0
- package/dist/api/bkn-backend.js +46 -0
- package/dist/api/datasources.d.ts +73 -0
- package/dist/api/datasources.js +218 -0
- package/dist/api/dataviews.d.ts +20 -0
- package/dist/api/dataviews.js +72 -0
- package/dist/api/knowledge-networks.d.ts +84 -0
- package/dist/api/knowledge-networks.js +167 -0
- package/dist/api/ontology-query.d.ts +1 -1
- package/dist/api/ontology-query.js +1 -0
- package/dist/api/vega.d.ts +110 -0
- package/dist/api/vega.js +251 -0
- package/dist/auth/oauth.d.ts +3 -1
- package/dist/auth/oauth.js +12 -9
- package/dist/cli.js +15 -0
- package/dist/client.d.ts +19 -0
- package/dist/client.js +76 -13
- package/dist/commands/agent.d.ts +7 -0
- package/dist/commands/agent.js +392 -13
- package/dist/commands/bkn.d.ts +22 -0
- package/dist/commands/bkn.js +1057 -41
- package/dist/commands/call.js +20 -1
- package/dist/commands/context-loader.js +4 -4
- package/dist/commands/ds.d.ts +7 -0
- package/dist/commands/ds.js +283 -0
- package/dist/commands/vega.d.ts +1 -0
- package/dist/commands/vega.js +663 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/resources/agents.d.ts +83 -9
- package/dist/resources/agents.js +46 -10
- package/dist/resources/bkn.d.ts +12 -0
- package/dist/resources/bkn.js +12 -0
- package/dist/resources/knowledge-networks.js +19 -58
- package/dist/utils/crypto.d.ts +10 -0
- package/dist/utils/crypto.js +31 -0
- package/package.json +4 -2
package/dist/commands/bkn.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { createInterface } from "node:readline";
|
|
2
|
-
import {
|
|
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
|
-
import { listKnowledgeNetworks, getKnowledgeNetwork, createKnowledgeNetwork, updateKnowledgeNetwork, deleteKnowledgeNetwork, listObjectTypes, listRelationTypes, listActionTypes, } from "../api/knowledge-networks.js";
|
|
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";
|
|
10
|
+
import { listTablesWithColumns } from "../api/datasources.js";
|
|
11
|
+
import { createDataView } from "../api/dataviews.js";
|
|
12
|
+
import { downloadBkn, uploadBkn } from "../api/bkn-backend.js";
|
|
7
13
|
import { formatCallOutput } from "./call.js";
|
|
8
14
|
export function formatSimpleKnList(text, pretty, includeDetail = false) {
|
|
9
15
|
const parsed = JSON.parse(text);
|
|
@@ -336,6 +342,92 @@ export function parseKnDeleteArgs(args) {
|
|
|
336
342
|
}
|
|
337
343
|
return { knId, businessDomain, yes };
|
|
338
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
|
+
}
|
|
339
431
|
function parseJsonObject(text, errorMessage) {
|
|
340
432
|
let parsed;
|
|
341
433
|
try {
|
|
@@ -436,16 +528,28 @@ const KN_HELP = `kweaver bkn
|
|
|
436
528
|
Subcommands:
|
|
437
529
|
list [options] List business knowledge networks
|
|
438
530
|
get <kn-id> [options] Get knowledge network detail (use --stats or --export)
|
|
439
|
-
create [options] Create a knowledge network
|
|
531
|
+
create [options] Create a knowledge network (empty or from --body-file)
|
|
532
|
+
create-from-ds <ds-id> --name X [--tables a,b] [--build] Create KN from datasource
|
|
440
533
|
update <kn-id> [options] Update a knowledge network
|
|
441
534
|
delete <kn-id> Delete a knowledge network
|
|
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
|
|
442
538
|
export <kn-id> Export knowledge network (alias for get --export)
|
|
443
539
|
stats <kn-id> Get statistics (alias for get --stats)
|
|
444
540
|
search <kn-id> <query> [options] Semantic search within a knowledge network
|
|
445
541
|
object-type list <kn-id> List object types (schema)
|
|
542
|
+
object-type get <kn-id> <ot-id> Get object type details
|
|
543
|
+
object-type create <kn-id> [options] Create object type (--name --dataview-id --primary-key --display-key)
|
|
544
|
+
object-type update <kn-id> <ot-id> [options] Update object type
|
|
545
|
+
object-type delete <kn-id> <ot-ids> [-y] Delete object type(s)
|
|
446
546
|
object-type query <kn-id> <ot-id> ['<json>'] Query object instances (ontology-query; supports --limit/--search-after)
|
|
447
|
-
object-type properties <kn-id> <ot-id> '<json>' Query
|
|
547
|
+
object-type properties <kn-id> <ot-id> '<json>' Query instance properties (json: {"_instance_identities":[{pk:val}],"properties":[...]})
|
|
448
548
|
relation-type list <kn-id> List relation types (schema)
|
|
549
|
+
relation-type get <kn-id> <rt-id> Get relation type details
|
|
550
|
+
relation-type create <kn-id> [options] Create relation type (--name --source --target [--mapping src:tgt])
|
|
551
|
+
relation-type update <kn-id> <rt-id> [options] Update relation type
|
|
552
|
+
relation-type delete <kn-id> <rt-ids> [-y] Delete relation type(s)
|
|
449
553
|
subgraph <kn-id> '<json>' Query subgraph
|
|
450
554
|
action-type list <kn-id> List action types (schema)
|
|
451
555
|
action-type query <kn-id> <at-id> '<json>' Query action info
|
|
@@ -471,12 +575,24 @@ export async function runKnCommand(args) {
|
|
|
471
575
|
if (subcommand === "create") {
|
|
472
576
|
return runKnCreateCommand(rest);
|
|
473
577
|
}
|
|
578
|
+
if (subcommand === "create-from-ds") {
|
|
579
|
+
return runKnCreateFromDsCommand(rest);
|
|
580
|
+
}
|
|
474
581
|
if (subcommand === "update") {
|
|
475
582
|
return runKnUpdateCommand(rest);
|
|
476
583
|
}
|
|
477
584
|
if (subcommand === "delete") {
|
|
478
585
|
return runKnDeleteCommand(rest);
|
|
479
586
|
}
|
|
587
|
+
if (subcommand === "build") {
|
|
588
|
+
return runKnBuildCommand(rest);
|
|
589
|
+
}
|
|
590
|
+
if (subcommand === "push") {
|
|
591
|
+
return runKnPushCommand(rest);
|
|
592
|
+
}
|
|
593
|
+
if (subcommand === "pull") {
|
|
594
|
+
return runKnPullCommand(rest);
|
|
595
|
+
}
|
|
480
596
|
if (subcommand === "export") {
|
|
481
597
|
return runKnGetCommand([...(rest[0] ? [rest[0]] : []), "--export", ...rest.slice(1)]);
|
|
482
598
|
}
|
|
@@ -507,6 +623,150 @@ export async function runKnCommand(args) {
|
|
|
507
623
|
console.error(`Unknown bkn subcommand: ${subcommand}`);
|
|
508
624
|
return 1;
|
|
509
625
|
}
|
|
626
|
+
/** Parse object-type create args: --name --dataview-id --primary-key --display-key [--property '<json>' ...] */
|
|
627
|
+
function parseObjectTypeCreateArgs(args) {
|
|
628
|
+
let name = "";
|
|
629
|
+
let dataviewId = "";
|
|
630
|
+
let primaryKey = "";
|
|
631
|
+
let displayKey = "";
|
|
632
|
+
let businessDomain = "bd_public";
|
|
633
|
+
let branch = "main";
|
|
634
|
+
let pretty = true;
|
|
635
|
+
const properties = [];
|
|
636
|
+
const positional = [];
|
|
637
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
638
|
+
const arg = args[i];
|
|
639
|
+
if (arg === "--help" || arg === "-h")
|
|
640
|
+
throw new Error("help");
|
|
641
|
+
if (arg === "--name" && args[i + 1]) {
|
|
642
|
+
name = args[++i];
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
645
|
+
if (arg === "--dataview-id" && args[i + 1]) {
|
|
646
|
+
dataviewId = args[++i];
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
if (arg === "--primary-key" && args[i + 1]) {
|
|
650
|
+
primaryKey = args[++i];
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
if (arg === "--display-key" && args[i + 1]) {
|
|
654
|
+
displayKey = args[++i];
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
if (arg === "--property" && args[i + 1]) {
|
|
658
|
+
properties.push(args[++i]);
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
662
|
+
businessDomain = args[++i];
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
if (arg === "--branch" && args[i + 1]) {
|
|
666
|
+
branch = args[++i];
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
if (arg === "--pretty") {
|
|
670
|
+
pretty = true;
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
if (!arg.startsWith("-"))
|
|
674
|
+
positional.push(arg);
|
|
675
|
+
}
|
|
676
|
+
const knId = positional[0];
|
|
677
|
+
if (!knId || !name || !dataviewId || !primaryKey || !displayKey) {
|
|
678
|
+
throw new Error("Usage: kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W");
|
|
679
|
+
}
|
|
680
|
+
const entry = {
|
|
681
|
+
name,
|
|
682
|
+
data_source: { type: "data_view", id: dataviewId },
|
|
683
|
+
primary_keys: [primaryKey],
|
|
684
|
+
display_key: displayKey,
|
|
685
|
+
};
|
|
686
|
+
if (properties.length > 0) {
|
|
687
|
+
entry.data_properties = properties.map((p) => JSON.parse(p));
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
const autoProps = new Set([primaryKey, displayKey]);
|
|
691
|
+
entry.data_properties = Array.from(autoProps).map((n) => ({
|
|
692
|
+
name: n,
|
|
693
|
+
display_name: n,
|
|
694
|
+
type: "string",
|
|
695
|
+
}));
|
|
696
|
+
}
|
|
697
|
+
const body = JSON.stringify({ entries: [entry], branch });
|
|
698
|
+
return { knId, body, businessDomain, branch, pretty };
|
|
699
|
+
}
|
|
700
|
+
/** Parse object-type update args: --name X [--display-key Y] */
|
|
701
|
+
function parseObjectTypeUpdateArgs(args) {
|
|
702
|
+
let name;
|
|
703
|
+
let displayKey;
|
|
704
|
+
let businessDomain = "bd_public";
|
|
705
|
+
let pretty = true;
|
|
706
|
+
const positional = [];
|
|
707
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
708
|
+
const arg = args[i];
|
|
709
|
+
if (arg === "--help" || arg === "-h")
|
|
710
|
+
throw new Error("help");
|
|
711
|
+
if (arg === "--name" && args[i + 1]) {
|
|
712
|
+
name = args[++i];
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
if (arg === "--display-key" && args[i + 1]) {
|
|
716
|
+
displayKey = args[++i];
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
720
|
+
businessDomain = args[++i];
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
if (arg === "--pretty") {
|
|
724
|
+
pretty = true;
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
if (!arg.startsWith("-"))
|
|
728
|
+
positional.push(arg);
|
|
729
|
+
}
|
|
730
|
+
const [knId, otId] = positional;
|
|
731
|
+
if (!knId || !otId) {
|
|
732
|
+
throw new Error("Usage: kweaver bkn object-type update <kn-id> <ot-id> [--name X] [--display-key Y]");
|
|
733
|
+
}
|
|
734
|
+
const payload = {};
|
|
735
|
+
if (name !== undefined)
|
|
736
|
+
payload.name = name;
|
|
737
|
+
if (displayKey !== undefined)
|
|
738
|
+
payload.display_key = displayKey;
|
|
739
|
+
if (Object.keys(payload).length === 0) {
|
|
740
|
+
throw new Error("No update fields. Use --name or --display-key.");
|
|
741
|
+
}
|
|
742
|
+
return { knId, otId, body: JSON.stringify(payload), businessDomain, pretty };
|
|
743
|
+
}
|
|
744
|
+
/** Parse object-type delete args: <kn-id> <ot-ids> [-y] */
|
|
745
|
+
function parseObjectTypeDeleteArgs(args) {
|
|
746
|
+
let businessDomain = "bd_public";
|
|
747
|
+
let yes = false;
|
|
748
|
+
const positional = [];
|
|
749
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
750
|
+
const arg = args[i];
|
|
751
|
+
if (arg === "--help" || arg === "-h")
|
|
752
|
+
throw new Error("help");
|
|
753
|
+
if (arg === "--yes" || arg === "-y") {
|
|
754
|
+
yes = true;
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
758
|
+
businessDomain = args[++i];
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
if (!arg.startsWith("-"))
|
|
762
|
+
positional.push(arg);
|
|
763
|
+
}
|
|
764
|
+
const [knId, otIds] = positional;
|
|
765
|
+
if (!knId || !otIds) {
|
|
766
|
+
throw new Error("Usage: kweaver bkn object-type delete <kn-id> <ot-ids> [-y]");
|
|
767
|
+
}
|
|
768
|
+
return { knId, otIds, businessDomain, yes };
|
|
769
|
+
}
|
|
510
770
|
/** Parse common flags for ontology-query subcommands; returns { filteredArgs, pretty, businessDomain } */
|
|
511
771
|
function parseOntologyQueryFlags(args) {
|
|
512
772
|
let pretty = true;
|
|
@@ -581,18 +841,126 @@ export function parseKnActionTypeExecuteArgs(args) {
|
|
|
581
841
|
timeout,
|
|
582
842
|
};
|
|
583
843
|
}
|
|
844
|
+
const PK_CANDIDATES = new Set(["id", "pk", "key"]);
|
|
845
|
+
const PK_TYPES = new Set(["integer", "unsigned integer", "string", "varchar", "bigint", "int"]);
|
|
846
|
+
const DISPLAY_HINTS = ["name", "title", "label", "display_name", "description"];
|
|
847
|
+
function detectPrimaryKey(table) {
|
|
848
|
+
for (const col of table.columns) {
|
|
849
|
+
if (PK_CANDIDATES.has(col.name.toLowerCase()) && PK_TYPES.has(col.type.toLowerCase())) {
|
|
850
|
+
return col.name;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
for (const col of table.columns) {
|
|
854
|
+
if (PK_TYPES.has(col.type.toLowerCase())) {
|
|
855
|
+
return col.name;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return table.columns[0]?.name ?? "id";
|
|
859
|
+
}
|
|
860
|
+
function detectDisplayKey(table, primaryKey) {
|
|
861
|
+
for (const col of table.columns) {
|
|
862
|
+
if (DISPLAY_HINTS.some((h) => col.name.toLowerCase().includes(h))) {
|
|
863
|
+
return col.name;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return primaryKey;
|
|
867
|
+
}
|
|
868
|
+
function confirmYes(prompt) {
|
|
869
|
+
return new Promise((resolve) => {
|
|
870
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
871
|
+
rl.question(`${prompt} [y/N] `, (answer) => {
|
|
872
|
+
rl.close();
|
|
873
|
+
const trimmed = answer.trim().toLowerCase();
|
|
874
|
+
resolve(trimmed === "y" || trimmed === "yes");
|
|
875
|
+
});
|
|
876
|
+
});
|
|
877
|
+
}
|
|
584
878
|
async function runKnObjectTypeCommand(args) {
|
|
585
879
|
const [action, ...rest] = args;
|
|
586
880
|
if (!action || action === "--help" || action === "-h") {
|
|
587
881
|
console.log(`kweaver bkn object-type list <kn-id> [--pretty] [-bd value]
|
|
882
|
+
kweaver bkn object-type get <kn-id> <ot-id> [--pretty] [-bd value]
|
|
883
|
+
kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W [--property '<json>' ...]
|
|
884
|
+
kweaver bkn object-type update <kn-id> <ot-id> [--name X] [--display-key Y]
|
|
885
|
+
kweaver bkn object-type delete <kn-id> <ot-ids> [-y]
|
|
588
886
|
kweaver bkn object-type query <kn-id> <ot-id> ['<json>'] [--limit <n>] [--search-after '<json-array>'] [--pretty] [-bd value]
|
|
589
887
|
kweaver bkn object-type properties <kn-id> <ot-id> '<json>' [--pretty] [-bd value]
|
|
590
888
|
|
|
591
889
|
list: List object types (schema) from ontology-manager.
|
|
592
|
-
|
|
890
|
+
get: Get single object type details.
|
|
891
|
+
create/update/delete: Schema CRUD (create requires dataview-id).
|
|
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"]}`);
|
|
593
895
|
return 0;
|
|
594
896
|
}
|
|
595
897
|
try {
|
|
898
|
+
if (action === "get") {
|
|
899
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
900
|
+
const [knId, otId] = parsed.filteredArgs;
|
|
901
|
+
if (!knId || !otId) {
|
|
902
|
+
console.error("Usage: kweaver bkn object-type get <kn-id> <ot-id> [options]");
|
|
903
|
+
return 1;
|
|
904
|
+
}
|
|
905
|
+
const token = await ensureValidToken();
|
|
906
|
+
const body = await getObjectType({
|
|
907
|
+
baseUrl: token.baseUrl,
|
|
908
|
+
accessToken: token.accessToken,
|
|
909
|
+
knId,
|
|
910
|
+
otId,
|
|
911
|
+
businessDomain: parsed.businessDomain,
|
|
912
|
+
});
|
|
913
|
+
console.log(formatCallOutput(body, parsed.pretty));
|
|
914
|
+
return 0;
|
|
915
|
+
}
|
|
916
|
+
if (action === "create") {
|
|
917
|
+
const opts = parseObjectTypeCreateArgs(rest);
|
|
918
|
+
const token = await ensureValidToken();
|
|
919
|
+
const body = await createObjectTypes({
|
|
920
|
+
baseUrl: token.baseUrl,
|
|
921
|
+
accessToken: token.accessToken,
|
|
922
|
+
knId: opts.knId,
|
|
923
|
+
body: opts.body,
|
|
924
|
+
businessDomain: opts.businessDomain,
|
|
925
|
+
branch: opts.branch,
|
|
926
|
+
});
|
|
927
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
928
|
+
return 0;
|
|
929
|
+
}
|
|
930
|
+
if (action === "update") {
|
|
931
|
+
const opts = parseObjectTypeUpdateArgs(rest);
|
|
932
|
+
const token = await ensureValidToken();
|
|
933
|
+
const body = await updateObjectType({
|
|
934
|
+
baseUrl: token.baseUrl,
|
|
935
|
+
accessToken: token.accessToken,
|
|
936
|
+
knId: opts.knId,
|
|
937
|
+
otId: opts.otId,
|
|
938
|
+
body: opts.body,
|
|
939
|
+
businessDomain: opts.businessDomain,
|
|
940
|
+
});
|
|
941
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
942
|
+
return 0;
|
|
943
|
+
}
|
|
944
|
+
if (action === "delete") {
|
|
945
|
+
const opts = parseObjectTypeDeleteArgs(rest);
|
|
946
|
+
if (!opts.yes) {
|
|
947
|
+
const confirmed = await confirmYes(`Delete object type(s) ${opts.otIds}?`);
|
|
948
|
+
if (!confirmed) {
|
|
949
|
+
console.error("Aborted.");
|
|
950
|
+
return 1;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
const token = await ensureValidToken();
|
|
954
|
+
await deleteObjectTypes({
|
|
955
|
+
baseUrl: token.baseUrl,
|
|
956
|
+
accessToken: token.accessToken,
|
|
957
|
+
knId: opts.knId,
|
|
958
|
+
otIds: opts.otIds,
|
|
959
|
+
businessDomain: opts.businessDomain,
|
|
960
|
+
});
|
|
961
|
+
console.log(`Deleted ${opts.otIds}`);
|
|
962
|
+
return 0;
|
|
963
|
+
}
|
|
596
964
|
if (action === "list") {
|
|
597
965
|
const parsed = parseOntologyQueryFlags(rest);
|
|
598
966
|
const [knId] = parsed.filteredArgs;
|
|
@@ -628,7 +996,8 @@ query/properties: Query via ontology-query API. For query, --limit and --search-
|
|
|
628
996
|
const parsed = parseOntologyQueryFlags(rest);
|
|
629
997
|
const [knId, otId, body] = parsed.filteredArgs;
|
|
630
998
|
if (!knId || !otId || !body) {
|
|
631
|
-
console.error(
|
|
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"]}`);
|
|
632
1001
|
return 1;
|
|
633
1002
|
}
|
|
634
1003
|
const token = await ensureValidToken();
|
|
@@ -643,44 +1012,255 @@ query/properties: Query via ontology-query API. For query, --limit and --search-
|
|
|
643
1012
|
console.log(formatCallOutput(result, parsed.pretty));
|
|
644
1013
|
return 0;
|
|
645
1014
|
}
|
|
646
|
-
console.error(`Unknown object-type action: ${action}. Use list, query, or properties.`);
|
|
1015
|
+
console.error(`Unknown object-type action: ${action}. Use list, get, create, update, delete, query, or properties.`);
|
|
1016
|
+
return 1;
|
|
1017
|
+
}
|
|
1018
|
+
catch (error) {
|
|
1019
|
+
if (error instanceof Error && error.message === "help") {
|
|
1020
|
+
console.log(`kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W [--property '<json>' ...]
|
|
1021
|
+
kweaver bkn object-type update <kn-id> <ot-id> [--name X] [--display-key Y]
|
|
1022
|
+
kweaver bkn object-type delete <kn-id> <ot-ids> [-y]`);
|
|
1023
|
+
return 0;
|
|
1024
|
+
}
|
|
1025
|
+
console.error(formatHttpError(error));
|
|
1026
|
+
return 1;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
/** Parse relation-type create args: --name --source --target [--mapping src:tgt ...] */
|
|
1030
|
+
function parseRelationTypeCreateArgs(args) {
|
|
1031
|
+
let name = "";
|
|
1032
|
+
let source = "";
|
|
1033
|
+
let target = "";
|
|
1034
|
+
let businessDomain = "bd_public";
|
|
1035
|
+
let branch = "main";
|
|
1036
|
+
let pretty = true;
|
|
1037
|
+
const mappings = [];
|
|
1038
|
+
const positional = [];
|
|
1039
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
1040
|
+
const arg = args[i];
|
|
1041
|
+
if (arg === "--help" || arg === "-h")
|
|
1042
|
+
throw new Error("help");
|
|
1043
|
+
if (arg === "--name" && args[i + 1]) {
|
|
1044
|
+
name = args[++i];
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
if (arg === "--source" && args[i + 1]) {
|
|
1048
|
+
source = args[++i];
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
1051
|
+
if (arg === "--target" && args[i + 1]) {
|
|
1052
|
+
target = args[++i];
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
if (arg === "--mapping" && args[i + 1]) {
|
|
1056
|
+
const m = args[++i];
|
|
1057
|
+
if (!m.includes(":")) {
|
|
1058
|
+
throw new Error(`Invalid mapping format '${m}'. Expected source_prop:target_prop.`);
|
|
1059
|
+
}
|
|
1060
|
+
const [s, t] = m.split(":", 2);
|
|
1061
|
+
mappings.push([s, t]);
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1065
|
+
businessDomain = args[++i];
|
|
1066
|
+
continue;
|
|
1067
|
+
}
|
|
1068
|
+
if (arg === "--branch" && args[i + 1]) {
|
|
1069
|
+
branch = args[++i];
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
if (arg === "--pretty") {
|
|
1073
|
+
pretty = true;
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
if (!arg.startsWith("-"))
|
|
1077
|
+
positional.push(arg);
|
|
1078
|
+
}
|
|
1079
|
+
const knId = positional[0];
|
|
1080
|
+
if (!knId || !name || !source || !target) {
|
|
1081
|
+
throw new Error("Usage: kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]");
|
|
1082
|
+
}
|
|
1083
|
+
const entry = {
|
|
1084
|
+
name,
|
|
1085
|
+
source_object_type_id: source,
|
|
1086
|
+
target_object_type_id: target,
|
|
1087
|
+
type: "direct",
|
|
1088
|
+
mapping_rules: mappings.map(([s, t]) => ({
|
|
1089
|
+
source_property: { name: s },
|
|
1090
|
+
target_property: { name: t },
|
|
1091
|
+
})),
|
|
1092
|
+
};
|
|
1093
|
+
const body = JSON.stringify({ entries: [entry], branch });
|
|
1094
|
+
return { knId, body, businessDomain, branch, pretty };
|
|
1095
|
+
}
|
|
1096
|
+
/** Parse relation-type update args: [--name X] */
|
|
1097
|
+
function parseRelationTypeUpdateArgs(args) {
|
|
1098
|
+
let name;
|
|
1099
|
+
let businessDomain = "bd_public";
|
|
1100
|
+
let pretty = true;
|
|
1101
|
+
const positional = [];
|
|
1102
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
1103
|
+
const arg = args[i];
|
|
1104
|
+
if (arg === "--help" || arg === "-h")
|
|
1105
|
+
throw new Error("help");
|
|
1106
|
+
if (arg === "--name" && args[i + 1]) {
|
|
1107
|
+
name = args[++i];
|
|
1108
|
+
continue;
|
|
1109
|
+
}
|
|
1110
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1111
|
+
businessDomain = args[++i];
|
|
1112
|
+
continue;
|
|
1113
|
+
}
|
|
1114
|
+
if (arg === "--pretty") {
|
|
1115
|
+
pretty = true;
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
if (!arg.startsWith("-"))
|
|
1119
|
+
positional.push(arg);
|
|
1120
|
+
}
|
|
1121
|
+
const [knId, rtId] = positional;
|
|
1122
|
+
if (!knId || !rtId) {
|
|
1123
|
+
throw new Error("Usage: kweaver bkn relation-type update <kn-id> <rt-id> [--name X]");
|
|
1124
|
+
}
|
|
1125
|
+
if (name === undefined) {
|
|
1126
|
+
throw new Error("No update fields. Use --name.");
|
|
1127
|
+
}
|
|
1128
|
+
return { knId, rtId, body: JSON.stringify({ name }), businessDomain, pretty };
|
|
1129
|
+
}
|
|
1130
|
+
/** Parse relation-type delete args: <kn-id> <rt-ids> [-y] */
|
|
1131
|
+
function parseRelationTypeDeleteArgs(args) {
|
|
1132
|
+
let businessDomain = "bd_public";
|
|
1133
|
+
let yes = false;
|
|
1134
|
+
const positional = [];
|
|
1135
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
1136
|
+
const arg = args[i];
|
|
1137
|
+
if (arg === "--help" || arg === "-h")
|
|
1138
|
+
throw new Error("help");
|
|
1139
|
+
if (arg === "--yes" || arg === "-y") {
|
|
1140
|
+
yes = true;
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1144
|
+
businessDomain = args[++i];
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
if (!arg.startsWith("-"))
|
|
1148
|
+
positional.push(arg);
|
|
1149
|
+
}
|
|
1150
|
+
const [knId, rtIds] = positional;
|
|
1151
|
+
if (!knId || !rtIds) {
|
|
1152
|
+
throw new Error("Usage: kweaver bkn relation-type delete <kn-id> <rt-ids> [-y]");
|
|
1153
|
+
}
|
|
1154
|
+
return { knId, rtIds, businessDomain, yes };
|
|
1155
|
+
}
|
|
1156
|
+
async function runKnRelationTypeCommand(args) {
|
|
1157
|
+
const [action, ...rest] = args;
|
|
1158
|
+
if (!action || action === "--help" || action === "-h") {
|
|
1159
|
+
console.log(`kweaver bkn relation-type list <kn-id> [--pretty] [-bd value]
|
|
1160
|
+
kweaver bkn relation-type get <kn-id> <rt-id> [--pretty] [-bd value]
|
|
1161
|
+
kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]
|
|
1162
|
+
kweaver bkn relation-type update <kn-id> <rt-id> [--name X]
|
|
1163
|
+
kweaver bkn relation-type delete <kn-id> <rt-ids> [-y]
|
|
1164
|
+
|
|
1165
|
+
list: List relation types (schema) from ontology-manager.
|
|
1166
|
+
get: Get single relation type details.
|
|
1167
|
+
create/update/delete: Schema CRUD.`);
|
|
1168
|
+
return 0;
|
|
1169
|
+
}
|
|
1170
|
+
try {
|
|
1171
|
+
if (action === "get") {
|
|
1172
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1173
|
+
const [knId, rtId] = parsed.filteredArgs;
|
|
1174
|
+
if (!knId || !rtId) {
|
|
1175
|
+
console.error("Usage: kweaver bkn relation-type get <kn-id> <rt-id> [options]");
|
|
1176
|
+
return 1;
|
|
1177
|
+
}
|
|
1178
|
+
const token = await ensureValidToken();
|
|
1179
|
+
const body = await getRelationType({
|
|
1180
|
+
baseUrl: token.baseUrl,
|
|
1181
|
+
accessToken: token.accessToken,
|
|
1182
|
+
knId,
|
|
1183
|
+
rtId,
|
|
1184
|
+
businessDomain: parsed.businessDomain,
|
|
1185
|
+
});
|
|
1186
|
+
console.log(formatCallOutput(body, parsed.pretty));
|
|
1187
|
+
return 0;
|
|
1188
|
+
}
|
|
1189
|
+
if (action === "create") {
|
|
1190
|
+
const opts = parseRelationTypeCreateArgs(rest);
|
|
1191
|
+
const token = await ensureValidToken();
|
|
1192
|
+
const body = await createRelationTypes({
|
|
1193
|
+
baseUrl: token.baseUrl,
|
|
1194
|
+
accessToken: token.accessToken,
|
|
1195
|
+
knId: opts.knId,
|
|
1196
|
+
body: opts.body,
|
|
1197
|
+
businessDomain: opts.businessDomain,
|
|
1198
|
+
branch: opts.branch,
|
|
1199
|
+
});
|
|
1200
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
1201
|
+
return 0;
|
|
1202
|
+
}
|
|
1203
|
+
if (action === "update") {
|
|
1204
|
+
const opts = parseRelationTypeUpdateArgs(rest);
|
|
1205
|
+
const token = await ensureValidToken();
|
|
1206
|
+
const body = await updateRelationType({
|
|
1207
|
+
baseUrl: token.baseUrl,
|
|
1208
|
+
accessToken: token.accessToken,
|
|
1209
|
+
knId: opts.knId,
|
|
1210
|
+
rtId: opts.rtId,
|
|
1211
|
+
body: opts.body,
|
|
1212
|
+
businessDomain: opts.businessDomain,
|
|
1213
|
+
});
|
|
1214
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
1215
|
+
return 0;
|
|
1216
|
+
}
|
|
1217
|
+
if (action === "delete") {
|
|
1218
|
+
const opts = parseRelationTypeDeleteArgs(rest);
|
|
1219
|
+
if (!opts.yes) {
|
|
1220
|
+
const confirmed = await confirmYes(`Delete relation type(s) ${opts.rtIds}?`);
|
|
1221
|
+
if (!confirmed) {
|
|
1222
|
+
console.error("Aborted.");
|
|
1223
|
+
return 1;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
const token = await ensureValidToken();
|
|
1227
|
+
await deleteRelationTypes({
|
|
1228
|
+
baseUrl: token.baseUrl,
|
|
1229
|
+
accessToken: token.accessToken,
|
|
1230
|
+
knId: opts.knId,
|
|
1231
|
+
rtIds: opts.rtIds,
|
|
1232
|
+
businessDomain: opts.businessDomain,
|
|
1233
|
+
});
|
|
1234
|
+
console.log(`Deleted ${opts.rtIds}`);
|
|
1235
|
+
return 0;
|
|
1236
|
+
}
|
|
1237
|
+
if (action === "list") {
|
|
1238
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1239
|
+
const [knId] = parsed.filteredArgs;
|
|
1240
|
+
if (!knId) {
|
|
1241
|
+
console.error("Usage: kweaver bkn relation-type list <kn-id> [options]");
|
|
1242
|
+
return 1;
|
|
1243
|
+
}
|
|
1244
|
+
const token = await ensureValidToken();
|
|
1245
|
+
const body = await listRelationTypes({
|
|
1246
|
+
baseUrl: token.baseUrl,
|
|
1247
|
+
accessToken: token.accessToken,
|
|
1248
|
+
knId,
|
|
1249
|
+
businessDomain: parsed.businessDomain,
|
|
1250
|
+
});
|
|
1251
|
+
console.log(formatCallOutput(body, parsed.pretty));
|
|
1252
|
+
return 0;
|
|
1253
|
+
}
|
|
1254
|
+
console.error(`Unknown relation-type action: ${action}. Use list, get, create, update, or delete.`);
|
|
647
1255
|
return 1;
|
|
648
1256
|
}
|
|
649
1257
|
catch (error) {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
const [action, ...rest] = args;
|
|
656
|
-
if (!action || action === "--help" || action === "-h") {
|
|
657
|
-
console.log(`kweaver bkn relation-type list <kn-id> [--pretty] [-bd value]
|
|
658
|
-
|
|
659
|
-
List relation types (schema) from ontology-manager.`);
|
|
660
|
-
return 0;
|
|
661
|
-
}
|
|
662
|
-
if (action !== "list") {
|
|
663
|
-
console.error(`Unknown relation-type action: ${action}. Use list.`);
|
|
664
|
-
return 1;
|
|
665
|
-
}
|
|
666
|
-
try {
|
|
667
|
-
const parsed = parseOntologyQueryFlags(rest);
|
|
668
|
-
const [knId] = parsed.filteredArgs;
|
|
669
|
-
if (!knId) {
|
|
670
|
-
console.error("Usage: kweaver bkn relation-type list <kn-id> [options]");
|
|
671
|
-
return 1;
|
|
1258
|
+
if (error instanceof Error && error.message === "help") {
|
|
1259
|
+
console.log(`kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]
|
|
1260
|
+
kweaver bkn relation-type update <kn-id> <rt-id> [--name X]
|
|
1261
|
+
kweaver bkn relation-type delete <kn-id> <rt-ids> [-y]`);
|
|
1262
|
+
return 0;
|
|
672
1263
|
}
|
|
673
|
-
const token = await ensureValidToken();
|
|
674
|
-
const body = await listRelationTypes({
|
|
675
|
-
baseUrl: token.baseUrl,
|
|
676
|
-
accessToken: token.accessToken,
|
|
677
|
-
knId,
|
|
678
|
-
businessDomain: parsed.businessDomain,
|
|
679
|
-
});
|
|
680
|
-
console.log(formatCallOutput(body, parsed.pretty));
|
|
681
|
-
return 0;
|
|
682
|
-
}
|
|
683
|
-
catch (error) {
|
|
684
1264
|
console.error(formatHttpError(error));
|
|
685
1265
|
return 1;
|
|
686
1266
|
}
|
|
@@ -699,7 +1279,7 @@ async function runKnSubgraphCommand(args) {
|
|
|
699
1279
|
if (error instanceof Error && error.message === "help") {
|
|
700
1280
|
console.log(`kweaver bkn subgraph <kn-id> '<json>' [--pretty] [-bd value]
|
|
701
1281
|
|
|
702
|
-
Query subgraph via ontology-query API. JSON body format see
|
|
1282
|
+
Query subgraph via ontology-query API. JSON body format see references/json-formats.md#subgraph.`);
|
|
703
1283
|
return 0;
|
|
704
1284
|
}
|
|
705
1285
|
throw error;
|
|
@@ -710,6 +1290,17 @@ Query subgraph via ontology-query API. JSON body format see ref/ontology/ontolog
|
|
|
710
1290
|
return 1;
|
|
711
1291
|
}
|
|
712
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
|
+
}
|
|
713
1304
|
const token = await ensureValidToken();
|
|
714
1305
|
const result = await subgraph({
|
|
715
1306
|
baseUrl: token.baseUrl,
|
|
@@ -717,6 +1308,7 @@ Query subgraph via ontology-query API. JSON body format see ref/ontology/ontolog
|
|
|
717
1308
|
knId,
|
|
718
1309
|
body,
|
|
719
1310
|
businessDomain,
|
|
1311
|
+
queryType,
|
|
720
1312
|
});
|
|
721
1313
|
console.log(formatCallOutput(result, pretty));
|
|
722
1314
|
return 0;
|
|
@@ -1210,6 +1802,183 @@ async function runKnCreateCommand(args) {
|
|
|
1210
1802
|
return 1;
|
|
1211
1803
|
}
|
|
1212
1804
|
}
|
|
1805
|
+
const KN_CREATE_FROM_DS_HELP = `kweaver bkn create-from-ds <ds-id> --name X [options]
|
|
1806
|
+
|
|
1807
|
+
Create a knowledge network from a datasource (dataviews + object types + optional build).
|
|
1808
|
+
|
|
1809
|
+
Options:
|
|
1810
|
+
--name <s> Knowledge network name (required)
|
|
1811
|
+
--tables <a,b> Comma-separated table names (default: all)
|
|
1812
|
+
--build (default) Build after creation
|
|
1813
|
+
--no-build Skip build after creation
|
|
1814
|
+
--timeout <n> Build timeout in seconds (default: 300)
|
|
1815
|
+
-bd, --biz-domain Business domain (default: bd_public)
|
|
1816
|
+
--pretty Pretty-print output (default)`;
|
|
1817
|
+
function parseKnCreateFromDsArgs(args) {
|
|
1818
|
+
let dsId = "";
|
|
1819
|
+
let name = "";
|
|
1820
|
+
let tablesStr = "";
|
|
1821
|
+
let build = true;
|
|
1822
|
+
let timeout = 300;
|
|
1823
|
+
let businessDomain = "bd_public";
|
|
1824
|
+
let pretty = true;
|
|
1825
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
1826
|
+
const arg = args[i];
|
|
1827
|
+
if (arg === "--help" || arg === "-h")
|
|
1828
|
+
throw new Error("help");
|
|
1829
|
+
if (arg === "--name" && args[i + 1]) {
|
|
1830
|
+
name = args[++i];
|
|
1831
|
+
continue;
|
|
1832
|
+
}
|
|
1833
|
+
if (arg === "--tables" && args[i + 1]) {
|
|
1834
|
+
tablesStr = args[++i];
|
|
1835
|
+
continue;
|
|
1836
|
+
}
|
|
1837
|
+
if (arg === "--build") {
|
|
1838
|
+
build = true;
|
|
1839
|
+
continue;
|
|
1840
|
+
}
|
|
1841
|
+
if (arg === "--no-build") {
|
|
1842
|
+
build = false;
|
|
1843
|
+
continue;
|
|
1844
|
+
}
|
|
1845
|
+
if (arg === "--timeout" && args[i + 1]) {
|
|
1846
|
+
timeout = parseInt(args[++i], 10);
|
|
1847
|
+
if (Number.isNaN(timeout) || timeout < 1)
|
|
1848
|
+
timeout = 300;
|
|
1849
|
+
continue;
|
|
1850
|
+
}
|
|
1851
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1852
|
+
businessDomain = args[++i];
|
|
1853
|
+
continue;
|
|
1854
|
+
}
|
|
1855
|
+
if (arg === "--pretty") {
|
|
1856
|
+
pretty = true;
|
|
1857
|
+
continue;
|
|
1858
|
+
}
|
|
1859
|
+
if (!arg.startsWith("-") && !dsId) {
|
|
1860
|
+
dsId = arg;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
const tables = tablesStr ? tablesStr.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
1864
|
+
if (!dsId || !name) {
|
|
1865
|
+
throw new Error("Usage: kweaver bkn create-from-ds <ds-id> --name X [options]");
|
|
1866
|
+
}
|
|
1867
|
+
return { dsId, name, tables, build, timeout, businessDomain, pretty };
|
|
1868
|
+
}
|
|
1869
|
+
async function runKnCreateFromDsCommand(args) {
|
|
1870
|
+
let options;
|
|
1871
|
+
try {
|
|
1872
|
+
options = parseKnCreateFromDsArgs(args);
|
|
1873
|
+
}
|
|
1874
|
+
catch (error) {
|
|
1875
|
+
if (error instanceof Error && error.message === "help") {
|
|
1876
|
+
console.log(KN_CREATE_FROM_DS_HELP);
|
|
1877
|
+
return 0;
|
|
1878
|
+
}
|
|
1879
|
+
console.error(formatHttpError(error));
|
|
1880
|
+
return 1;
|
|
1881
|
+
}
|
|
1882
|
+
try {
|
|
1883
|
+
const token = await ensureValidToken();
|
|
1884
|
+
const base = {
|
|
1885
|
+
baseUrl: token.baseUrl,
|
|
1886
|
+
accessToken: token.accessToken,
|
|
1887
|
+
businessDomain: options.businessDomain,
|
|
1888
|
+
};
|
|
1889
|
+
const tablesBody = await listTablesWithColumns({ ...base, id: options.dsId });
|
|
1890
|
+
const allTables = JSON.parse(tablesBody);
|
|
1891
|
+
const targetTables = options.tables.length > 0
|
|
1892
|
+
? allTables.filter((t) => options.tables.includes(t.name))
|
|
1893
|
+
: allTables;
|
|
1894
|
+
if (targetTables.length === 0) {
|
|
1895
|
+
console.error("No tables available");
|
|
1896
|
+
return 1;
|
|
1897
|
+
}
|
|
1898
|
+
const viewMap = {};
|
|
1899
|
+
for (const t of targetTables) {
|
|
1900
|
+
const dvId = await createDataView({
|
|
1901
|
+
...base,
|
|
1902
|
+
name: t.name,
|
|
1903
|
+
datasourceId: options.dsId,
|
|
1904
|
+
table: t.name,
|
|
1905
|
+
fields: t.columns.map((c) => ({ name: c.name, type: c.type })),
|
|
1906
|
+
});
|
|
1907
|
+
viewMap[t.name] = dvId;
|
|
1908
|
+
}
|
|
1909
|
+
const knBody = JSON.stringify({
|
|
1910
|
+
name: options.name,
|
|
1911
|
+
branch: "main",
|
|
1912
|
+
base_branch: "",
|
|
1913
|
+
});
|
|
1914
|
+
const knResponse = await createKnowledgeNetwork({
|
|
1915
|
+
...base,
|
|
1916
|
+
body: knBody,
|
|
1917
|
+
});
|
|
1918
|
+
const knParsed = JSON.parse(knResponse);
|
|
1919
|
+
const knItem = Array.isArray(knParsed) ? knParsed[0] : knParsed;
|
|
1920
|
+
const knId = String(knItem?.id ?? "");
|
|
1921
|
+
const otResults = [];
|
|
1922
|
+
for (const t of targetTables) {
|
|
1923
|
+
const pk = detectPrimaryKey(t);
|
|
1924
|
+
const dk = detectDisplayKey(t, pk);
|
|
1925
|
+
const entry = {
|
|
1926
|
+
name: t.name,
|
|
1927
|
+
data_source: { type: "data_view", id: viewMap[t.name] },
|
|
1928
|
+
primary_keys: [pk],
|
|
1929
|
+
display_key: dk,
|
|
1930
|
+
data_properties: [pk, dk].filter((x, i, a) => a.indexOf(x) === i).map((n) => ({
|
|
1931
|
+
name: n,
|
|
1932
|
+
display_name: n,
|
|
1933
|
+
type: "string",
|
|
1934
|
+
})),
|
|
1935
|
+
};
|
|
1936
|
+
const otBody = JSON.stringify({ entries: [entry], branch: "main" });
|
|
1937
|
+
const otResponse = await createObjectTypes({
|
|
1938
|
+
...base,
|
|
1939
|
+
knId,
|
|
1940
|
+
body: otBody,
|
|
1941
|
+
});
|
|
1942
|
+
const otParsed = JSON.parse(otResponse);
|
|
1943
|
+
const otItem = otParsed.entries?.[0];
|
|
1944
|
+
otResults.push({
|
|
1945
|
+
name: t.name,
|
|
1946
|
+
id: otItem?.id ?? "",
|
|
1947
|
+
field_count: t.columns.length,
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
let statusStr = "skipped";
|
|
1951
|
+
if (options.build) {
|
|
1952
|
+
console.error("Building ...");
|
|
1953
|
+
await buildKnowledgeNetwork({ ...base, knId });
|
|
1954
|
+
const deadline = Date.now() + options.timeout * 1000;
|
|
1955
|
+
const TERMINAL = ["completed", "failed", "success"];
|
|
1956
|
+
while (Date.now() < deadline) {
|
|
1957
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
1958
|
+
const statusBody = await getBuildStatus({ ...base, knId });
|
|
1959
|
+
const statusParsed = JSON.parse(statusBody);
|
|
1960
|
+
const jobs = Array.isArray(statusParsed) ? statusParsed : (statusParsed.entries ?? []);
|
|
1961
|
+
const state = (jobs[0]?.state ?? "running").toLowerCase();
|
|
1962
|
+
if (TERMINAL.includes(state)) {
|
|
1963
|
+
statusStr = state;
|
|
1964
|
+
break;
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
const output = {
|
|
1969
|
+
kn_id: knId,
|
|
1970
|
+
kn_name: options.name,
|
|
1971
|
+
object_types: otResults,
|
|
1972
|
+
status: statusStr,
|
|
1973
|
+
};
|
|
1974
|
+
console.log(JSON.stringify(output, null, options.pretty ? 2 : 0));
|
|
1975
|
+
return 0;
|
|
1976
|
+
}
|
|
1977
|
+
catch (error) {
|
|
1978
|
+
console.error(formatHttpError(error));
|
|
1979
|
+
return 1;
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1213
1982
|
async function runKnUpdateCommand(args) {
|
|
1214
1983
|
let options;
|
|
1215
1984
|
try {
|
|
@@ -1287,6 +2056,253 @@ async function runKnDeleteCommand(args) {
|
|
|
1287
2056
|
return 1;
|
|
1288
2057
|
}
|
|
1289
2058
|
}
|
|
2059
|
+
const KN_BUILD_HELP = `kweaver bkn build <kn-id> [options]
|
|
2060
|
+
|
|
2061
|
+
Trigger a full build for a knowledge network.
|
|
2062
|
+
|
|
2063
|
+
Options:
|
|
2064
|
+
--wait (default) Poll until build completes
|
|
2065
|
+
--no-wait Return immediately after triggering
|
|
2066
|
+
--timeout <seconds> Max wait time when --wait (default: 300)
|
|
2067
|
+
-bd, --biz-domain Business domain (default: bd_public)`;
|
|
2068
|
+
export function parseKnBuildArgs(args) {
|
|
2069
|
+
let knId = "";
|
|
2070
|
+
let wait = true;
|
|
2071
|
+
let timeout = 300;
|
|
2072
|
+
let businessDomain = "bd_public";
|
|
2073
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
2074
|
+
const arg = args[i];
|
|
2075
|
+
if (arg === "--help" || arg === "-h")
|
|
2076
|
+
throw new Error("help");
|
|
2077
|
+
if (arg === "--wait") {
|
|
2078
|
+
wait = true;
|
|
2079
|
+
continue;
|
|
2080
|
+
}
|
|
2081
|
+
if (arg === "--no-wait") {
|
|
2082
|
+
wait = false;
|
|
2083
|
+
continue;
|
|
2084
|
+
}
|
|
2085
|
+
if (arg === "--timeout" && args[i + 1]) {
|
|
2086
|
+
timeout = parseInt(args[i + 1], 10);
|
|
2087
|
+
if (Number.isNaN(timeout) || timeout < 1)
|
|
2088
|
+
timeout = 300;
|
|
2089
|
+
i += 1;
|
|
2090
|
+
continue;
|
|
2091
|
+
}
|
|
2092
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
2093
|
+
businessDomain = args[i + 1];
|
|
2094
|
+
i += 1;
|
|
2095
|
+
continue;
|
|
2096
|
+
}
|
|
2097
|
+
if (!arg.startsWith("-") && !knId) {
|
|
2098
|
+
knId = arg;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
if (!knId) {
|
|
2102
|
+
throw new Error("Missing kn-id. Usage: kweaver bkn build <kn-id> [options]");
|
|
2103
|
+
}
|
|
2104
|
+
return { knId, wait, timeout, businessDomain };
|
|
2105
|
+
}
|
|
2106
|
+
async function runKnBuildCommand(args) {
|
|
2107
|
+
let options;
|
|
2108
|
+
try {
|
|
2109
|
+
options = parseKnBuildArgs(args);
|
|
2110
|
+
}
|
|
2111
|
+
catch (error) {
|
|
2112
|
+
if (error instanceof Error && error.message === "help") {
|
|
2113
|
+
console.log(KN_BUILD_HELP);
|
|
2114
|
+
return 0;
|
|
2115
|
+
}
|
|
2116
|
+
console.error(formatHttpError(error));
|
|
2117
|
+
return 1;
|
|
2118
|
+
}
|
|
2119
|
+
const TERMINAL_STATES = ["completed", "failed", "success"];
|
|
2120
|
+
try {
|
|
2121
|
+
const token = await ensureValidToken();
|
|
2122
|
+
await buildKnowledgeNetwork({
|
|
2123
|
+
baseUrl: token.baseUrl,
|
|
2124
|
+
accessToken: token.accessToken,
|
|
2125
|
+
knId: options.knId,
|
|
2126
|
+
businessDomain: options.businessDomain,
|
|
2127
|
+
});
|
|
2128
|
+
console.error(`Build started for ${options.knId}`);
|
|
2129
|
+
if (!options.wait) {
|
|
2130
|
+
console.error("Build triggered (not waiting).");
|
|
2131
|
+
return 0;
|
|
2132
|
+
}
|
|
2133
|
+
console.error("Waiting for build to complete ...");
|
|
2134
|
+
const deadline = Date.now() + options.timeout * 1000;
|
|
2135
|
+
while (Date.now() < deadline) {
|
|
2136
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
2137
|
+
const body = await getBuildStatus({
|
|
2138
|
+
baseUrl: token.baseUrl,
|
|
2139
|
+
accessToken: token.accessToken,
|
|
2140
|
+
knId: options.knId,
|
|
2141
|
+
businessDomain: options.businessDomain,
|
|
2142
|
+
});
|
|
2143
|
+
const parsed = JSON.parse(body);
|
|
2144
|
+
const jobs = Array.isArray(parsed) ? parsed : (parsed.entries ?? parsed.data ?? []);
|
|
2145
|
+
const job = jobs[0];
|
|
2146
|
+
const state = (job?.state ?? "running").toLowerCase();
|
|
2147
|
+
const detail = job?.state_detail;
|
|
2148
|
+
if (TERMINAL_STATES.includes(state)) {
|
|
2149
|
+
console.log(state);
|
|
2150
|
+
if (detail) {
|
|
2151
|
+
console.log(`Detail: ${detail}`);
|
|
2152
|
+
}
|
|
2153
|
+
return state === "failed" ? 1 : 0;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
console.error(`Build did not complete within ${options.timeout}s`);
|
|
2157
|
+
return 1;
|
|
2158
|
+
}
|
|
2159
|
+
catch (error) {
|
|
2160
|
+
console.error(formatHttpError(error));
|
|
2161
|
+
return 1;
|
|
2162
|
+
}
|
|
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
|
+
}
|
|
1290
2306
|
// ── search ──────────────────────────────────────────────────────────────────
|
|
1291
2307
|
const KN_SEARCH_HELP = `kweaver bkn search <kn-id> <query> [--max-concepts <n>] [--mode <mode>] [--pretty] [-bd value]
|
|
1292
2308
|
|