@kweaver-ai/kweaver-sdk 0.5.1 → 0.5.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 +6 -1
- package/README.zh.md +5 -0
- package/dist/api/agent-chat.d.ts +1 -1
- package/dist/api/agent-chat.js +4 -4
- package/dist/api/agent-list.d.ts +35 -0
- package/dist/api/agent-list.js +86 -12
- package/dist/api/bkn-backend.d.ts +60 -0
- package/dist/api/bkn-backend.js +103 -10
- package/dist/api/conversations.d.ts +6 -3
- package/dist/api/conversations.js +26 -27
- package/dist/api/dataflow.js +1 -10
- package/dist/api/datasources.js +1 -10
- package/dist/api/dataviews.js +1 -10
- package/dist/api/headers.d.ts +9 -0
- package/dist/api/headers.js +25 -0
- package/dist/api/knowledge-networks.d.ts +41 -0
- package/dist/api/knowledge-networks.js +69 -22
- package/dist/api/ontology-query.d.ts +14 -1
- package/dist/api/ontology-query.js +63 -49
- package/dist/api/semantic-search.js +2 -12
- package/dist/api/skills.d.ts +141 -0
- package/dist/api/skills.js +216 -0
- package/dist/api/vega.d.ts +63 -0
- package/dist/api/vega.js +130 -10
- package/dist/auth/oauth.d.ts +5 -1
- package/dist/auth/oauth.js +293 -94
- package/dist/cli.js +28 -4
- package/dist/client.d.ts +3 -0
- package/dist/client.js +4 -0
- package/dist/commands/agent.d.ts +33 -1
- package/dist/commands/agent.js +721 -49
- package/dist/commands/auth.js +156 -33
- package/dist/commands/bkn-ops.d.ts +77 -0
- package/dist/commands/bkn-ops.js +1056 -0
- package/dist/commands/bkn-query.d.ts +14 -0
- package/dist/commands/bkn-query.js +370 -0
- package/dist/commands/bkn-schema.d.ts +135 -0
- package/dist/commands/bkn-schema.js +1461 -0
- package/dist/commands/bkn-utils.d.ts +36 -0
- package/dist/commands/bkn-utils.js +102 -0
- package/dist/commands/bkn.d.ts +7 -113
- package/dist/commands/bkn.js +175 -2429
- package/dist/commands/dataview.d.ts +7 -0
- package/dist/commands/dataview.js +38 -2
- package/dist/commands/ds.d.ts +1 -0
- package/dist/commands/ds.js +8 -1
- package/dist/commands/import-csv.d.ts +2 -0
- package/dist/commands/import-csv.js +3 -2
- package/dist/commands/skill.d.ts +26 -0
- package/dist/commands/skill.js +524 -0
- package/dist/commands/vega.js +371 -14
- package/dist/config/jwt.d.ts +6 -0
- package/dist/config/jwt.js +21 -0
- package/dist/config/store.d.ts +37 -5
- package/dist/config/store.js +363 -30
- package/dist/index.d.ts +6 -1
- package/dist/index.js +5 -1
- package/dist/resources/bkn.d.ts +4 -0
- package/dist/resources/bkn.js +4 -0
- package/dist/resources/conversations.d.ts +5 -2
- package/dist/resources/conversations.js +17 -3
- package/dist/resources/skills.d.ts +47 -0
- package/dist/resources/skills.js +47 -0
- package/dist/resources/vega.d.ts +11 -0
- package/dist/resources/vega.js +37 -1
- package/package.json +1 -1
package/dist/commands/bkn.js
CHANGED
|
@@ -1,32 +1,20 @@
|
|
|
1
1
|
import { createInterface } from "node:readline";
|
|
2
|
-
import {
|
|
3
|
-
import { mkdirSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
4
|
-
import { resolve } from "node:path";
|
|
5
|
-
import { loadNetwork, allObjects, allRelations, allActions, generateChecksum, validateNetwork } from "@kweaver-ai/bkn";
|
|
6
|
-
import { prepareBknDirectoryForImport, stripBknEncodingCliArgs, } from "../utils/bkn-encoding.js";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
7
3
|
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
8
|
-
import { listKnowledgeNetworks, getKnowledgeNetwork, createKnowledgeNetwork, updateKnowledgeNetwork, deleteKnowledgeNetwork,
|
|
9
|
-
import { objectTypeQuery, objectTypeProperties, subgraph, actionTypeQuery, actionTypeExecute, actionExecutionGet, actionLogsList, actionLogGet, actionLogCancel, } from "../api/ontology-query.js";
|
|
10
|
-
import { semanticSearch } from "../api/semantic-search.js";
|
|
11
|
-
import { listTablesWithColumns, scanMetadata, getDatasource } from "../api/datasources.js";
|
|
12
|
-
import { createDataView, findDataView } from "../api/dataviews.js"; // used by runKnCreateFromDsCommand
|
|
13
|
-
import { downloadBkn, uploadBkn } from "../api/bkn-backend.js";
|
|
4
|
+
import { listKnowledgeNetworks, getKnowledgeNetwork, createKnowledgeNetwork, updateKnowledgeNetwork, deleteKnowledgeNetwork, } from "../api/knowledge-networks.js";
|
|
14
5
|
import { formatCallOutput } from "./call.js";
|
|
15
6
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
throw new Error(`Polling timed out after ${timeout}ms`);
|
|
29
|
-
}
|
|
7
|
+
import { runKnObjectTypeCommand, runKnRelationTypeCommand, runKnActionTypeCommand, runKnConceptGroupCommand, } from "./bkn-schema.js";
|
|
8
|
+
import { runKnSubgraphCommand, runKnActionExecutionCommand, runKnActionLogCommand, runKnSearchCommand, runKnRelationTypePathsCommand, runKnResourcesCommand, } from "./bkn-query.js";
|
|
9
|
+
import { runKnBuildCommand, runKnValidateCommand, runKnPushCommand, runKnPullCommand, runKnCreateFromDsCommand, runKnCreateFromCsvCommand, runKnActionScheduleCommand, runKnJobCommand, } from "./bkn-ops.js";
|
|
10
|
+
// Re-export shared utils for backward compatibility (tests import from bkn.js)
|
|
11
|
+
export { pollWithBackoff, parseOntologyQueryFlags, parseJsonObject, parseSearchAfterArray, confirmYes, DISPLAY_HINTS, detectPrimaryKey, detectDisplayKey, } from "./bkn-utils.js";
|
|
12
|
+
// Re-export schema types and parse functions for backward compatibility
|
|
13
|
+
export { parseObjectTypeCreateArgs, finalizeObjectTypeCreateFromDataview, ensureMappedFieldOnDataProperty, normalizeAdpFieldType, parseKnObjectTypeQueryArgs, parseKnActionTypeExecuteArgs, parseRelationTypeCreateArgs, applyObjectTypeMerge, stripObjectTypeForPut, parseObjectTypeUpdateArgs, parseObjectTypeDeleteArgs, parseRelationTypeUpdateArgs, parseRelationTypeDeleteArgs, runKnObjectTypeCommand, runKnRelationTypeCommand, runKnActionTypeCommand, parseConceptGroupArgs, } from "./bkn-schema.js";
|
|
14
|
+
// Re-export query parse functions for backward compatibility (tests import from bkn.js)
|
|
15
|
+
export { parseKnSearchArgs } from "./bkn-query.js";
|
|
16
|
+
// Re-export ops types and parse functions for backward compatibility (tests import from bkn.js)
|
|
17
|
+
export { parseKnBuildArgs, parseKnPushArgs, parseKnPullArgs, packDirectoryToTar, extractTarToDirectory, parseActionScheduleArgs, parseJobArgs, } from "./bkn-ops.js";
|
|
30
18
|
export function formatSimpleKnList(text, pretty, includeDetail = false) {
|
|
31
19
|
const parsed = JSON.parse(text);
|
|
32
20
|
const entries = Array.isArray(parsed.entries) ? parsed.entries : [];
|
|
@@ -368,245 +356,6 @@ export function parseKnDeleteArgs(args) {
|
|
|
368
356
|
businessDomain = resolveBusinessDomain();
|
|
369
357
|
return { knId, businessDomain, yes };
|
|
370
358
|
}
|
|
371
|
-
export function parseKnPushArgs(args) {
|
|
372
|
-
const { rest, options: encodingOptions } = stripBknEncodingCliArgs(args);
|
|
373
|
-
let directory = "";
|
|
374
|
-
let branch = "main";
|
|
375
|
-
let businessDomain = "";
|
|
376
|
-
let pretty = true;
|
|
377
|
-
for (let i = 0; i < rest.length; i += 1) {
|
|
378
|
-
const arg = rest[i];
|
|
379
|
-
if (arg === "--help" || arg === "-h") {
|
|
380
|
-
throw new Error("help");
|
|
381
|
-
}
|
|
382
|
-
if (arg === "--branch") {
|
|
383
|
-
branch = args[i + 1] ?? "main";
|
|
384
|
-
if (!branch || branch.startsWith("-")) {
|
|
385
|
-
throw new Error("Missing value for --branch");
|
|
386
|
-
}
|
|
387
|
-
i += 1;
|
|
388
|
-
continue;
|
|
389
|
-
}
|
|
390
|
-
if (arg === "-bd" || arg === "--biz-domain") {
|
|
391
|
-
businessDomain = args[i + 1] ?? "bd_public";
|
|
392
|
-
if (!businessDomain || businessDomain.startsWith("-")) {
|
|
393
|
-
throw new Error("Missing value for biz-domain flag");
|
|
394
|
-
}
|
|
395
|
-
i += 1;
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
if (arg === "--pretty") {
|
|
399
|
-
pretty = true;
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
if (!arg.startsWith("-") && !directory) {
|
|
403
|
-
directory = arg;
|
|
404
|
-
continue;
|
|
405
|
-
}
|
|
406
|
-
throw new Error(`Unsupported bkn push argument: ${arg}`);
|
|
407
|
-
}
|
|
408
|
-
if (!directory) {
|
|
409
|
-
throw new Error("Missing directory. Usage: kweaver bkn push <directory> [--branch main] [-bd value]");
|
|
410
|
-
}
|
|
411
|
-
if (!businessDomain)
|
|
412
|
-
businessDomain = resolveBusinessDomain();
|
|
413
|
-
return { directory, branch, businessDomain, pretty, encodingOptions };
|
|
414
|
-
}
|
|
415
|
-
export function parseKnPullArgs(args) {
|
|
416
|
-
let knId = "";
|
|
417
|
-
let directory = "";
|
|
418
|
-
let branch = "main";
|
|
419
|
-
let businessDomain = "";
|
|
420
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
421
|
-
const arg = args[i];
|
|
422
|
-
if (arg === "--help" || arg === "-h") {
|
|
423
|
-
throw new Error("help");
|
|
424
|
-
}
|
|
425
|
-
if (arg === "--branch") {
|
|
426
|
-
branch = args[i + 1] ?? "main";
|
|
427
|
-
if (!branch || branch.startsWith("-")) {
|
|
428
|
-
throw new Error("Missing value for --branch");
|
|
429
|
-
}
|
|
430
|
-
i += 1;
|
|
431
|
-
continue;
|
|
432
|
-
}
|
|
433
|
-
if (arg === "-bd" || arg === "--biz-domain") {
|
|
434
|
-
businessDomain = args[i + 1] ?? "bd_public";
|
|
435
|
-
if (!businessDomain || businessDomain.startsWith("-")) {
|
|
436
|
-
throw new Error("Missing value for biz-domain flag");
|
|
437
|
-
}
|
|
438
|
-
i += 1;
|
|
439
|
-
continue;
|
|
440
|
-
}
|
|
441
|
-
if (!arg.startsWith("-")) {
|
|
442
|
-
if (!knId) {
|
|
443
|
-
knId = arg;
|
|
444
|
-
}
|
|
445
|
-
else if (!directory) {
|
|
446
|
-
directory = arg;
|
|
447
|
-
}
|
|
448
|
-
else {
|
|
449
|
-
throw new Error(`Unexpected positional argument: ${arg}`);
|
|
450
|
-
}
|
|
451
|
-
continue;
|
|
452
|
-
}
|
|
453
|
-
throw new Error(`Unsupported bkn pull argument: ${arg}`);
|
|
454
|
-
}
|
|
455
|
-
if (!knId) {
|
|
456
|
-
throw new Error("Missing kn-id. Usage: kweaver bkn pull <kn-id> [<directory>] [--branch main] [-bd value]");
|
|
457
|
-
}
|
|
458
|
-
if (!businessDomain)
|
|
459
|
-
businessDomain = resolveBusinessDomain();
|
|
460
|
-
return { knId, directory: directory || knId, branch, businessDomain };
|
|
461
|
-
}
|
|
462
|
-
function parseJsonObject(text, errorMessage) {
|
|
463
|
-
let parsed;
|
|
464
|
-
try {
|
|
465
|
-
parsed = JSON.parse(text);
|
|
466
|
-
}
|
|
467
|
-
catch {
|
|
468
|
-
throw new Error(errorMessage);
|
|
469
|
-
}
|
|
470
|
-
if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") {
|
|
471
|
-
throw new Error(errorMessage);
|
|
472
|
-
}
|
|
473
|
-
return parsed;
|
|
474
|
-
}
|
|
475
|
-
const MAX_OUTPUT_BYTES = 100_000;
|
|
476
|
-
/**
|
|
477
|
-
* If a query response exceeds MAX_OUTPUT_BYTES, trim the datas array
|
|
478
|
-
* to fit, preserving valid JSON and the search_after cursor for pagination.
|
|
479
|
-
*/
|
|
480
|
-
function truncateQueryResult(raw) {
|
|
481
|
-
if (raw.length <= MAX_OUTPUT_BYTES) {
|
|
482
|
-
return raw;
|
|
483
|
-
}
|
|
484
|
-
let parsed;
|
|
485
|
-
try {
|
|
486
|
-
parsed = JSON.parse(raw);
|
|
487
|
-
}
|
|
488
|
-
catch {
|
|
489
|
-
return raw;
|
|
490
|
-
}
|
|
491
|
-
const datas = parsed.datas;
|
|
492
|
-
if (!Array.isArray(datas) || datas.length === 0) {
|
|
493
|
-
return raw;
|
|
494
|
-
}
|
|
495
|
-
const originalCount = datas.length;
|
|
496
|
-
while (datas.length > 1) {
|
|
497
|
-
datas.pop();
|
|
498
|
-
const candidate = JSON.stringify(parsed);
|
|
499
|
-
if (candidate.length <= MAX_OUTPUT_BYTES) {
|
|
500
|
-
const remaining = originalCount - datas.length;
|
|
501
|
-
const sa = parsed.search_after;
|
|
502
|
-
parsed._truncated = {
|
|
503
|
-
returned: datas.length,
|
|
504
|
-
total_fetched: originalCount,
|
|
505
|
-
remaining,
|
|
506
|
-
next_search_after: sa ?? null,
|
|
507
|
-
hint: sa
|
|
508
|
-
? `Pass --search-after '${JSON.stringify(sa)}' --limit ${datas.length} to fetch the next page.`
|
|
509
|
-
: `Reduce --limit to ${datas.length} or less to avoid truncation.`,
|
|
510
|
-
};
|
|
511
|
-
console.error(`[warn] Truncated ${originalCount} → ${datas.length} records (output exceeded ${Math.round(MAX_OUTPUT_BYTES / 1024)}KB). ${parsed._truncated.hint}`);
|
|
512
|
-
return JSON.stringify(parsed);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
const sa = parsed.search_after;
|
|
516
|
-
parsed._truncated = {
|
|
517
|
-
returned: 1,
|
|
518
|
-
total_fetched: originalCount,
|
|
519
|
-
remaining: originalCount - 1,
|
|
520
|
-
next_search_after: sa ?? null,
|
|
521
|
-
hint: `Single record is very large. Use --limit 1 and --search-after to iterate.`,
|
|
522
|
-
};
|
|
523
|
-
console.error(`[warn] Truncated ${originalCount} → 1 record. Single record is very large. Use --limit 1 and --search-after to iterate.`);
|
|
524
|
-
return JSON.stringify(parsed);
|
|
525
|
-
}
|
|
526
|
-
function parseSearchAfterArray(text) {
|
|
527
|
-
let parsed;
|
|
528
|
-
try {
|
|
529
|
-
parsed = JSON.parse(text);
|
|
530
|
-
}
|
|
531
|
-
catch {
|
|
532
|
-
throw new Error("Invalid value for --search-after. Expected a JSON array string.");
|
|
533
|
-
}
|
|
534
|
-
if (!Array.isArray(parsed)) {
|
|
535
|
-
throw new Error("Invalid value for --search-after. Expected a JSON array string.");
|
|
536
|
-
}
|
|
537
|
-
return parsed;
|
|
538
|
-
}
|
|
539
|
-
export function parseKnObjectTypeQueryArgs(args) {
|
|
540
|
-
let pretty = true;
|
|
541
|
-
let businessDomain = "";
|
|
542
|
-
let limit;
|
|
543
|
-
let searchAfter;
|
|
544
|
-
const positionalArgs = [];
|
|
545
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
546
|
-
const arg = args[i];
|
|
547
|
-
if (arg === "--help" || arg === "-h") {
|
|
548
|
-
throw new Error("help");
|
|
549
|
-
}
|
|
550
|
-
if (arg === "--pretty") {
|
|
551
|
-
pretty = true;
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
if (arg === "-bd" || arg === "--biz-domain") {
|
|
555
|
-
businessDomain = args[i + 1] ?? "bd_public";
|
|
556
|
-
if (!businessDomain || businessDomain.startsWith("-")) {
|
|
557
|
-
throw new Error("Missing value for biz-domain flag");
|
|
558
|
-
}
|
|
559
|
-
i += 1;
|
|
560
|
-
continue;
|
|
561
|
-
}
|
|
562
|
-
if (arg === "--limit") {
|
|
563
|
-
const rawLimit = args[i + 1];
|
|
564
|
-
const parsedLimit = parseInt(rawLimit ?? "", 10);
|
|
565
|
-
if (!rawLimit || rawLimit.startsWith("-") || Number.isNaN(parsedLimit) || parsedLimit < 1) {
|
|
566
|
-
throw new Error("Invalid value for --limit. Expected a positive integer.");
|
|
567
|
-
}
|
|
568
|
-
limit = parsedLimit;
|
|
569
|
-
i += 1;
|
|
570
|
-
continue;
|
|
571
|
-
}
|
|
572
|
-
if (arg === "--search-after") {
|
|
573
|
-
const rawSearchAfter = args[i + 1];
|
|
574
|
-
if (!rawSearchAfter) {
|
|
575
|
-
throw new Error("Missing value for --search-after. Expected a JSON array string.");
|
|
576
|
-
}
|
|
577
|
-
searchAfter = parseSearchAfterArray(rawSearchAfter);
|
|
578
|
-
i += 1;
|
|
579
|
-
continue;
|
|
580
|
-
}
|
|
581
|
-
positionalArgs.push(arg);
|
|
582
|
-
}
|
|
583
|
-
const [knId, otId, bodyText = "{}"] = positionalArgs;
|
|
584
|
-
if (!knId || !otId) {
|
|
585
|
-
throw new Error("Usage: kweaver bkn object-type query <kn-id> <ot-id> ['<json>'] [--limit <n>] [--search-after '<json-array>'] [--pretty] [-bd value]");
|
|
586
|
-
}
|
|
587
|
-
if (positionalArgs.length > 3) {
|
|
588
|
-
throw new Error("Usage: kweaver bkn object-type query <kn-id> <ot-id> ['<json>'] [--limit <n>] [--search-after '<json-array>'] [--pretty] [-bd value]");
|
|
589
|
-
}
|
|
590
|
-
const body = parseJsonObject(bodyText, "object-type query body must be a JSON object.");
|
|
591
|
-
if (limit !== undefined) {
|
|
592
|
-
body.limit = limit;
|
|
593
|
-
}
|
|
594
|
-
if (searchAfter !== undefined) {
|
|
595
|
-
body.search_after = searchAfter;
|
|
596
|
-
}
|
|
597
|
-
if (typeof body.limit !== "number" || !Number.isFinite(body.limit) || body.limit < 1) {
|
|
598
|
-
body.limit = 50;
|
|
599
|
-
}
|
|
600
|
-
if (!businessDomain)
|
|
601
|
-
businessDomain = resolveBusinessDomain();
|
|
602
|
-
return {
|
|
603
|
-
knId,
|
|
604
|
-
otId,
|
|
605
|
-
body: JSON.stringify(body),
|
|
606
|
-
pretty,
|
|
607
|
-
businessDomain,
|
|
608
|
-
};
|
|
609
|
-
}
|
|
610
359
|
const KN_HELP = `kweaver bkn
|
|
611
360
|
|
|
612
361
|
Subcommands:
|
|
@@ -635,16 +384,25 @@ Subcommands:
|
|
|
635
384
|
relation-type list <kn-id> List relation types (schema)
|
|
636
385
|
relation-type get <kn-id> <rt-id> Get relation type details
|
|
637
386
|
relation-type create <kn-id> [options] Create relation type (--name --source --target [--mapping src:tgt])
|
|
638
|
-
relation-type update <kn-id> <rt-id> [
|
|
387
|
+
relation-type update <kn-id> <rt-id> --source <ot-id> --target <ot-id> [--name X] [--type direct|data_view] [--mapping src:tgt ...] Update relation type
|
|
639
388
|
relation-type delete <kn-id> <rt-ids> [-y] Delete relation type(s)
|
|
640
389
|
subgraph <kn-id> '<json>' Query subgraph
|
|
641
390
|
action-type list <kn-id> List action types (schema)
|
|
391
|
+
action-type get <kn-id> <at-id> Get action type details
|
|
392
|
+
action-type create <kn-id> '<json>' Create action type
|
|
393
|
+
action-type update <kn-id> <at-id> '<json>' Update action type
|
|
394
|
+
action-type delete <kn-id> <at-ids> [-y] Delete action type(s)
|
|
642
395
|
action-type query <kn-id> <at-id> '<json>' Query action info
|
|
643
396
|
action-type execute <kn-id> <at-id> '<json>' Execute action (has side effects)
|
|
644
397
|
action-execution get <kn-id> <execution-id> Get execution status
|
|
645
398
|
action-log list <kn-id> [options] List action execution logs
|
|
646
399
|
action-log get <kn-id> <log-id> Get single execution log
|
|
647
400
|
action-log cancel <kn-id> <log-id> Cancel running execution (has side effects)
|
|
401
|
+
concept-group list|get|create|update|delete|add-members|remove-members <kn-id> ...
|
|
402
|
+
action-schedule list|get|create|update|set-status|delete <kn-id> ...
|
|
403
|
+
job list|get|tasks|delete <kn-id> ...
|
|
404
|
+
relation-type-paths <kn-id> '<json>' Query relation type paths between OTs
|
|
405
|
+
resources List available resources
|
|
648
406
|
|
|
649
407
|
Use 'kweaver bkn <subcommand> --help' for subcommand options.`;
|
|
650
408
|
export async function runKnCommand(args) {
|
|
@@ -694,6 +452,16 @@ export async function runKnCommand(args) {
|
|
|
694
452
|
return runKnActionExecutionCommand(rest);
|
|
695
453
|
if (subcommand === "action-log")
|
|
696
454
|
return runKnActionLogCommand(rest);
|
|
455
|
+
if (subcommand === "concept-group")
|
|
456
|
+
return runKnConceptGroupCommand(rest);
|
|
457
|
+
if (subcommand === "action-schedule")
|
|
458
|
+
return runKnActionScheduleCommand(rest);
|
|
459
|
+
if (subcommand === "job")
|
|
460
|
+
return runKnJobCommand(rest);
|
|
461
|
+
if (subcommand === "relation-type-paths")
|
|
462
|
+
return runKnRelationTypePathsCommand(rest);
|
|
463
|
+
if (subcommand === "resources")
|
|
464
|
+
return runKnResourcesCommand(rest);
|
|
697
465
|
return Promise.resolve(-1);
|
|
698
466
|
};
|
|
699
467
|
try {
|
|
@@ -711,1341 +479,119 @@ export async function runKnCommand(args) {
|
|
|
711
479
|
return 1;
|
|
712
480
|
}
|
|
713
481
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
let primaryKey = "";
|
|
719
|
-
let displayKey = "";
|
|
720
|
-
let businessDomain = "";
|
|
721
|
-
let branch = "main";
|
|
722
|
-
let pretty = true;
|
|
723
|
-
const properties = [];
|
|
724
|
-
const positional = [];
|
|
725
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
726
|
-
const arg = args[i];
|
|
727
|
-
if (arg === "--help" || arg === "-h")
|
|
728
|
-
throw new Error("help");
|
|
729
|
-
if (arg === "--name" && args[i + 1]) {
|
|
730
|
-
name = args[++i];
|
|
731
|
-
continue;
|
|
732
|
-
}
|
|
733
|
-
if (arg === "--dataview-id" && args[i + 1]) {
|
|
734
|
-
dataviewId = args[++i];
|
|
735
|
-
continue;
|
|
736
|
-
}
|
|
737
|
-
if (arg === "--primary-key" && args[i + 1]) {
|
|
738
|
-
primaryKey = args[++i];
|
|
739
|
-
continue;
|
|
740
|
-
}
|
|
741
|
-
if (arg === "--display-key" && args[i + 1]) {
|
|
742
|
-
displayKey = args[++i];
|
|
743
|
-
continue;
|
|
744
|
-
}
|
|
745
|
-
if (arg === "--property" && args[i + 1]) {
|
|
746
|
-
properties.push(args[++i]);
|
|
747
|
-
continue;
|
|
748
|
-
}
|
|
749
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
750
|
-
businessDomain = args[++i];
|
|
751
|
-
continue;
|
|
752
|
-
}
|
|
753
|
-
if (arg === "--branch" && args[i + 1]) {
|
|
754
|
-
branch = args[++i];
|
|
755
|
-
continue;
|
|
756
|
-
}
|
|
757
|
-
if (arg === "--pretty") {
|
|
758
|
-
pretty = true;
|
|
759
|
-
continue;
|
|
760
|
-
}
|
|
761
|
-
if (!arg.startsWith("-"))
|
|
762
|
-
positional.push(arg);
|
|
763
|
-
}
|
|
764
|
-
const knId = positional[0];
|
|
765
|
-
if (!knId || !name || !dataviewId || !primaryKey || !displayKey) {
|
|
766
|
-
throw new Error("Usage: kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W");
|
|
482
|
+
async function runKnListCommand(args) {
|
|
483
|
+
let options;
|
|
484
|
+
try {
|
|
485
|
+
options = parseKnListArgs(args);
|
|
767
486
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
if (properties.length > 0) {
|
|
776
|
-
entry.data_properties = properties.map((p) => JSON.parse(p));
|
|
487
|
+
catch (error) {
|
|
488
|
+
if (error instanceof Error && error.message === "help") {
|
|
489
|
+
console.log(KN_LIST_HELP);
|
|
490
|
+
return 0;
|
|
491
|
+
}
|
|
492
|
+
console.error(formatHttpError(error));
|
|
493
|
+
return 1;
|
|
777
494
|
}
|
|
778
|
-
|
|
779
|
-
const
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
495
|
+
try {
|
|
496
|
+
const token = await ensureValidToken();
|
|
497
|
+
const body = await listKnowledgeNetworks({
|
|
498
|
+
baseUrl: token.baseUrl,
|
|
499
|
+
accessToken: token.accessToken,
|
|
500
|
+
businessDomain: options.businessDomain,
|
|
501
|
+
offset: options.offset,
|
|
502
|
+
limit: options.limit,
|
|
503
|
+
sort: options.sort,
|
|
504
|
+
direction: options.direction,
|
|
505
|
+
name_pattern: options.name_pattern,
|
|
506
|
+
tag: options.tag,
|
|
507
|
+
});
|
|
508
|
+
if (body) {
|
|
509
|
+
console.log(options.verbose
|
|
510
|
+
? formatCallOutput(body, options.pretty)
|
|
511
|
+
: formatSimpleKnList(body, options.pretty, options.detail));
|
|
512
|
+
}
|
|
513
|
+
return 0;
|
|
785
514
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
return { knId, body, businessDomain, branch, pretty };
|
|
790
|
-
}
|
|
791
|
-
const OBJECT_TYPE_PUT_STRIP_KEYS = new Set([
|
|
792
|
-
"status",
|
|
793
|
-
"creator",
|
|
794
|
-
"updater",
|
|
795
|
-
"create_time",
|
|
796
|
-
"update_time",
|
|
797
|
-
"module_type",
|
|
798
|
-
"kn_id",
|
|
799
|
-
]);
|
|
800
|
-
/** Prepare a GET response entry for PUT (drop read-only fields). */
|
|
801
|
-
export function stripObjectTypeForPut(entry) {
|
|
802
|
-
const out = { ...entry };
|
|
803
|
-
for (const k of OBJECT_TYPE_PUT_STRIP_KEYS) {
|
|
804
|
-
delete out[k];
|
|
515
|
+
catch (error) {
|
|
516
|
+
console.error(formatHttpError(error));
|
|
517
|
+
return 1;
|
|
805
518
|
}
|
|
806
|
-
return out;
|
|
807
519
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
520
|
+
const KN_LIST_HELP = `kweaver bkn list [options]
|
|
521
|
+
|
|
522
|
+
List business knowledge networks from the ontology-manager API.
|
|
523
|
+
|
|
524
|
+
Options:
|
|
525
|
+
--offset <n> Offset (default: 0)
|
|
526
|
+
--limit <n> Limit (default: 30)
|
|
527
|
+
--sort <key> Sort field (default: update_time)
|
|
528
|
+
--direction <asc|desc> Sort direction (default: desc)
|
|
529
|
+
--name-pattern <s> Filter by name pattern
|
|
530
|
+
--tag <s> Filter by tag
|
|
531
|
+
--detail Include the detail field in simplified output
|
|
532
|
+
--verbose, -v Show full JSON response
|
|
533
|
+
-bd, --biz-domain <value> Business domain (default: bd_public)
|
|
534
|
+
--pretty Pretty-print JSON output (applies to both modes)`;
|
|
535
|
+
const KN_GET_HELP = `kweaver bkn get <kn-id> [options]
|
|
536
|
+
|
|
537
|
+
Get knowledge network detail.
|
|
538
|
+
|
|
539
|
+
Options:
|
|
540
|
+
--stats Include statistics
|
|
541
|
+
--export Export mode (include sub-types)
|
|
542
|
+
-bd, --biz-domain <value> Business domain (default: bd_public)
|
|
543
|
+
--pretty Pretty-print JSON output`;
|
|
544
|
+
const KN_CREATE_HELP = `kweaver bkn create [options]
|
|
545
|
+
|
|
546
|
+
Create a knowledge network.
|
|
547
|
+
|
|
548
|
+
Options:
|
|
549
|
+
--name <s> Name (required unless --body-file)
|
|
550
|
+
--comment <s> Comment
|
|
551
|
+
--tags <t1,t2> Comma-separated tags
|
|
552
|
+
--icon <s> Icon
|
|
553
|
+
--color <s> Color
|
|
554
|
+
--branch <s> Branch (default: main)
|
|
555
|
+
--base-branch <s> Base branch (default: empty for main)
|
|
556
|
+
--body-file <path> Read full JSON body from file (cannot combine with flags above)
|
|
557
|
+
--import-mode <normal|ignore|overwrite> Import mode (default: normal)
|
|
558
|
+
--validate-dependency <true|false> Validate dependency (default: true)
|
|
559
|
+
-bd, --biz-domain <value> Business domain (default: bd_public)
|
|
560
|
+
--pretty Pretty-print JSON output`;
|
|
561
|
+
const KN_UPDATE_HELP = `kweaver bkn update <kn-id> [options]
|
|
562
|
+
|
|
563
|
+
Update a knowledge network.
|
|
564
|
+
|
|
565
|
+
Options:
|
|
566
|
+
--name <s> Name (required unless --body-file)
|
|
567
|
+
--comment <s> Comment
|
|
568
|
+
--tags <t1,t2> Comma-separated tags
|
|
569
|
+
--icon <s> Icon
|
|
570
|
+
--color <s> Color
|
|
571
|
+
--branch <s> Branch (default: main)
|
|
572
|
+
--base-branch <s> Base branch (default: empty for main)
|
|
573
|
+
--body-file <path> Read full JSON body from file (cannot combine with flags above)
|
|
574
|
+
-bd, --biz-domain <value> Business domain (default: bd_public)
|
|
575
|
+
--pretty Pretty-print JSON output`;
|
|
576
|
+
const KN_DELETE_HELP = `kweaver bkn delete <kn-id>
|
|
577
|
+
|
|
578
|
+
Delete a knowledge network and its object types, relation types, action types, and concept groups.
|
|
579
|
+
|
|
580
|
+
Options:
|
|
581
|
+
--yes, -y Skip confirmation prompt
|
|
582
|
+
-bd, --biz-domain <value> Business domain (default: bd_public)`;
|
|
583
|
+
async function runKnGetCommand(args) {
|
|
584
|
+
let options;
|
|
585
|
+
try {
|
|
586
|
+
options = parseKnGetArgs(args);
|
|
841
587
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
588
|
+
catch (error) {
|
|
589
|
+
if (error instanceof Error && error.message === "help") {
|
|
590
|
+
console.log(KN_GET_HELP);
|
|
591
|
+
return 0;
|
|
846
592
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
list[idx] = add;
|
|
850
|
-
else
|
|
851
|
-
list.push(add);
|
|
852
|
-
}
|
|
853
|
-
target.data_properties = list;
|
|
854
|
-
return target;
|
|
855
|
-
}
|
|
856
|
-
/** Parse object-type update: raw JSON body OR merge flags (GET-merge-PUT). */
|
|
857
|
-
function parseObjectTypeUpdateArgs(args) {
|
|
858
|
-
let name;
|
|
859
|
-
let displayKey;
|
|
860
|
-
let businessDomain = "";
|
|
861
|
-
let pretty = true;
|
|
862
|
-
let branch = "main";
|
|
863
|
-
let comment;
|
|
864
|
-
let icon;
|
|
865
|
-
let color;
|
|
866
|
-
let tagsJson;
|
|
867
|
-
const addProperties = [];
|
|
868
|
-
const removeProperties = [];
|
|
869
|
-
const positional = [];
|
|
870
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
871
|
-
const arg = args[i];
|
|
872
|
-
if (arg === "--help" || arg === "-h")
|
|
873
|
-
throw new Error("help");
|
|
874
|
-
if (arg === "--name" && args[i + 1]) {
|
|
875
|
-
name = args[++i];
|
|
876
|
-
continue;
|
|
877
|
-
}
|
|
878
|
-
if (arg === "--display-key" && args[i + 1]) {
|
|
879
|
-
displayKey = args[++i];
|
|
880
|
-
continue;
|
|
881
|
-
}
|
|
882
|
-
if ((arg === "--add-property" || arg === "--update-property") && args[i + 1]) {
|
|
883
|
-
const raw = args[++i];
|
|
884
|
-
addProperties.push(parseJsonObject(raw, `--add-property / --update-property must be valid JSON object: ${raw}`));
|
|
885
|
-
continue;
|
|
886
|
-
}
|
|
887
|
-
if (arg === "--remove-property" && args[i + 1]) {
|
|
888
|
-
removeProperties.push(args[++i]);
|
|
889
|
-
continue;
|
|
890
|
-
}
|
|
891
|
-
if (arg === "--tags" && args[i + 1]) {
|
|
892
|
-
tagsJson = args[++i];
|
|
893
|
-
continue;
|
|
894
|
-
}
|
|
895
|
-
if (arg === "--comment" && args[i + 1]) {
|
|
896
|
-
comment = args[++i];
|
|
897
|
-
continue;
|
|
898
|
-
}
|
|
899
|
-
if (arg === "--icon" && args[i + 1]) {
|
|
900
|
-
icon = args[++i];
|
|
901
|
-
continue;
|
|
902
|
-
}
|
|
903
|
-
if (arg === "--color" && args[i + 1]) {
|
|
904
|
-
color = args[++i];
|
|
905
|
-
continue;
|
|
906
|
-
}
|
|
907
|
-
if (arg === "--branch" && args[i + 1]) {
|
|
908
|
-
branch = args[++i];
|
|
909
|
-
continue;
|
|
910
|
-
}
|
|
911
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
912
|
-
businessDomain = args[++i];
|
|
913
|
-
continue;
|
|
914
|
-
}
|
|
915
|
-
if (arg === "--pretty") {
|
|
916
|
-
pretty = true;
|
|
917
|
-
continue;
|
|
918
|
-
}
|
|
919
|
-
if (!arg.startsWith("-"))
|
|
920
|
-
positional.push(arg);
|
|
921
|
-
}
|
|
922
|
-
const [knId, otId, maybeBody] = positional;
|
|
923
|
-
if (!knId || !otId) {
|
|
924
|
-
throw new Error("Usage: kweaver bkn object-type update <kn-id> <ot-id> [ '<full-json-body>' ] [--name ...] [--add-property|--update-property '<json>' ...] [--remove-property <name> ...]");
|
|
925
|
-
}
|
|
926
|
-
const hasMergeFlags = name !== undefined ||
|
|
927
|
-
displayKey !== undefined ||
|
|
928
|
-
addProperties.length > 0 ||
|
|
929
|
-
removeProperties.length > 0 ||
|
|
930
|
-
tagsJson !== undefined ||
|
|
931
|
-
comment !== undefined ||
|
|
932
|
-
icon !== undefined ||
|
|
933
|
-
color !== undefined;
|
|
934
|
-
if (maybeBody !== undefined && maybeBody.trim().startsWith("{")) {
|
|
935
|
-
if (hasMergeFlags) {
|
|
936
|
-
throw new Error("Do not combine a raw JSON body with --name/--add-property/--update-property/--remove-property and other merge flags.");
|
|
937
|
-
}
|
|
938
|
-
if (!businessDomain)
|
|
939
|
-
businessDomain = resolveBusinessDomain();
|
|
940
|
-
return {
|
|
941
|
-
mode: "body",
|
|
942
|
-
knId,
|
|
943
|
-
otId,
|
|
944
|
-
body: maybeBody.trim(),
|
|
945
|
-
businessDomain,
|
|
946
|
-
pretty,
|
|
947
|
-
};
|
|
948
|
-
}
|
|
949
|
-
if (maybeBody !== undefined) {
|
|
950
|
-
throw new Error(`Unexpected third argument "${maybeBody}". For raw PUT body, pass a single JSON object starting with "{".`);
|
|
951
|
-
}
|
|
952
|
-
let tags;
|
|
953
|
-
if (tagsJson !== undefined) {
|
|
954
|
-
try {
|
|
955
|
-
const t = JSON.parse(tagsJson);
|
|
956
|
-
if (!Array.isArray(t) || !t.every((x) => typeof x === "string")) {
|
|
957
|
-
throw new Error("invalid");
|
|
958
|
-
}
|
|
959
|
-
tags = t;
|
|
960
|
-
}
|
|
961
|
-
catch {
|
|
962
|
-
throw new Error(`--tags must be a JSON array of strings, e.g. '["足球","球员"]'`);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
const merge = {
|
|
966
|
-
addProperties,
|
|
967
|
-
removeProperties,
|
|
968
|
-
...(name !== undefined ? { name } : {}),
|
|
969
|
-
...(displayKey !== undefined ? { displayKey } : {}),
|
|
970
|
-
...(tags !== undefined ? { tags } : {}),
|
|
971
|
-
...(comment !== undefined ? { comment } : {}),
|
|
972
|
-
...(icon !== undefined ? { icon } : {}),
|
|
973
|
-
...(color !== undefined ? { color } : {}),
|
|
974
|
-
};
|
|
975
|
-
if (merge.name === undefined &&
|
|
976
|
-
merge.displayKey === undefined &&
|
|
977
|
-
merge.addProperties.length === 0 &&
|
|
978
|
-
merge.removeProperties.length === 0 &&
|
|
979
|
-
merge.tags === undefined &&
|
|
980
|
-
merge.comment === undefined &&
|
|
981
|
-
merge.icon === undefined &&
|
|
982
|
-
merge.color === undefined) {
|
|
983
|
-
throw new Error("No update fields. Use --name, --display-key, --add-property (new), --update-property (same as add; replaces by name), --remove-property, --tags, --comment, --icon, --color, or pass a full JSON object as the third argument.");
|
|
984
|
-
}
|
|
985
|
-
if (!businessDomain)
|
|
986
|
-
businessDomain = resolveBusinessDomain();
|
|
987
|
-
return { mode: "merge", knId, otId, merge, businessDomain, pretty, branch };
|
|
988
|
-
}
|
|
989
|
-
/** Parse object-type delete args: <kn-id> <ot-ids> [-y] */
|
|
990
|
-
function parseObjectTypeDeleteArgs(args) {
|
|
991
|
-
let businessDomain = "";
|
|
992
|
-
let yes = false;
|
|
993
|
-
const positional = [];
|
|
994
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
995
|
-
const arg = args[i];
|
|
996
|
-
if (arg === "--help" || arg === "-h")
|
|
997
|
-
throw new Error("help");
|
|
998
|
-
if (arg === "--yes" || arg === "-y") {
|
|
999
|
-
yes = true;
|
|
1000
|
-
continue;
|
|
1001
|
-
}
|
|
1002
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1003
|
-
businessDomain = args[++i];
|
|
1004
|
-
continue;
|
|
1005
|
-
}
|
|
1006
|
-
if (!arg.startsWith("-"))
|
|
1007
|
-
positional.push(arg);
|
|
1008
|
-
}
|
|
1009
|
-
const [knId, otIds] = positional;
|
|
1010
|
-
if (!knId || !otIds) {
|
|
1011
|
-
throw new Error("Usage: kweaver bkn object-type delete <kn-id> <ot-ids> [-y]");
|
|
1012
|
-
}
|
|
1013
|
-
if (!businessDomain)
|
|
1014
|
-
businessDomain = resolveBusinessDomain();
|
|
1015
|
-
return { knId, otIds, businessDomain, yes };
|
|
1016
|
-
}
|
|
1017
|
-
/** Parse common flags for ontology-query subcommands; returns { filteredArgs, pretty, businessDomain } */
|
|
1018
|
-
function parseOntologyQueryFlags(args) {
|
|
1019
|
-
let pretty = true;
|
|
1020
|
-
let businessDomain = "";
|
|
1021
|
-
const filteredArgs = [];
|
|
1022
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1023
|
-
const arg = args[i];
|
|
1024
|
-
if (arg === "--help" || arg === "-h") {
|
|
1025
|
-
throw new Error("help");
|
|
1026
|
-
}
|
|
1027
|
-
if (arg === "--pretty") {
|
|
1028
|
-
pretty = true;
|
|
1029
|
-
continue;
|
|
1030
|
-
}
|
|
1031
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1032
|
-
businessDomain = args[i + 1];
|
|
1033
|
-
i += 1;
|
|
1034
|
-
continue;
|
|
1035
|
-
}
|
|
1036
|
-
filteredArgs.push(arg);
|
|
1037
|
-
}
|
|
1038
|
-
if (!businessDomain)
|
|
1039
|
-
businessDomain = resolveBusinessDomain();
|
|
1040
|
-
return { filteredArgs, pretty, businessDomain };
|
|
1041
|
-
}
|
|
1042
|
-
export function parseKnActionTypeExecuteArgs(args) {
|
|
1043
|
-
let pretty = true;
|
|
1044
|
-
let businessDomain = "";
|
|
1045
|
-
let wait = true;
|
|
1046
|
-
let timeout = 300;
|
|
1047
|
-
const positional = [];
|
|
1048
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1049
|
-
const arg = args[i];
|
|
1050
|
-
if (arg === "--help" || arg === "-h") {
|
|
1051
|
-
throw new Error("help");
|
|
1052
|
-
}
|
|
1053
|
-
if (arg === "--pretty") {
|
|
1054
|
-
pretty = true;
|
|
1055
|
-
continue;
|
|
1056
|
-
}
|
|
1057
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1058
|
-
businessDomain = args[i + 1];
|
|
1059
|
-
i += 1;
|
|
1060
|
-
continue;
|
|
1061
|
-
}
|
|
1062
|
-
if (arg === "--wait") {
|
|
1063
|
-
wait = true;
|
|
1064
|
-
continue;
|
|
1065
|
-
}
|
|
1066
|
-
if (arg === "--no-wait") {
|
|
1067
|
-
wait = false;
|
|
1068
|
-
continue;
|
|
1069
|
-
}
|
|
1070
|
-
if (arg === "--timeout" && args[i + 1]) {
|
|
1071
|
-
timeout = parseInt(args[i + 1], 10);
|
|
1072
|
-
if (Number.isNaN(timeout) || timeout < 1)
|
|
1073
|
-
timeout = 300;
|
|
1074
|
-
i += 1;
|
|
1075
|
-
continue;
|
|
1076
|
-
}
|
|
1077
|
-
positional.push(arg);
|
|
1078
|
-
}
|
|
1079
|
-
const [knId, atId, body] = positional;
|
|
1080
|
-
if (!knId || !atId || !body) {
|
|
1081
|
-
throw new Error("Missing kn-id, at-id, or body. Usage: kweaver bkn action-type execute <kn-id> <at-id> '<json>' [options]");
|
|
1082
|
-
}
|
|
1083
|
-
if (!businessDomain)
|
|
1084
|
-
businessDomain = resolveBusinessDomain();
|
|
1085
|
-
return {
|
|
1086
|
-
knId,
|
|
1087
|
-
atId,
|
|
1088
|
-
body,
|
|
1089
|
-
pretty,
|
|
1090
|
-
businessDomain,
|
|
1091
|
-
wait,
|
|
1092
|
-
timeout,
|
|
1093
|
-
};
|
|
1094
|
-
}
|
|
1095
|
-
const DISPLAY_HINTS = ["name", "title", "label", "display_name", "description"];
|
|
1096
|
-
/** Detect primary key: first column (left-to-right) with all unique values in the sample. */
|
|
1097
|
-
function detectPrimaryKey(table, rows) {
|
|
1098
|
-
if (rows && rows.length > 0) {
|
|
1099
|
-
for (const col of table.columns) {
|
|
1100
|
-
const values = rows.map((r) => r[col.name]);
|
|
1101
|
-
const unique = new Set(values);
|
|
1102
|
-
if (unique.size === rows.length)
|
|
1103
|
-
return col.name;
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
// Fallback: first column
|
|
1107
|
-
return table.columns[0]?.name ?? "id";
|
|
1108
|
-
}
|
|
1109
|
-
function detectDisplayKey(table, primaryKey) {
|
|
1110
|
-
for (const col of table.columns) {
|
|
1111
|
-
if (DISPLAY_HINTS.some((h) => col.name.toLowerCase().includes(h))) {
|
|
1112
|
-
return col.name;
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
return primaryKey;
|
|
1116
|
-
}
|
|
1117
|
-
function confirmYes(prompt) {
|
|
1118
|
-
return new Promise((resolve) => {
|
|
1119
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1120
|
-
rl.question(`${prompt} [y/N] `, (answer) => {
|
|
1121
|
-
rl.close();
|
|
1122
|
-
const trimmed = answer.trim().toLowerCase();
|
|
1123
|
-
resolve(trimmed === "y" || trimmed === "yes");
|
|
1124
|
-
});
|
|
1125
|
-
});
|
|
1126
|
-
}
|
|
1127
|
-
async function runKnObjectTypeCommand(args) {
|
|
1128
|
-
const [action, ...rest] = args;
|
|
1129
|
-
if (!action || action === "--help" || action === "-h") {
|
|
1130
|
-
console.log(`kweaver bkn object-type list <kn-id> [--pretty] [-bd value]
|
|
1131
|
-
kweaver bkn object-type get <kn-id> <ot-id> [--pretty] [-bd value]
|
|
1132
|
-
kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W [--property '<json>' ...]
|
|
1133
|
-
kweaver bkn object-type update <kn-id> <ot-id> [--name X] [--display-key Y] [--add-property|--update-property '<json>' ...] [--remove-property N ...] [--tags '["a","b"]'] [--comment S] [--icon I] [--color C] [--branch main]
|
|
1134
|
-
kweaver bkn object-type update <kn-id> <ot-id> '<full-json-body>'
|
|
1135
|
-
kweaver bkn object-type delete <kn-id> <ot-ids> [-y]
|
|
1136
|
-
kweaver bkn object-type query <kn-id> <ot-id> ['<json>'] [--limit <n>] [--search-after '<json-array>'] [--pretty] [-bd value]
|
|
1137
|
-
kweaver bkn object-type properties <kn-id> <ot-id> '<json>' [--pretty] [-bd value]
|
|
1138
|
-
|
|
1139
|
-
list: List object types (schema) from ontology-manager.
|
|
1140
|
-
get: Get single object type details.
|
|
1141
|
-
create/update/delete: Schema CRUD (create requires dataview-id). update: merge flags (--add-property / --update-property / --remove-property, etc.) GET-merge-PUT; or full JSON as third arg.
|
|
1142
|
-
query: Query via ontology-query API. Default limit is 50 if not specified. Use --search-after for pagination.
|
|
1143
|
-
properties: Query instance properties by primary key.
|
|
1144
|
-
|
|
1145
|
-
properties JSON format: {"_instance_identities":[{"<primary-key>":"<value>"}],"properties":["prop1","prop2"]}`);
|
|
1146
|
-
return 0;
|
|
1147
|
-
}
|
|
1148
|
-
try {
|
|
1149
|
-
if (action === "get") {
|
|
1150
|
-
const parsed = parseOntologyQueryFlags(rest);
|
|
1151
|
-
const [knId, otId] = parsed.filteredArgs;
|
|
1152
|
-
if (!knId || !otId) {
|
|
1153
|
-
console.error("Usage: kweaver bkn object-type get <kn-id> <ot-id> [options]");
|
|
1154
|
-
return 1;
|
|
1155
|
-
}
|
|
1156
|
-
const token = await ensureValidToken();
|
|
1157
|
-
const body = await getObjectType({
|
|
1158
|
-
baseUrl: token.baseUrl,
|
|
1159
|
-
accessToken: token.accessToken,
|
|
1160
|
-
knId,
|
|
1161
|
-
otId,
|
|
1162
|
-
businessDomain: parsed.businessDomain,
|
|
1163
|
-
});
|
|
1164
|
-
console.log(formatCallOutput(body, parsed.pretty));
|
|
1165
|
-
return 0;
|
|
1166
|
-
}
|
|
1167
|
-
if (action === "create") {
|
|
1168
|
-
const opts = parseObjectTypeCreateArgs(rest);
|
|
1169
|
-
const token = await ensureValidToken();
|
|
1170
|
-
const body = await createObjectTypes({
|
|
1171
|
-
baseUrl: token.baseUrl,
|
|
1172
|
-
accessToken: token.accessToken,
|
|
1173
|
-
knId: opts.knId,
|
|
1174
|
-
body: opts.body,
|
|
1175
|
-
businessDomain: opts.businessDomain,
|
|
1176
|
-
branch: opts.branch,
|
|
1177
|
-
});
|
|
1178
|
-
console.log(formatCallOutput(body, opts.pretty));
|
|
1179
|
-
return 0;
|
|
1180
|
-
}
|
|
1181
|
-
if (action === "update") {
|
|
1182
|
-
const opts = parseObjectTypeUpdateArgs(rest);
|
|
1183
|
-
const token = await ensureValidToken();
|
|
1184
|
-
let putBody;
|
|
1185
|
-
if (opts.mode === "body") {
|
|
1186
|
-
putBody = opts.body;
|
|
1187
|
-
}
|
|
1188
|
-
else {
|
|
1189
|
-
const raw = await getObjectType({
|
|
1190
|
-
baseUrl: token.baseUrl,
|
|
1191
|
-
accessToken: token.accessToken,
|
|
1192
|
-
knId: opts.knId,
|
|
1193
|
-
otId: opts.otId,
|
|
1194
|
-
businessDomain: opts.businessDomain,
|
|
1195
|
-
branch: opts.branch,
|
|
1196
|
-
});
|
|
1197
|
-
const parsed = JSON.parse(raw);
|
|
1198
|
-
const entryUnknown = parsed.entries;
|
|
1199
|
-
const entry = Array.isArray(entryUnknown) && entryUnknown.length > 0 && entryUnknown[0] && typeof entryUnknown[0] === "object"
|
|
1200
|
-
? entryUnknown[0]
|
|
1201
|
-
: parsed;
|
|
1202
|
-
if (!entry || typeof entry !== "object") {
|
|
1203
|
-
throw new Error("Unexpected object-type GET response shape.");
|
|
1204
|
-
}
|
|
1205
|
-
const stripped = stripObjectTypeForPut(entry);
|
|
1206
|
-
applyObjectTypeMerge(stripped, opts.merge);
|
|
1207
|
-
putBody = JSON.stringify(stripped);
|
|
1208
|
-
}
|
|
1209
|
-
const body = await updateObjectType({
|
|
1210
|
-
baseUrl: token.baseUrl,
|
|
1211
|
-
accessToken: token.accessToken,
|
|
1212
|
-
knId: opts.knId,
|
|
1213
|
-
otId: opts.otId,
|
|
1214
|
-
body: putBody,
|
|
1215
|
-
businessDomain: opts.businessDomain,
|
|
1216
|
-
});
|
|
1217
|
-
console.log(formatCallOutput(body, opts.pretty));
|
|
1218
|
-
return 0;
|
|
1219
|
-
}
|
|
1220
|
-
if (action === "delete") {
|
|
1221
|
-
const opts = parseObjectTypeDeleteArgs(rest);
|
|
1222
|
-
if (!opts.yes) {
|
|
1223
|
-
const confirmed = await confirmYes(`Delete object type(s) ${opts.otIds}?`);
|
|
1224
|
-
if (!confirmed) {
|
|
1225
|
-
console.error("Aborted.");
|
|
1226
|
-
return 1;
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
const token = await ensureValidToken();
|
|
1230
|
-
await deleteObjectTypes({
|
|
1231
|
-
baseUrl: token.baseUrl,
|
|
1232
|
-
accessToken: token.accessToken,
|
|
1233
|
-
knId: opts.knId,
|
|
1234
|
-
otIds: opts.otIds,
|
|
1235
|
-
businessDomain: opts.businessDomain,
|
|
1236
|
-
});
|
|
1237
|
-
console.log(`Deleted ${opts.otIds}`);
|
|
1238
|
-
return 0;
|
|
1239
|
-
}
|
|
1240
|
-
if (action === "list") {
|
|
1241
|
-
const parsed = parseOntologyQueryFlags(rest);
|
|
1242
|
-
const [knId] = parsed.filteredArgs;
|
|
1243
|
-
if (!knId) {
|
|
1244
|
-
console.error("Usage: kweaver bkn object-type list <kn-id> [options]");
|
|
1245
|
-
return 1;
|
|
1246
|
-
}
|
|
1247
|
-
const token = await ensureValidToken();
|
|
1248
|
-
const body = await listObjectTypes({
|
|
1249
|
-
baseUrl: token.baseUrl,
|
|
1250
|
-
accessToken: token.accessToken,
|
|
1251
|
-
knId,
|
|
1252
|
-
businessDomain: parsed.businessDomain,
|
|
1253
|
-
});
|
|
1254
|
-
console.log(formatCallOutput(body, parsed.pretty));
|
|
1255
|
-
return 0;
|
|
1256
|
-
}
|
|
1257
|
-
if (action === "query") {
|
|
1258
|
-
const options = parseKnObjectTypeQueryArgs(rest);
|
|
1259
|
-
const token = await ensureValidToken();
|
|
1260
|
-
const result = await objectTypeQuery({
|
|
1261
|
-
baseUrl: token.baseUrl,
|
|
1262
|
-
accessToken: token.accessToken,
|
|
1263
|
-
knId: options.knId,
|
|
1264
|
-
otId: options.otId,
|
|
1265
|
-
body: options.body,
|
|
1266
|
-
businessDomain: options.businessDomain,
|
|
1267
|
-
});
|
|
1268
|
-
console.log(formatCallOutput(truncateQueryResult(result), options.pretty));
|
|
1269
|
-
return 0;
|
|
1270
|
-
}
|
|
1271
|
-
if (action === "properties") {
|
|
1272
|
-
const parsed = parseOntologyQueryFlags(rest);
|
|
1273
|
-
const [knId, otId, body] = parsed.filteredArgs;
|
|
1274
|
-
if (!knId || !otId || !body) {
|
|
1275
|
-
console.error(`Usage: kweaver bkn object-type properties <kn-id> <ot-id> '<json>' [options]
|
|
1276
|
-
JSON: {"_instance_identities":[{"<primary-key>":"<value>"}],"properties":["prop1","prop2"]}`);
|
|
1277
|
-
return 1;
|
|
1278
|
-
}
|
|
1279
|
-
const token = await ensureValidToken();
|
|
1280
|
-
const result = await objectTypeProperties({
|
|
1281
|
-
baseUrl: token.baseUrl,
|
|
1282
|
-
accessToken: token.accessToken,
|
|
1283
|
-
knId,
|
|
1284
|
-
otId,
|
|
1285
|
-
body,
|
|
1286
|
-
businessDomain: parsed.businessDomain,
|
|
1287
|
-
});
|
|
1288
|
-
console.log(formatCallOutput(result, parsed.pretty));
|
|
1289
|
-
return 0;
|
|
1290
|
-
}
|
|
1291
|
-
console.error(`Unknown object-type action: ${action}. Use list, get, create, update, delete, query, or properties.`);
|
|
1292
|
-
return 1;
|
|
1293
|
-
}
|
|
1294
|
-
catch (error) {
|
|
1295
|
-
if (error instanceof Error && error.message === "help") {
|
|
1296
|
-
console.log(`kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W [--property '<json>' ...]
|
|
1297
|
-
kweaver bkn object-type update <kn-id> <ot-id> [--name X] [--display-key Y] [--add-property|--update-property '<json>' ...] [--remove-property N ...] [--tags '["a"]'] [--comment S] [--icon I] [--color C] [--branch main]
|
|
1298
|
-
kweaver bkn object-type update <kn-id> <ot-id> '<full-json-body>'
|
|
1299
|
-
kweaver bkn object-type delete <kn-id> <ot-ids> [-y]`);
|
|
1300
|
-
return 0;
|
|
1301
|
-
}
|
|
1302
|
-
console.error(formatHttpError(error));
|
|
1303
|
-
return 1;
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
/** Parse relation-type create args: --name --source --target [--mapping src:tgt ...] */
|
|
1307
|
-
export function parseRelationTypeCreateArgs(args) {
|
|
1308
|
-
let name = "";
|
|
1309
|
-
let source = "";
|
|
1310
|
-
let target = "";
|
|
1311
|
-
let businessDomain = "";
|
|
1312
|
-
let branch = "main";
|
|
1313
|
-
let pretty = true;
|
|
1314
|
-
const mappings = [];
|
|
1315
|
-
const positional = [];
|
|
1316
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1317
|
-
const arg = args[i];
|
|
1318
|
-
if (arg === "--help" || arg === "-h")
|
|
1319
|
-
throw new Error("help");
|
|
1320
|
-
if (arg === "--name" && args[i + 1]) {
|
|
1321
|
-
name = args[++i];
|
|
1322
|
-
continue;
|
|
1323
|
-
}
|
|
1324
|
-
if (arg === "--source" && args[i + 1]) {
|
|
1325
|
-
source = args[++i];
|
|
1326
|
-
continue;
|
|
1327
|
-
}
|
|
1328
|
-
if (arg === "--target" && args[i + 1]) {
|
|
1329
|
-
target = args[++i];
|
|
1330
|
-
continue;
|
|
1331
|
-
}
|
|
1332
|
-
if (arg === "--mapping" && args[i + 1]) {
|
|
1333
|
-
const m = args[++i];
|
|
1334
|
-
if (!m.includes(":")) {
|
|
1335
|
-
throw new Error(`Invalid mapping format '${m}'. Expected source_prop:target_prop.`);
|
|
1336
|
-
}
|
|
1337
|
-
const [s, t] = m.split(":", 2);
|
|
1338
|
-
mappings.push([s, t]);
|
|
1339
|
-
continue;
|
|
1340
|
-
}
|
|
1341
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1342
|
-
businessDomain = args[++i];
|
|
1343
|
-
continue;
|
|
1344
|
-
}
|
|
1345
|
-
if (arg === "--branch" && args[i + 1]) {
|
|
1346
|
-
branch = args[++i];
|
|
1347
|
-
continue;
|
|
1348
|
-
}
|
|
1349
|
-
if (arg === "--pretty") {
|
|
1350
|
-
pretty = true;
|
|
1351
|
-
continue;
|
|
1352
|
-
}
|
|
1353
|
-
if (!arg.startsWith("-"))
|
|
1354
|
-
positional.push(arg);
|
|
1355
|
-
}
|
|
1356
|
-
const knId = positional[0];
|
|
1357
|
-
if (!knId || !name || !source || !target) {
|
|
1358
|
-
throw new Error("Usage: kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]");
|
|
1359
|
-
}
|
|
1360
|
-
const entry = {
|
|
1361
|
-
branch,
|
|
1362
|
-
name,
|
|
1363
|
-
source_object_type_id: source,
|
|
1364
|
-
target_object_type_id: target,
|
|
1365
|
-
type: "direct",
|
|
1366
|
-
mapping_rules: mappings.map(([s, t]) => ({
|
|
1367
|
-
source_property: { name: s },
|
|
1368
|
-
target_property: { name: t },
|
|
1369
|
-
})),
|
|
1370
|
-
};
|
|
1371
|
-
const body = JSON.stringify({ entries: [entry] });
|
|
1372
|
-
if (!businessDomain)
|
|
1373
|
-
businessDomain = resolveBusinessDomain();
|
|
1374
|
-
return { knId, body, businessDomain, branch, pretty };
|
|
1375
|
-
}
|
|
1376
|
-
/** Parse relation-type update args: [--name X] */
|
|
1377
|
-
function parseRelationTypeUpdateArgs(args) {
|
|
1378
|
-
let name;
|
|
1379
|
-
let businessDomain = "";
|
|
1380
|
-
let pretty = true;
|
|
1381
|
-
const positional = [];
|
|
1382
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1383
|
-
const arg = args[i];
|
|
1384
|
-
if (arg === "--help" || arg === "-h")
|
|
1385
|
-
throw new Error("help");
|
|
1386
|
-
if (arg === "--name" && args[i + 1]) {
|
|
1387
|
-
name = args[++i];
|
|
1388
|
-
continue;
|
|
1389
|
-
}
|
|
1390
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1391
|
-
businessDomain = args[++i];
|
|
1392
|
-
continue;
|
|
1393
|
-
}
|
|
1394
|
-
if (arg === "--pretty") {
|
|
1395
|
-
pretty = true;
|
|
1396
|
-
continue;
|
|
1397
|
-
}
|
|
1398
|
-
if (!arg.startsWith("-"))
|
|
1399
|
-
positional.push(arg);
|
|
1400
|
-
}
|
|
1401
|
-
const [knId, rtId] = positional;
|
|
1402
|
-
if (!knId || !rtId) {
|
|
1403
|
-
throw new Error("Usage: kweaver bkn relation-type update <kn-id> <rt-id> [--name X]");
|
|
1404
|
-
}
|
|
1405
|
-
if (name === undefined) {
|
|
1406
|
-
throw new Error("No update fields. Use --name.");
|
|
1407
|
-
}
|
|
1408
|
-
if (!businessDomain)
|
|
1409
|
-
businessDomain = resolveBusinessDomain();
|
|
1410
|
-
return { knId, rtId, body: JSON.stringify({ name }), businessDomain, pretty };
|
|
1411
|
-
}
|
|
1412
|
-
/** Parse relation-type delete args: <kn-id> <rt-ids> [-y] */
|
|
1413
|
-
function parseRelationTypeDeleteArgs(args) {
|
|
1414
|
-
let businessDomain = "";
|
|
1415
|
-
let yes = false;
|
|
1416
|
-
const positional = [];
|
|
1417
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1418
|
-
const arg = args[i];
|
|
1419
|
-
if (arg === "--help" || arg === "-h")
|
|
1420
|
-
throw new Error("help");
|
|
1421
|
-
if (arg === "--yes" || arg === "-y") {
|
|
1422
|
-
yes = true;
|
|
1423
|
-
continue;
|
|
1424
|
-
}
|
|
1425
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
1426
|
-
businessDomain = args[++i];
|
|
1427
|
-
continue;
|
|
1428
|
-
}
|
|
1429
|
-
if (!arg.startsWith("-"))
|
|
1430
|
-
positional.push(arg);
|
|
1431
|
-
}
|
|
1432
|
-
const [knId, rtIds] = positional;
|
|
1433
|
-
if (!knId || !rtIds) {
|
|
1434
|
-
throw new Error("Usage: kweaver bkn relation-type delete <kn-id> <rt-ids> [-y]");
|
|
1435
|
-
}
|
|
1436
|
-
if (!businessDomain)
|
|
1437
|
-
businessDomain = resolveBusinessDomain();
|
|
1438
|
-
return { knId, rtIds, businessDomain, yes };
|
|
1439
|
-
}
|
|
1440
|
-
async function runKnRelationTypeCommand(args) {
|
|
1441
|
-
const [action, ...rest] = args;
|
|
1442
|
-
if (!action || action === "--help" || action === "-h") {
|
|
1443
|
-
console.log(`kweaver bkn relation-type list <kn-id> [--pretty] [-bd value]
|
|
1444
|
-
kweaver bkn relation-type get <kn-id> <rt-id> [--pretty] [-bd value]
|
|
1445
|
-
kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]
|
|
1446
|
-
kweaver bkn relation-type update <kn-id> <rt-id> [--name X]
|
|
1447
|
-
kweaver bkn relation-type delete <kn-id> <rt-ids> [-y]
|
|
1448
|
-
|
|
1449
|
-
list: List relation types (schema) from ontology-manager.
|
|
1450
|
-
get: Get single relation type details.
|
|
1451
|
-
create/update/delete: Schema CRUD.`);
|
|
1452
|
-
return 0;
|
|
1453
|
-
}
|
|
1454
|
-
try {
|
|
1455
|
-
if (action === "get") {
|
|
1456
|
-
const parsed = parseOntologyQueryFlags(rest);
|
|
1457
|
-
const [knId, rtId] = parsed.filteredArgs;
|
|
1458
|
-
if (!knId || !rtId) {
|
|
1459
|
-
console.error("Usage: kweaver bkn relation-type get <kn-id> <rt-id> [options]");
|
|
1460
|
-
return 1;
|
|
1461
|
-
}
|
|
1462
|
-
const token = await ensureValidToken();
|
|
1463
|
-
const body = await getRelationType({
|
|
1464
|
-
baseUrl: token.baseUrl,
|
|
1465
|
-
accessToken: token.accessToken,
|
|
1466
|
-
knId,
|
|
1467
|
-
rtId,
|
|
1468
|
-
businessDomain: parsed.businessDomain,
|
|
1469
|
-
});
|
|
1470
|
-
console.log(formatCallOutput(body, parsed.pretty));
|
|
1471
|
-
return 0;
|
|
1472
|
-
}
|
|
1473
|
-
if (action === "create") {
|
|
1474
|
-
const opts = parseRelationTypeCreateArgs(rest);
|
|
1475
|
-
const token = await ensureValidToken();
|
|
1476
|
-
const body = await createRelationTypes({
|
|
1477
|
-
baseUrl: token.baseUrl,
|
|
1478
|
-
accessToken: token.accessToken,
|
|
1479
|
-
knId: opts.knId,
|
|
1480
|
-
body: opts.body,
|
|
1481
|
-
businessDomain: opts.businessDomain,
|
|
1482
|
-
branch: opts.branch,
|
|
1483
|
-
});
|
|
1484
|
-
console.log(formatCallOutput(body, opts.pretty));
|
|
1485
|
-
return 0;
|
|
1486
|
-
}
|
|
1487
|
-
if (action === "update") {
|
|
1488
|
-
const opts = parseRelationTypeUpdateArgs(rest);
|
|
1489
|
-
const token = await ensureValidToken();
|
|
1490
|
-
const body = await updateRelationType({
|
|
1491
|
-
baseUrl: token.baseUrl,
|
|
1492
|
-
accessToken: token.accessToken,
|
|
1493
|
-
knId: opts.knId,
|
|
1494
|
-
rtId: opts.rtId,
|
|
1495
|
-
body: opts.body,
|
|
1496
|
-
businessDomain: opts.businessDomain,
|
|
1497
|
-
});
|
|
1498
|
-
console.log(formatCallOutput(body, opts.pretty));
|
|
1499
|
-
return 0;
|
|
1500
|
-
}
|
|
1501
|
-
if (action === "delete") {
|
|
1502
|
-
const opts = parseRelationTypeDeleteArgs(rest);
|
|
1503
|
-
if (!opts.yes) {
|
|
1504
|
-
const confirmed = await confirmYes(`Delete relation type(s) ${opts.rtIds}?`);
|
|
1505
|
-
if (!confirmed) {
|
|
1506
|
-
console.error("Aborted.");
|
|
1507
|
-
return 1;
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
const token = await ensureValidToken();
|
|
1511
|
-
await deleteRelationTypes({
|
|
1512
|
-
baseUrl: token.baseUrl,
|
|
1513
|
-
accessToken: token.accessToken,
|
|
1514
|
-
knId: opts.knId,
|
|
1515
|
-
rtIds: opts.rtIds,
|
|
1516
|
-
businessDomain: opts.businessDomain,
|
|
1517
|
-
});
|
|
1518
|
-
console.log(`Deleted ${opts.rtIds}`);
|
|
1519
|
-
return 0;
|
|
1520
|
-
}
|
|
1521
|
-
if (action === "list") {
|
|
1522
|
-
const parsed = parseOntologyQueryFlags(rest);
|
|
1523
|
-
const [knId] = parsed.filteredArgs;
|
|
1524
|
-
if (!knId) {
|
|
1525
|
-
console.error("Usage: kweaver bkn relation-type list <kn-id> [options]");
|
|
1526
|
-
return 1;
|
|
1527
|
-
}
|
|
1528
|
-
const token = await ensureValidToken();
|
|
1529
|
-
const body = await listRelationTypes({
|
|
1530
|
-
baseUrl: token.baseUrl,
|
|
1531
|
-
accessToken: token.accessToken,
|
|
1532
|
-
knId,
|
|
1533
|
-
businessDomain: parsed.businessDomain,
|
|
1534
|
-
});
|
|
1535
|
-
console.log(formatCallOutput(body, parsed.pretty));
|
|
1536
|
-
return 0;
|
|
1537
|
-
}
|
|
1538
|
-
console.error(`Unknown relation-type action: ${action}. Use list, get, create, update, or delete.`);
|
|
1539
|
-
return 1;
|
|
1540
|
-
}
|
|
1541
|
-
catch (error) {
|
|
1542
|
-
if (error instanceof Error && error.message === "help") {
|
|
1543
|
-
console.log(`kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]
|
|
1544
|
-
kweaver bkn relation-type update <kn-id> <rt-id> [--name X]
|
|
1545
|
-
kweaver bkn relation-type delete <kn-id> <rt-ids> [-y]`);
|
|
1546
|
-
return 0;
|
|
1547
|
-
}
|
|
1548
|
-
console.error(formatHttpError(error));
|
|
1549
|
-
return 1;
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
async function runKnSubgraphCommand(args) {
|
|
1553
|
-
let filteredArgs;
|
|
1554
|
-
let pretty;
|
|
1555
|
-
let businessDomain;
|
|
1556
|
-
try {
|
|
1557
|
-
const parsed = parseOntologyQueryFlags(args);
|
|
1558
|
-
filteredArgs = parsed.filteredArgs;
|
|
1559
|
-
pretty = parsed.pretty;
|
|
1560
|
-
businessDomain = parsed.businessDomain;
|
|
1561
|
-
}
|
|
1562
|
-
catch (error) {
|
|
1563
|
-
if (error instanceof Error && error.message === "help") {
|
|
1564
|
-
console.log(`kweaver bkn subgraph <kn-id> '<json>' [--pretty] [-bd value]
|
|
1565
|
-
|
|
1566
|
-
Query subgraph via ontology-query API. JSON body format see references/json-formats.md#subgraph.`);
|
|
1567
|
-
return 0;
|
|
1568
|
-
}
|
|
1569
|
-
throw error;
|
|
1570
|
-
}
|
|
1571
|
-
const [knId, body] = filteredArgs;
|
|
1572
|
-
if (!knId || !body) {
|
|
1573
|
-
console.error("Usage: kweaver bkn subgraph <kn-id> '<json>' [options]");
|
|
1574
|
-
return 1;
|
|
1575
|
-
}
|
|
1576
|
-
try {
|
|
1577
|
-
// Auto-detect query_type=relation_path when body contains source_object_type_id
|
|
1578
|
-
let queryType;
|
|
1579
|
-
try {
|
|
1580
|
-
const parsedBody = JSON.parse(body);
|
|
1581
|
-
if (parsedBody.source_object_type_id) {
|
|
1582
|
-
queryType = "relation_path";
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
catch {
|
|
1586
|
-
// Not valid JSON — let the API return the error
|
|
1587
|
-
}
|
|
1588
|
-
const token = await ensureValidToken();
|
|
1589
|
-
const result = await subgraph({
|
|
1590
|
-
baseUrl: token.baseUrl,
|
|
1591
|
-
accessToken: token.accessToken,
|
|
1592
|
-
knId,
|
|
1593
|
-
body,
|
|
1594
|
-
businessDomain,
|
|
1595
|
-
queryType,
|
|
1596
|
-
});
|
|
1597
|
-
if (result.length > 100_000) {
|
|
1598
|
-
console.error(`[warn] Response is ${(result.length / 1024).toFixed(0)}KB. Consider narrowing the subgraph query.`);
|
|
1599
|
-
}
|
|
1600
|
-
console.log(formatCallOutput(result, pretty));
|
|
1601
|
-
return 0;
|
|
1602
|
-
}
|
|
1603
|
-
catch (error) {
|
|
1604
|
-
console.error(formatHttpError(error));
|
|
1605
|
-
return 1;
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
const TERMINAL_STATUSES = ["SUCCESS", "FAILED", "CANCELLED"];
|
|
1609
|
-
function extractExecutionId(body) {
|
|
1610
|
-
try {
|
|
1611
|
-
const data = JSON.parse(body);
|
|
1612
|
-
const id = data.execution_id ?? data.id;
|
|
1613
|
-
return typeof id === "string" ? id : null;
|
|
1614
|
-
}
|
|
1615
|
-
catch {
|
|
1616
|
-
return null;
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
function extractStatus(body) {
|
|
1620
|
-
try {
|
|
1621
|
-
const data = JSON.parse(body);
|
|
1622
|
-
const status = data.status;
|
|
1623
|
-
return typeof status === "string" ? status : "";
|
|
1624
|
-
}
|
|
1625
|
-
catch {
|
|
1626
|
-
return "";
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
async function runKnActionTypeCommand(args) {
|
|
1630
|
-
const [action, ...rest] = args;
|
|
1631
|
-
if (!action || action === "--help" || action === "-h") {
|
|
1632
|
-
console.log(`kweaver bkn action-type list <kn-id> [--pretty] [-bd value]
|
|
1633
|
-
kweaver bkn action-type query <kn-id> <at-id> '<json>' [--pretty] [-bd value]
|
|
1634
|
-
kweaver bkn action-type execute <kn-id> <at-id> '<json>' [--pretty] [-bd value] [--wait|--no-wait] [--timeout n]
|
|
1635
|
-
|
|
1636
|
-
list: List action types (schema) from ontology-manager.
|
|
1637
|
-
query/execute: Query or execute actions. execute has side effects - only use when explicitly requested.
|
|
1638
|
-
--wait (default) Poll until execution completes
|
|
1639
|
-
--no-wait Return immediately after starting execution
|
|
1640
|
-
--timeout <seconds> Max wait time when --wait (default: 300)`);
|
|
1641
|
-
return 0;
|
|
1642
|
-
}
|
|
1643
|
-
if (action === "list") {
|
|
1644
|
-
try {
|
|
1645
|
-
const parsed = parseOntologyQueryFlags(rest);
|
|
1646
|
-
const [knId] = parsed.filteredArgs;
|
|
1647
|
-
if (!knId) {
|
|
1648
|
-
console.error("Usage: kweaver bkn action-type list <kn-id> [options]");
|
|
1649
|
-
return 1;
|
|
1650
|
-
}
|
|
1651
|
-
const token = await ensureValidToken();
|
|
1652
|
-
const body = await listActionTypes({
|
|
1653
|
-
baseUrl: token.baseUrl,
|
|
1654
|
-
accessToken: token.accessToken,
|
|
1655
|
-
knId,
|
|
1656
|
-
businessDomain: parsed.businessDomain,
|
|
1657
|
-
});
|
|
1658
|
-
console.log(formatCallOutput(body, parsed.pretty));
|
|
1659
|
-
return 0;
|
|
1660
|
-
}
|
|
1661
|
-
catch (error) {
|
|
1662
|
-
console.error(formatHttpError(error));
|
|
1663
|
-
return 1;
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
if (action === "query") {
|
|
1667
|
-
let filteredArgs;
|
|
1668
|
-
let pretty;
|
|
1669
|
-
let businessDomain;
|
|
1670
|
-
try {
|
|
1671
|
-
const parsed = parseOntologyQueryFlags(rest);
|
|
1672
|
-
filteredArgs = parsed.filteredArgs;
|
|
1673
|
-
pretty = parsed.pretty;
|
|
1674
|
-
businessDomain = parsed.businessDomain;
|
|
1675
|
-
}
|
|
1676
|
-
catch (error) {
|
|
1677
|
-
if (error instanceof Error && error.message === "help")
|
|
1678
|
-
return 0;
|
|
1679
|
-
throw error;
|
|
1680
|
-
}
|
|
1681
|
-
const [knId, atId, body] = filteredArgs;
|
|
1682
|
-
if (!knId || !atId || !body) {
|
|
1683
|
-
console.error("Usage: kweaver bkn action-type query <kn-id> <at-id> '<json>' [options]");
|
|
1684
|
-
return 1;
|
|
1685
|
-
}
|
|
1686
|
-
try {
|
|
1687
|
-
const token = await ensureValidToken();
|
|
1688
|
-
const result = await actionTypeQuery({
|
|
1689
|
-
baseUrl: token.baseUrl,
|
|
1690
|
-
accessToken: token.accessToken,
|
|
1691
|
-
knId,
|
|
1692
|
-
atId,
|
|
1693
|
-
body,
|
|
1694
|
-
businessDomain,
|
|
1695
|
-
});
|
|
1696
|
-
console.log(formatCallOutput(result, pretty));
|
|
1697
|
-
return 0;
|
|
1698
|
-
}
|
|
1699
|
-
catch (error) {
|
|
1700
|
-
console.error(formatHttpError(error));
|
|
1701
|
-
return 1;
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
if (action === "execute") {
|
|
1705
|
-
let options;
|
|
1706
|
-
try {
|
|
1707
|
-
options = parseKnActionTypeExecuteArgs(rest);
|
|
1708
|
-
}
|
|
1709
|
-
catch (error) {
|
|
1710
|
-
if (error instanceof Error && error.message === "help")
|
|
1711
|
-
return 0;
|
|
1712
|
-
console.error(formatHttpError(error));
|
|
1713
|
-
return 1;
|
|
1714
|
-
}
|
|
1715
|
-
try {
|
|
1716
|
-
const token = await ensureValidToken();
|
|
1717
|
-
const base = {
|
|
1718
|
-
baseUrl: token.baseUrl,
|
|
1719
|
-
accessToken: token.accessToken,
|
|
1720
|
-
knId: options.knId,
|
|
1721
|
-
atId: options.atId,
|
|
1722
|
-
body: options.body,
|
|
1723
|
-
businessDomain: options.businessDomain,
|
|
1724
|
-
};
|
|
1725
|
-
const result = await actionTypeExecute(base);
|
|
1726
|
-
if (!options.wait) {
|
|
1727
|
-
console.log(formatCallOutput(result, options.pretty));
|
|
1728
|
-
return 0;
|
|
1729
|
-
}
|
|
1730
|
-
const executionId = extractExecutionId(result);
|
|
1731
|
-
if (!executionId) {
|
|
1732
|
-
console.log(formatCallOutput(result, options.pretty));
|
|
1733
|
-
return 0;
|
|
1734
|
-
}
|
|
1735
|
-
let lastBody = result;
|
|
1736
|
-
try {
|
|
1737
|
-
lastBody = await pollWithBackoff({
|
|
1738
|
-
fn: async () => {
|
|
1739
|
-
const status = extractStatus(lastBody);
|
|
1740
|
-
if (TERMINAL_STATUSES.includes(status.toUpperCase())) {
|
|
1741
|
-
return { done: true, value: lastBody };
|
|
1742
|
-
}
|
|
1743
|
-
lastBody = await actionExecutionGet({
|
|
1744
|
-
baseUrl: token.baseUrl,
|
|
1745
|
-
accessToken: token.accessToken,
|
|
1746
|
-
knId: options.knId,
|
|
1747
|
-
executionId,
|
|
1748
|
-
businessDomain: options.businessDomain,
|
|
1749
|
-
});
|
|
1750
|
-
return { done: false, value: lastBody };
|
|
1751
|
-
},
|
|
1752
|
-
interval: 2000,
|
|
1753
|
-
timeout: options.timeout * 1000,
|
|
1754
|
-
});
|
|
1755
|
-
}
|
|
1756
|
-
catch {
|
|
1757
|
-
console.error(`Action execution did not complete within ${options.timeout}s`);
|
|
1758
|
-
console.log(formatCallOutput(lastBody, options.pretty));
|
|
1759
|
-
return 1;
|
|
1760
|
-
}
|
|
1761
|
-
const finalStatus = extractStatus(lastBody);
|
|
1762
|
-
console.log(formatCallOutput(lastBody, options.pretty));
|
|
1763
|
-
return finalStatus.toUpperCase() === "SUCCESS" ? 0 : 1;
|
|
1764
|
-
}
|
|
1765
|
-
catch (error) {
|
|
1766
|
-
console.error(formatHttpError(error));
|
|
1767
|
-
return 1;
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
console.error(`Unknown action-type action: ${action}. Use list, query, or execute.`);
|
|
1771
|
-
return 1;
|
|
1772
|
-
}
|
|
1773
|
-
async function runKnActionExecutionCommand(args) {
|
|
1774
|
-
let filteredArgs;
|
|
1775
|
-
let pretty;
|
|
1776
|
-
let businessDomain;
|
|
1777
|
-
try {
|
|
1778
|
-
const parsed = parseOntologyQueryFlags(args);
|
|
1779
|
-
filteredArgs = parsed.filteredArgs;
|
|
1780
|
-
pretty = parsed.pretty;
|
|
1781
|
-
businessDomain = parsed.businessDomain;
|
|
1782
|
-
}
|
|
1783
|
-
catch (error) {
|
|
1784
|
-
if (error instanceof Error && error.message === "help") {
|
|
1785
|
-
console.log(`kweaver bkn action-execution get <kn-id> <execution-id> [--pretty] [-bd value]
|
|
1786
|
-
|
|
1787
|
-
Get action execution status.`);
|
|
1788
|
-
return 0;
|
|
1789
|
-
}
|
|
1790
|
-
throw error;
|
|
1791
|
-
}
|
|
1792
|
-
const [subAction, knId, executionId] = filteredArgs;
|
|
1793
|
-
if (subAction !== "get" || !knId || !executionId) {
|
|
1794
|
-
console.error("Usage: kweaver bkn action-execution get <kn-id> <execution-id> [options]");
|
|
1795
|
-
return 1;
|
|
1796
|
-
}
|
|
1797
|
-
try {
|
|
1798
|
-
const token = await ensureValidToken();
|
|
1799
|
-
const result = await actionExecutionGet({
|
|
1800
|
-
baseUrl: token.baseUrl,
|
|
1801
|
-
accessToken: token.accessToken,
|
|
1802
|
-
knId,
|
|
1803
|
-
executionId,
|
|
1804
|
-
businessDomain,
|
|
1805
|
-
});
|
|
1806
|
-
console.log(formatCallOutput(result, pretty));
|
|
1807
|
-
return 0;
|
|
1808
|
-
}
|
|
1809
|
-
catch (error) {
|
|
1810
|
-
console.error(formatHttpError(error));
|
|
1811
|
-
return 1;
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
async function runKnActionLogCommand(args) {
|
|
1815
|
-
const [action, ...rest] = args;
|
|
1816
|
-
if (!action || action === "--help" || action === "-h") {
|
|
1817
|
-
console.log(`kweaver bkn action-log list <kn-id> [options]
|
|
1818
|
-
kweaver bkn action-log get <kn-id> <log-id> [options]
|
|
1819
|
-
kweaver bkn action-log cancel <kn-id> <log-id> [options]
|
|
1820
|
-
|
|
1821
|
-
List/get execution logs. cancel has side effects - only use when explicitly requested.
|
|
1822
|
-
Options for list: --limit, --need-total, --action-type-id, --status, --trigger-type, --search-after`);
|
|
1823
|
-
return 0;
|
|
1824
|
-
}
|
|
1825
|
-
let pretty = true;
|
|
1826
|
-
let businessDomain = "";
|
|
1827
|
-
let limit = 30;
|
|
1828
|
-
let needTotal;
|
|
1829
|
-
let actionTypeId;
|
|
1830
|
-
let status;
|
|
1831
|
-
let triggerType;
|
|
1832
|
-
let searchAfter;
|
|
1833
|
-
const filteredArgs = [];
|
|
1834
|
-
for (let i = 0; i < rest.length; i += 1) {
|
|
1835
|
-
const arg = rest[i];
|
|
1836
|
-
if (arg === "--help" || arg === "-h") {
|
|
1837
|
-
throw new Error("help");
|
|
1838
|
-
}
|
|
1839
|
-
if (arg === "--pretty") {
|
|
1840
|
-
pretty = true;
|
|
1841
|
-
continue;
|
|
1842
|
-
}
|
|
1843
|
-
if ((arg === "-bd" || arg === "--biz-domain") && rest[i + 1]) {
|
|
1844
|
-
businessDomain = rest[i + 1];
|
|
1845
|
-
i += 1;
|
|
1846
|
-
continue;
|
|
1847
|
-
}
|
|
1848
|
-
if (arg === "--limit" && rest[i + 1]) {
|
|
1849
|
-
limit = parseInt(rest[i + 1], 10);
|
|
1850
|
-
i += 1;
|
|
1851
|
-
continue;
|
|
1852
|
-
}
|
|
1853
|
-
if (arg === "--need-total" && rest[i + 1]) {
|
|
1854
|
-
needTotal = rest[i + 1].toLowerCase() === "true";
|
|
1855
|
-
i += 1;
|
|
1856
|
-
continue;
|
|
1857
|
-
}
|
|
1858
|
-
if (arg === "--action-type-id" && rest[i + 1]) {
|
|
1859
|
-
actionTypeId = rest[i + 1];
|
|
1860
|
-
i += 1;
|
|
1861
|
-
continue;
|
|
1862
|
-
}
|
|
1863
|
-
if (arg === "--status" && rest[i + 1]) {
|
|
1864
|
-
status = rest[i + 1];
|
|
1865
|
-
i += 1;
|
|
1866
|
-
continue;
|
|
1867
|
-
}
|
|
1868
|
-
if (arg === "--trigger-type" && rest[i + 1]) {
|
|
1869
|
-
triggerType = rest[i + 1];
|
|
1870
|
-
i += 1;
|
|
1871
|
-
continue;
|
|
1872
|
-
}
|
|
1873
|
-
if (arg === "--search-after" && rest[i + 1]) {
|
|
1874
|
-
searchAfter = rest[i + 1];
|
|
1875
|
-
i += 1;
|
|
1876
|
-
continue;
|
|
1877
|
-
}
|
|
1878
|
-
filteredArgs.push(arg);
|
|
1879
|
-
}
|
|
1880
|
-
if (!businessDomain)
|
|
1881
|
-
businessDomain = resolveBusinessDomain();
|
|
1882
|
-
try {
|
|
1883
|
-
const token = await ensureValidToken();
|
|
1884
|
-
const base = {
|
|
1885
|
-
baseUrl: token.baseUrl,
|
|
1886
|
-
accessToken: token.accessToken,
|
|
1887
|
-
businessDomain,
|
|
1888
|
-
};
|
|
1889
|
-
if (action === "list") {
|
|
1890
|
-
const [knId] = filteredArgs;
|
|
1891
|
-
if (!knId) {
|
|
1892
|
-
console.error("Usage: kweaver bkn action-log list <kn-id> [options]");
|
|
1893
|
-
return 1;
|
|
1894
|
-
}
|
|
1895
|
-
const result = await actionLogsList({
|
|
1896
|
-
...base,
|
|
1897
|
-
knId,
|
|
1898
|
-
limit,
|
|
1899
|
-
needTotal,
|
|
1900
|
-
actionTypeId,
|
|
1901
|
-
status,
|
|
1902
|
-
triggerType,
|
|
1903
|
-
searchAfter,
|
|
1904
|
-
});
|
|
1905
|
-
console.log(formatCallOutput(result, pretty));
|
|
1906
|
-
return 0;
|
|
1907
|
-
}
|
|
1908
|
-
if (action === "get") {
|
|
1909
|
-
const [knId, logId] = filteredArgs;
|
|
1910
|
-
if (!knId || !logId) {
|
|
1911
|
-
console.error("Usage: kweaver bkn action-log get <kn-id> <log-id> [options]");
|
|
1912
|
-
return 1;
|
|
1913
|
-
}
|
|
1914
|
-
const result = await actionLogGet({ ...base, knId, logId });
|
|
1915
|
-
console.log(formatCallOutput(result, pretty));
|
|
1916
|
-
return 0;
|
|
1917
|
-
}
|
|
1918
|
-
if (action === "cancel") {
|
|
1919
|
-
const [knId, logId] = filteredArgs;
|
|
1920
|
-
if (!knId || !logId) {
|
|
1921
|
-
console.error("Usage: kweaver bkn action-log cancel <kn-id> <log-id> [options]");
|
|
1922
|
-
return 1;
|
|
1923
|
-
}
|
|
1924
|
-
const result = await actionLogCancel({ ...base, knId, logId });
|
|
1925
|
-
console.log(formatCallOutput(result, pretty));
|
|
1926
|
-
return 0;
|
|
1927
|
-
}
|
|
1928
|
-
console.error(`Unknown action-log action: ${action}. Use list, get, or cancel.`);
|
|
1929
|
-
return 1;
|
|
1930
|
-
}
|
|
1931
|
-
catch (error) {
|
|
1932
|
-
console.error(formatHttpError(error));
|
|
1933
|
-
return 1;
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
async function runKnListCommand(args) {
|
|
1937
|
-
let options;
|
|
1938
|
-
try {
|
|
1939
|
-
options = parseKnListArgs(args);
|
|
1940
|
-
}
|
|
1941
|
-
catch (error) {
|
|
1942
|
-
if (error instanceof Error && error.message === "help") {
|
|
1943
|
-
console.log(KN_LIST_HELP);
|
|
1944
|
-
return 0;
|
|
1945
|
-
}
|
|
1946
|
-
console.error(formatHttpError(error));
|
|
1947
|
-
return 1;
|
|
1948
|
-
}
|
|
1949
|
-
try {
|
|
1950
|
-
const token = await ensureValidToken();
|
|
1951
|
-
const body = await listKnowledgeNetworks({
|
|
1952
|
-
baseUrl: token.baseUrl,
|
|
1953
|
-
accessToken: token.accessToken,
|
|
1954
|
-
businessDomain: options.businessDomain,
|
|
1955
|
-
offset: options.offset,
|
|
1956
|
-
limit: options.limit,
|
|
1957
|
-
sort: options.sort,
|
|
1958
|
-
direction: options.direction,
|
|
1959
|
-
name_pattern: options.name_pattern,
|
|
1960
|
-
tag: options.tag,
|
|
1961
|
-
});
|
|
1962
|
-
if (body) {
|
|
1963
|
-
console.log(options.verbose
|
|
1964
|
-
? formatCallOutput(body, options.pretty)
|
|
1965
|
-
: formatSimpleKnList(body, options.pretty, options.detail));
|
|
1966
|
-
}
|
|
1967
|
-
return 0;
|
|
1968
|
-
}
|
|
1969
|
-
catch (error) {
|
|
1970
|
-
console.error(formatHttpError(error));
|
|
1971
|
-
return 1;
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
const KN_LIST_HELP = `kweaver bkn list [options]
|
|
1975
|
-
|
|
1976
|
-
List business knowledge networks from the ontology-manager API.
|
|
1977
|
-
|
|
1978
|
-
Options:
|
|
1979
|
-
--offset <n> Offset (default: 0)
|
|
1980
|
-
--limit <n> Limit (default: 30)
|
|
1981
|
-
--sort <key> Sort field (default: update_time)
|
|
1982
|
-
--direction <asc|desc> Sort direction (default: desc)
|
|
1983
|
-
--name-pattern <s> Filter by name pattern
|
|
1984
|
-
--tag <s> Filter by tag
|
|
1985
|
-
--detail Include the detail field in simplified output
|
|
1986
|
-
--verbose, -v Show full JSON response
|
|
1987
|
-
-bd, --biz-domain <value> Business domain (default: bd_public)
|
|
1988
|
-
--pretty Pretty-print JSON output (applies to both modes)`;
|
|
1989
|
-
const KN_GET_HELP = `kweaver bkn get <kn-id> [options]
|
|
1990
|
-
|
|
1991
|
-
Get knowledge network detail.
|
|
1992
|
-
|
|
1993
|
-
Options:
|
|
1994
|
-
--stats Include statistics
|
|
1995
|
-
--export Export mode (include sub-types)
|
|
1996
|
-
-bd, --biz-domain <value> Business domain (default: bd_public)
|
|
1997
|
-
--pretty Pretty-print JSON output`;
|
|
1998
|
-
const KN_CREATE_HELP = `kweaver bkn create [options]
|
|
1999
|
-
|
|
2000
|
-
Create a knowledge network.
|
|
2001
|
-
|
|
2002
|
-
Options:
|
|
2003
|
-
--name <s> Name (required unless --body-file)
|
|
2004
|
-
--comment <s> Comment
|
|
2005
|
-
--tags <t1,t2> Comma-separated tags
|
|
2006
|
-
--icon <s> Icon
|
|
2007
|
-
--color <s> Color
|
|
2008
|
-
--branch <s> Branch (default: main)
|
|
2009
|
-
--base-branch <s> Base branch (default: empty for main)
|
|
2010
|
-
--body-file <path> Read full JSON body from file (cannot combine with flags above)
|
|
2011
|
-
--import-mode <normal|ignore|overwrite> Import mode (default: normal)
|
|
2012
|
-
--validate-dependency <true|false> Validate dependency (default: true)
|
|
2013
|
-
-bd, --biz-domain <value> Business domain (default: bd_public)
|
|
2014
|
-
--pretty Pretty-print JSON output`;
|
|
2015
|
-
const KN_UPDATE_HELP = `kweaver bkn update <kn-id> [options]
|
|
2016
|
-
|
|
2017
|
-
Update a knowledge network.
|
|
2018
|
-
|
|
2019
|
-
Options:
|
|
2020
|
-
--name <s> Name (required unless --body-file)
|
|
2021
|
-
--comment <s> Comment
|
|
2022
|
-
--tags <t1,t2> Comma-separated tags
|
|
2023
|
-
--icon <s> Icon
|
|
2024
|
-
--color <s> Color
|
|
2025
|
-
--branch <s> Branch (default: main)
|
|
2026
|
-
--base-branch <s> Base branch (default: empty for main)
|
|
2027
|
-
--body-file <path> Read full JSON body from file (cannot combine with flags above)
|
|
2028
|
-
-bd, --biz-domain <value> Business domain (default: bd_public)
|
|
2029
|
-
--pretty Pretty-print JSON output`;
|
|
2030
|
-
const KN_DELETE_HELP = `kweaver bkn delete <kn-id>
|
|
2031
|
-
|
|
2032
|
-
Delete a knowledge network and its object types, relation types, action types, and concept groups.
|
|
2033
|
-
|
|
2034
|
-
Options:
|
|
2035
|
-
--yes, -y Skip confirmation prompt
|
|
2036
|
-
-bd, --biz-domain <value> Business domain (default: bd_public)`;
|
|
2037
|
-
async function runKnGetCommand(args) {
|
|
2038
|
-
let options;
|
|
2039
|
-
try {
|
|
2040
|
-
options = parseKnGetArgs(args);
|
|
2041
|
-
}
|
|
2042
|
-
catch (error) {
|
|
2043
|
-
if (error instanceof Error && error.message === "help") {
|
|
2044
|
-
console.log(KN_GET_HELP);
|
|
2045
|
-
return 0;
|
|
2046
|
-
}
|
|
2047
|
-
console.error(formatHttpError(error));
|
|
2048
|
-
return 1;
|
|
593
|
+
console.error(formatHttpError(error));
|
|
594
|
+
return 1;
|
|
2049
595
|
}
|
|
2050
596
|
try {
|
|
2051
597
|
const token = await ensureValidToken();
|
|
@@ -2054,303 +600,8 @@ async function runKnGetCommand(args) {
|
|
|
2054
600
|
accessToken: token.accessToken,
|
|
2055
601
|
knId: options.knId,
|
|
2056
602
|
businessDomain: options.businessDomain,
|
|
2057
|
-
mode: options.export ? "export" : undefined,
|
|
2058
|
-
include_statistics: options.stats ? true : undefined,
|
|
2059
|
-
});
|
|
2060
|
-
if (body) {
|
|
2061
|
-
console.log(formatCallOutput(body, options.pretty));
|
|
2062
|
-
}
|
|
2063
|
-
return 0;
|
|
2064
|
-
}
|
|
2065
|
-
catch (error) {
|
|
2066
|
-
console.error(formatHttpError(error));
|
|
2067
|
-
return 1;
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
async function runKnCreateCommand(args) {
|
|
2071
|
-
let options;
|
|
2072
|
-
try {
|
|
2073
|
-
options = parseKnCreateArgs(args);
|
|
2074
|
-
}
|
|
2075
|
-
catch (error) {
|
|
2076
|
-
if (error instanceof Error && error.message === "help") {
|
|
2077
|
-
console.log(KN_CREATE_HELP);
|
|
2078
|
-
return 0;
|
|
2079
|
-
}
|
|
2080
|
-
console.error(formatHttpError(error));
|
|
2081
|
-
return 1;
|
|
2082
|
-
}
|
|
2083
|
-
try {
|
|
2084
|
-
const token = await ensureValidToken();
|
|
2085
|
-
const body = await createKnowledgeNetwork({
|
|
2086
|
-
baseUrl: token.baseUrl,
|
|
2087
|
-
accessToken: token.accessToken,
|
|
2088
|
-
body: options.body,
|
|
2089
|
-
businessDomain: options.businessDomain,
|
|
2090
|
-
import_mode: options.import_mode,
|
|
2091
|
-
validate_dependency: options.validate_dependency,
|
|
2092
|
-
});
|
|
2093
|
-
if (body) {
|
|
2094
|
-
console.log(formatCallOutput(body, options.pretty));
|
|
2095
|
-
}
|
|
2096
|
-
return 0;
|
|
2097
|
-
}
|
|
2098
|
-
catch (error) {
|
|
2099
|
-
console.error(formatHttpError(error));
|
|
2100
|
-
return 1;
|
|
2101
|
-
}
|
|
2102
|
-
}
|
|
2103
|
-
const KN_CREATE_FROM_DS_HELP = `kweaver bkn create-from-ds <ds-id> --name X [options]
|
|
2104
|
-
|
|
2105
|
-
Create a knowledge network from a datasource (dataviews + object types + optional build).
|
|
2106
|
-
|
|
2107
|
-
Options:
|
|
2108
|
-
--name <s> Knowledge network name (required)
|
|
2109
|
-
--tables <a,b> Comma-separated table names (default: all)
|
|
2110
|
-
--build (default) Build after creation
|
|
2111
|
-
--no-build Skip build after creation
|
|
2112
|
-
--timeout <n> Build timeout in seconds (default: 300)
|
|
2113
|
-
-bd, --biz-domain Business domain (default: bd_public)
|
|
2114
|
-
--pretty Pretty-print output (default)`;
|
|
2115
|
-
function parseKnCreateFromDsArgs(args) {
|
|
2116
|
-
let dsId = "";
|
|
2117
|
-
let name = "";
|
|
2118
|
-
let tablesStr = "";
|
|
2119
|
-
let build = true;
|
|
2120
|
-
let timeout = 300;
|
|
2121
|
-
let businessDomain = "";
|
|
2122
|
-
let pretty = true;
|
|
2123
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
2124
|
-
const arg = args[i];
|
|
2125
|
-
if (arg === "--help" || arg === "-h")
|
|
2126
|
-
throw new Error("help");
|
|
2127
|
-
if (arg === "--name" && args[i + 1]) {
|
|
2128
|
-
name = args[++i];
|
|
2129
|
-
continue;
|
|
2130
|
-
}
|
|
2131
|
-
if (arg === "--tables" && args[i + 1]) {
|
|
2132
|
-
tablesStr = args[++i];
|
|
2133
|
-
continue;
|
|
2134
|
-
}
|
|
2135
|
-
if (arg === "--build") {
|
|
2136
|
-
build = true;
|
|
2137
|
-
continue;
|
|
2138
|
-
}
|
|
2139
|
-
if (arg === "--no-build") {
|
|
2140
|
-
build = false;
|
|
2141
|
-
continue;
|
|
2142
|
-
}
|
|
2143
|
-
if (arg === "--timeout" && args[i + 1]) {
|
|
2144
|
-
timeout = parseInt(args[++i], 10);
|
|
2145
|
-
if (Number.isNaN(timeout) || timeout < 1)
|
|
2146
|
-
timeout = 300;
|
|
2147
|
-
continue;
|
|
2148
|
-
}
|
|
2149
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
2150
|
-
businessDomain = args[++i];
|
|
2151
|
-
continue;
|
|
2152
|
-
}
|
|
2153
|
-
if (arg === "--pretty") {
|
|
2154
|
-
pretty = true;
|
|
2155
|
-
continue;
|
|
2156
|
-
}
|
|
2157
|
-
if (!arg.startsWith("-") && !dsId) {
|
|
2158
|
-
dsId = arg;
|
|
2159
|
-
}
|
|
2160
|
-
}
|
|
2161
|
-
const tables = tablesStr ? tablesStr.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
2162
|
-
if (!dsId || !name) {
|
|
2163
|
-
throw new Error("Usage: kweaver bkn create-from-ds <ds-id> --name X [options]");
|
|
2164
|
-
}
|
|
2165
|
-
if (!businessDomain)
|
|
2166
|
-
businessDomain = resolveBusinessDomain();
|
|
2167
|
-
return { dsId, name, tables, build, timeout, businessDomain, pretty };
|
|
2168
|
-
}
|
|
2169
|
-
/** Sanitize a table name into a BKN-safe ID (alphanumeric + underscore). */
|
|
2170
|
-
function sanitizeBknId(name) {
|
|
2171
|
-
return name.replace(/[^a-zA-Z0-9_]/g, "_").replace(/^(\d)/, "_$1");
|
|
2172
|
-
}
|
|
2173
|
-
/** Generate a BKN ObjectType YAML markdown file for a table. */
|
|
2174
|
-
function generateObjectTypeBkn(tableName, dvId, pk, dk, columns) {
|
|
2175
|
-
const safeId = sanitizeBknId(tableName);
|
|
2176
|
-
const header = `## ObjectType: ${safeId}\n\n**${tableName}**\n`;
|
|
2177
|
-
const dsTable = `### Data Source\n\n| Type | ID | Name |\n|------|-----|------|\n| data_view | ${dvId} | ${tableName} |\n`;
|
|
2178
|
-
const dpHeader = `### Data Properties\n\n| Property | Display Name | Type | Primary Key | Display Key |\n|----------|-------------|------|-------------|-------------|\n`;
|
|
2179
|
-
const dpRows = columns.map((c) => {
|
|
2180
|
-
const isPk = c.name === pk ? "yes" : "no";
|
|
2181
|
-
const isDk = c.name === dk ? "yes" : "no";
|
|
2182
|
-
return `| ${c.name} | ${c.name} | string | ${isPk} | ${isDk} |`;
|
|
2183
|
-
}).join("\n");
|
|
2184
|
-
const frontmatter = `---\ntype: object_type\nid: ${safeId}\nname: ${tableName}\n---\n\n`;
|
|
2185
|
-
return `${frontmatter}${header}\n${dsTable}\n${dpHeader}${dpRows}\n`;
|
|
2186
|
-
}
|
|
2187
|
-
async function runKnCreateFromDsCommand(args, sampleRows) {
|
|
2188
|
-
let options;
|
|
2189
|
-
try {
|
|
2190
|
-
options = parseKnCreateFromDsArgs(args);
|
|
2191
|
-
}
|
|
2192
|
-
catch (error) {
|
|
2193
|
-
if (error instanceof Error && error.message === "help") {
|
|
2194
|
-
console.log(KN_CREATE_FROM_DS_HELP);
|
|
2195
|
-
return 0;
|
|
2196
|
-
}
|
|
2197
|
-
console.error(formatHttpError(error));
|
|
2198
|
-
return 1;
|
|
2199
|
-
}
|
|
2200
|
-
try {
|
|
2201
|
-
const token = await ensureValidToken();
|
|
2202
|
-
const base = {
|
|
2203
|
-
baseUrl: token.baseUrl,
|
|
2204
|
-
accessToken: token.accessToken,
|
|
2205
|
-
businessDomain: options.businessDomain,
|
|
2206
|
-
};
|
|
2207
|
-
const tablesBody = await listTablesWithColumns({ ...base, id: options.dsId });
|
|
2208
|
-
const allTables = JSON.parse(tablesBody);
|
|
2209
|
-
const targetTables = options.tables.length > 0
|
|
2210
|
-
? allTables.filter((t) => options.tables.includes(t.name))
|
|
2211
|
-
: allTables;
|
|
2212
|
-
if (targetTables.length === 0) {
|
|
2213
|
-
console.error("No tables available");
|
|
2214
|
-
return 1;
|
|
2215
|
-
}
|
|
2216
|
-
// Phase 1: Create DataViews for each table
|
|
2217
|
-
console.error(`Creating data views for ${targetTables.length} table(s) ...`);
|
|
2218
|
-
const viewMap = {};
|
|
2219
|
-
for (const t of targetTables) {
|
|
2220
|
-
const found = await findDataView({
|
|
2221
|
-
...base,
|
|
2222
|
-
name: t.name,
|
|
2223
|
-
datasourceId: options.dsId,
|
|
2224
|
-
exact: true,
|
|
2225
|
-
wait: true,
|
|
2226
|
-
});
|
|
2227
|
-
const dvId = found[0]?.id ??
|
|
2228
|
-
(await createDataView({
|
|
2229
|
-
...base,
|
|
2230
|
-
name: t.name,
|
|
2231
|
-
datasourceId: options.dsId,
|
|
2232
|
-
table: t.name,
|
|
2233
|
-
fields: t.columns.map((c) => ({ name: c.name, type: c.type })),
|
|
2234
|
-
}));
|
|
2235
|
-
viewMap[t.name] = dvId;
|
|
2236
|
-
}
|
|
2237
|
-
// Phase 2: Create the KN record
|
|
2238
|
-
const knBody = JSON.stringify({
|
|
2239
|
-
name: options.name,
|
|
2240
|
-
branch: "main",
|
|
2241
|
-
base_branch: "",
|
|
2242
|
-
});
|
|
2243
|
-
const knResponse = await createKnowledgeNetwork({
|
|
2244
|
-
...base,
|
|
2245
|
-
body: knBody,
|
|
2246
|
-
});
|
|
2247
|
-
const knParsed = JSON.parse(knResponse);
|
|
2248
|
-
const knItem = Array.isArray(knParsed) ? knParsed[0] : knParsed;
|
|
2249
|
-
const knId = String(knItem?.id ?? "");
|
|
2250
|
-
console.error(`Knowledge network created: ${knId}`);
|
|
2251
|
-
// Phase 3: Create object types via REST API
|
|
2252
|
-
console.error(`Creating ${targetTables.length} object type(s) ...`);
|
|
2253
|
-
const otResults = [];
|
|
2254
|
-
for (const t of targetTables) {
|
|
2255
|
-
const pk = detectPrimaryKey(t, sampleRows?.[t.name]);
|
|
2256
|
-
const dk = detectDisplayKey(t, pk);
|
|
2257
|
-
const uniqueProps = [pk, dk].filter((x, i, a) => a.indexOf(x) === i);
|
|
2258
|
-
const entry = {
|
|
2259
|
-
branch: "main",
|
|
2260
|
-
name: t.name,
|
|
2261
|
-
data_source: { type: "data_view", id: viewMap[t.name] },
|
|
2262
|
-
primary_keys: [pk],
|
|
2263
|
-
display_key: dk,
|
|
2264
|
-
data_properties: t.columns.map((c) => ({
|
|
2265
|
-
name: c.name,
|
|
2266
|
-
display_name: c.name,
|
|
2267
|
-
type: "string",
|
|
2268
|
-
mapped_field: { name: c.name, type: c.type || "varchar" },
|
|
2269
|
-
})),
|
|
2270
|
-
};
|
|
2271
|
-
const otBody = JSON.stringify({ entries: [entry] });
|
|
2272
|
-
const otResponse = await createObjectTypes({
|
|
2273
|
-
...base,
|
|
2274
|
-
knId,
|
|
2275
|
-
body: otBody,
|
|
2276
|
-
});
|
|
2277
|
-
const otParsed = JSON.parse(otResponse);
|
|
2278
|
-
const otItem = otParsed.entries?.[0];
|
|
2279
|
-
otResults.push({
|
|
2280
|
-
name: t.name,
|
|
2281
|
-
id: otItem?.id ?? "",
|
|
2282
|
-
field_count: t.columns.length,
|
|
2283
|
-
});
|
|
2284
|
-
console.error(` Created: ${t.name} (${t.columns.length} fields, pk=${pk}, dk=${dk})`);
|
|
2285
|
-
}
|
|
2286
|
-
if (otResults.length === 0) {
|
|
2287
|
-
const errorOutput = {
|
|
2288
|
-
kn_id: knId,
|
|
2289
|
-
kn_name: options.name,
|
|
2290
|
-
error: "No object types were created",
|
|
2291
|
-
};
|
|
2292
|
-
console.log(JSON.stringify(errorOutput, null, options.pretty ? 2 : 0));
|
|
2293
|
-
return 1;
|
|
2294
|
-
}
|
|
2295
|
-
let statusStr = "skipped";
|
|
2296
|
-
if (options.build) {
|
|
2297
|
-
console.error("Building ...");
|
|
2298
|
-
await buildKnowledgeNetwork({ ...base, knId });
|
|
2299
|
-
const TERMINAL = ["completed", "failed", "success"];
|
|
2300
|
-
try {
|
|
2301
|
-
statusStr = await pollWithBackoff({
|
|
2302
|
-
fn: async () => {
|
|
2303
|
-
const statusBody = await getBuildStatus({ ...base, knId });
|
|
2304
|
-
const statusParsed = JSON.parse(statusBody);
|
|
2305
|
-
const jobs = Array.isArray(statusParsed) ? statusParsed : (statusParsed.entries ?? []);
|
|
2306
|
-
const state = (jobs[0]?.state ?? "running").toLowerCase();
|
|
2307
|
-
if (TERMINAL.includes(state))
|
|
2308
|
-
return { done: true, value: state };
|
|
2309
|
-
return { done: false, value: "running" };
|
|
2310
|
-
},
|
|
2311
|
-
interval: 2000,
|
|
2312
|
-
timeout: options.timeout * 1000,
|
|
2313
|
-
});
|
|
2314
|
-
}
|
|
2315
|
-
catch {
|
|
2316
|
-
// timeout — statusStr remains "skipped"
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
const output = {
|
|
2320
|
-
kn_id: knId,
|
|
2321
|
-
kn_name: options.name,
|
|
2322
|
-
object_types: otResults,
|
|
2323
|
-
status: statusStr,
|
|
2324
|
-
};
|
|
2325
|
-
console.log(JSON.stringify(output, null, options.pretty ? 2 : 0));
|
|
2326
|
-
return 0;
|
|
2327
|
-
}
|
|
2328
|
-
catch (error) {
|
|
2329
|
-
console.error(formatHttpError(error));
|
|
2330
|
-
return 1;
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
async function runKnUpdateCommand(args) {
|
|
2334
|
-
let options;
|
|
2335
|
-
try {
|
|
2336
|
-
options = parseKnUpdateArgs(args);
|
|
2337
|
-
}
|
|
2338
|
-
catch (error) {
|
|
2339
|
-
if (error instanceof Error && error.message === "help") {
|
|
2340
|
-
console.log(KN_UPDATE_HELP);
|
|
2341
|
-
return 0;
|
|
2342
|
-
}
|
|
2343
|
-
console.error(formatHttpError(error));
|
|
2344
|
-
return 1;
|
|
2345
|
-
}
|
|
2346
|
-
try {
|
|
2347
|
-
const token = await ensureValidToken();
|
|
2348
|
-
const body = await updateKnowledgeNetwork({
|
|
2349
|
-
baseUrl: token.baseUrl,
|
|
2350
|
-
accessToken: token.accessToken,
|
|
2351
|
-
knId: options.knId,
|
|
2352
|
-
body: options.body,
|
|
2353
|
-
businessDomain: options.businessDomain,
|
|
603
|
+
mode: options.export ? "export" : undefined,
|
|
604
|
+
include_statistics: options.stats ? true : undefined,
|
|
2354
605
|
});
|
|
2355
606
|
if (body) {
|
|
2356
607
|
console.log(formatCallOutput(body, options.pretty));
|
|
@@ -2362,44 +613,32 @@ async function runKnUpdateCommand(args) {
|
|
|
2362
613
|
return 1;
|
|
2363
614
|
}
|
|
2364
615
|
}
|
|
2365
|
-
function
|
|
2366
|
-
return new Promise((resolve) => {
|
|
2367
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2368
|
-
rl.question(`Delete knowledge network ${knId}? [y/N] `, (answer) => {
|
|
2369
|
-
rl.close();
|
|
2370
|
-
const trimmed = answer.trim().toLowerCase();
|
|
2371
|
-
resolve(trimmed === "y" || trimmed === "yes");
|
|
2372
|
-
});
|
|
2373
|
-
});
|
|
2374
|
-
}
|
|
2375
|
-
async function runKnDeleteCommand(args) {
|
|
616
|
+
async function runKnCreateCommand(args) {
|
|
2376
617
|
let options;
|
|
2377
618
|
try {
|
|
2378
|
-
options =
|
|
619
|
+
options = parseKnCreateArgs(args);
|
|
2379
620
|
}
|
|
2380
621
|
catch (error) {
|
|
2381
622
|
if (error instanceof Error && error.message === "help") {
|
|
2382
|
-
console.log(
|
|
623
|
+
console.log(KN_CREATE_HELP);
|
|
2383
624
|
return 0;
|
|
2384
625
|
}
|
|
2385
626
|
console.error(formatHttpError(error));
|
|
2386
627
|
return 1;
|
|
2387
628
|
}
|
|
2388
|
-
if (!options.yes) {
|
|
2389
|
-
const confirmed = await confirmDelete(options.knId);
|
|
2390
|
-
if (!confirmed) {
|
|
2391
|
-
console.error("Aborted.");
|
|
2392
|
-
return 1;
|
|
2393
|
-
}
|
|
2394
|
-
}
|
|
2395
629
|
try {
|
|
2396
630
|
const token = await ensureValidToken();
|
|
2397
|
-
await
|
|
631
|
+
const body = await createKnowledgeNetwork({
|
|
2398
632
|
baseUrl: token.baseUrl,
|
|
2399
633
|
accessToken: token.accessToken,
|
|
2400
|
-
|
|
634
|
+
body: options.body,
|
|
2401
635
|
businessDomain: options.businessDomain,
|
|
636
|
+
import_mode: options.import_mode,
|
|
637
|
+
validate_dependency: options.validate_dependency,
|
|
2402
638
|
});
|
|
639
|
+
if (body) {
|
|
640
|
+
console.log(formatCallOutput(body, options.pretty));
|
|
641
|
+
}
|
|
2403
642
|
return 0;
|
|
2404
643
|
}
|
|
2405
644
|
catch (error) {
|
|
@@ -2407,423 +646,76 @@ async function runKnDeleteCommand(args) {
|
|
|
2407
646
|
return 1;
|
|
2408
647
|
}
|
|
2409
648
|
}
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
Trigger a full build for a knowledge network.
|
|
2413
|
-
|
|
2414
|
-
Options:
|
|
2415
|
-
--wait (default) Poll until build completes
|
|
2416
|
-
--no-wait Return immediately after triggering
|
|
2417
|
-
--timeout <seconds> Max wait time when --wait (default: 300)
|
|
2418
|
-
-bd, --biz-domain Business domain (default: bd_public)`;
|
|
2419
|
-
export function parseKnBuildArgs(args) {
|
|
2420
|
-
let knId = "";
|
|
2421
|
-
let wait = true;
|
|
2422
|
-
let timeout = 300;
|
|
2423
|
-
let businessDomain = "";
|
|
2424
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
2425
|
-
const arg = args[i];
|
|
2426
|
-
if (arg === "--help" || arg === "-h")
|
|
2427
|
-
throw new Error("help");
|
|
2428
|
-
if (arg === "--wait") {
|
|
2429
|
-
wait = true;
|
|
2430
|
-
continue;
|
|
2431
|
-
}
|
|
2432
|
-
if (arg === "--no-wait") {
|
|
2433
|
-
wait = false;
|
|
2434
|
-
continue;
|
|
2435
|
-
}
|
|
2436
|
-
if (arg === "--timeout" && args[i + 1]) {
|
|
2437
|
-
timeout = parseInt(args[i + 1], 10);
|
|
2438
|
-
if (Number.isNaN(timeout) || timeout < 1)
|
|
2439
|
-
timeout = 300;
|
|
2440
|
-
i += 1;
|
|
2441
|
-
continue;
|
|
2442
|
-
}
|
|
2443
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
2444
|
-
businessDomain = args[i + 1];
|
|
2445
|
-
i += 1;
|
|
2446
|
-
continue;
|
|
2447
|
-
}
|
|
2448
|
-
if (!arg.startsWith("-") && !knId) {
|
|
2449
|
-
knId = arg;
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
if (!knId) {
|
|
2453
|
-
throw new Error("Missing kn-id. Usage: kweaver bkn build <kn-id> [options]");
|
|
2454
|
-
}
|
|
2455
|
-
if (!businessDomain)
|
|
2456
|
-
businessDomain = resolveBusinessDomain();
|
|
2457
|
-
return { knId, wait, timeout, businessDomain };
|
|
2458
|
-
}
|
|
2459
|
-
async function runKnBuildCommand(args) {
|
|
649
|
+
async function runKnUpdateCommand(args) {
|
|
2460
650
|
let options;
|
|
2461
651
|
try {
|
|
2462
|
-
options =
|
|
652
|
+
options = parseKnUpdateArgs(args);
|
|
2463
653
|
}
|
|
2464
654
|
catch (error) {
|
|
2465
655
|
if (error instanceof Error && error.message === "help") {
|
|
2466
|
-
console.log(
|
|
656
|
+
console.log(KN_UPDATE_HELP);
|
|
2467
657
|
return 0;
|
|
2468
658
|
}
|
|
2469
659
|
console.error(formatHttpError(error));
|
|
2470
660
|
return 1;
|
|
2471
661
|
}
|
|
2472
|
-
const TERMINAL_STATES = ["completed", "failed", "success"];
|
|
2473
662
|
try {
|
|
2474
663
|
const token = await ensureValidToken();
|
|
2475
|
-
await
|
|
664
|
+
const body = await updateKnowledgeNetwork({
|
|
2476
665
|
baseUrl: token.baseUrl,
|
|
2477
666
|
accessToken: token.accessToken,
|
|
2478
667
|
knId: options.knId,
|
|
668
|
+
body: options.body,
|
|
2479
669
|
businessDomain: options.businessDomain,
|
|
2480
670
|
});
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
console.error("Build triggered (not waiting).");
|
|
2484
|
-
return 0;
|
|
2485
|
-
}
|
|
2486
|
-
console.error("Waiting for build to complete ...");
|
|
2487
|
-
try {
|
|
2488
|
-
const { state, detail } = await pollWithBackoff({
|
|
2489
|
-
fn: async () => {
|
|
2490
|
-
const body = await getBuildStatus({
|
|
2491
|
-
baseUrl: token.baseUrl,
|
|
2492
|
-
accessToken: token.accessToken,
|
|
2493
|
-
knId: options.knId,
|
|
2494
|
-
businessDomain: options.businessDomain,
|
|
2495
|
-
});
|
|
2496
|
-
const parsed = JSON.parse(body);
|
|
2497
|
-
const jobs = Array.isArray(parsed) ? parsed : (parsed.entries ?? parsed.data ?? []);
|
|
2498
|
-
const job = jobs[0];
|
|
2499
|
-
const st = (job?.state ?? "running").toLowerCase();
|
|
2500
|
-
const dt = job?.state_detail;
|
|
2501
|
-
if (TERMINAL_STATES.includes(st))
|
|
2502
|
-
return { done: true, value: { state: st, detail: dt } };
|
|
2503
|
-
return { done: false, value: { state: st } };
|
|
2504
|
-
},
|
|
2505
|
-
interval: 2000,
|
|
2506
|
-
timeout: options.timeout * 1000,
|
|
2507
|
-
});
|
|
2508
|
-
console.log(state);
|
|
2509
|
-
if (detail) {
|
|
2510
|
-
console.log(`Detail: ${detail}`);
|
|
2511
|
-
}
|
|
2512
|
-
return state === "failed" ? 1 : 0;
|
|
2513
|
-
}
|
|
2514
|
-
catch {
|
|
2515
|
-
console.error(`Build did not complete within ${options.timeout}s`);
|
|
2516
|
-
return 1;
|
|
671
|
+
if (body) {
|
|
672
|
+
console.log(formatCallOutput(body, options.pretty));
|
|
2517
673
|
}
|
|
674
|
+
return 0;
|
|
2518
675
|
}
|
|
2519
676
|
catch (error) {
|
|
2520
677
|
console.error(formatHttpError(error));
|
|
2521
678
|
return 1;
|
|
2522
679
|
}
|
|
2523
680
|
}
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
});
|
|
2533
|
-
if (result.error) {
|
|
2534
|
-
if ("code" in result.error && result.error.code === "ENOENT") {
|
|
2535
|
-
throw new Error("tar executable not found. On Windows, ensure tar.exe is in PATH " +
|
|
2536
|
-
"(ships with Windows 10 1803+) or install GNU tar via Git for Windows / scoop.");
|
|
2537
|
-
}
|
|
2538
|
-
throw result.error;
|
|
2539
|
-
}
|
|
2540
|
-
if (result.status !== 0) {
|
|
2541
|
-
throw new Error(`tar pack failed: ${result.stderr?.toString() ?? result.status}`);
|
|
2542
|
-
}
|
|
2543
|
-
return result.stdout;
|
|
2544
|
-
}
|
|
2545
|
-
export function extractTarToDirectory(tarBuffer, dirPath) {
|
|
2546
|
-
const absPath = resolve(dirPath);
|
|
2547
|
-
mkdirSync(absPath, { recursive: true });
|
|
2548
|
-
const result = spawnSync("tar", ["xf", "-", "-C", absPath], {
|
|
2549
|
-
input: tarBuffer,
|
|
681
|
+
function confirmDelete(knId) {
|
|
682
|
+
return new Promise((resolve) => {
|
|
683
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
684
|
+
rl.question(`Delete knowledge network ${knId}? [y/N] `, (answer) => {
|
|
685
|
+
rl.close();
|
|
686
|
+
const trimmed = answer.trim().toLowerCase();
|
|
687
|
+
resolve(trimmed === "y" || trimmed === "yes");
|
|
688
|
+
});
|
|
2550
689
|
});
|
|
2551
|
-
if (result.error) {
|
|
2552
|
-
if ("code" in result.error && result.error.code === "ENOENT") {
|
|
2553
|
-
throw new Error("tar executable not found. On Windows, ensure tar.exe is in PATH " +
|
|
2554
|
-
"(ships with Windows 10 1803+) or install GNU tar via Git for Windows / scoop.");
|
|
2555
|
-
}
|
|
2556
|
-
throw result.error;
|
|
2557
|
-
}
|
|
2558
|
-
if (result.status !== 0) {
|
|
2559
|
-
throw new Error(`tar extract failed: ${result.stderr?.toString() ?? result.status}`);
|
|
2560
|
-
}
|
|
2561
|
-
}
|
|
2562
|
-
const KN_PUSH_HELP = `kweaver bkn push <directory> [options]
|
|
2563
|
-
|
|
2564
|
-
Pack a BKN directory into a tar and upload to import as a knowledge network.
|
|
2565
|
-
|
|
2566
|
-
Options:
|
|
2567
|
-
--branch <s> Branch name (default: main)
|
|
2568
|
-
-bd, --biz-domain Business domain (default: bd_public)
|
|
2569
|
-
--pretty Pretty-print JSON output
|
|
2570
|
-
--detect-encoding Detect .bkn encoding and normalize to UTF-8 (default: on)
|
|
2571
|
-
--no-detect-encoding Do not detect; require UTF-8 .bkn files
|
|
2572
|
-
--source-encoding <name> Decode all .bkn files with this encoding (e.g. gb18030); overrides detection`;
|
|
2573
|
-
const KN_PULL_HELP = `kweaver bkn pull <kn-id> [<directory>] [options]
|
|
2574
|
-
|
|
2575
|
-
Download a BKN tar from a knowledge network and extract to a local directory.
|
|
2576
|
-
|
|
2577
|
-
Options:
|
|
2578
|
-
<directory> Output directory (default: <kn-id>)
|
|
2579
|
-
--branch <s> Branch name (default: main)
|
|
2580
|
-
-bd, --biz-domain Business domain (default: bd_public)`;
|
|
2581
|
-
async function runKnValidateCommand(args) {
|
|
2582
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
2583
|
-
console.log("Usage: kweaver bkn validate <directory> [options]\n\n" +
|
|
2584
|
-
"Validate a local BKN directory without uploading.\n\n" +
|
|
2585
|
-
"Options:\n" +
|
|
2586
|
-
" --detect-encoding Detect .bkn encoding and normalize to UTF-8 (default: on)\n" +
|
|
2587
|
-
" --no-detect-encoding Require UTF-8 .bkn files\n" +
|
|
2588
|
-
" --source-encoding <n> Decode all .bkn with this encoding (e.g. gb18030)");
|
|
2589
|
-
return 0;
|
|
2590
|
-
}
|
|
2591
|
-
let encodingOptions;
|
|
2592
|
-
let restArgs;
|
|
2593
|
-
try {
|
|
2594
|
-
const stripped = stripBknEncodingCliArgs(args);
|
|
2595
|
-
encodingOptions = stripped.options;
|
|
2596
|
-
restArgs = stripped.rest;
|
|
2597
|
-
}
|
|
2598
|
-
catch (e) {
|
|
2599
|
-
console.error(e instanceof Error ? e.message : String(e));
|
|
2600
|
-
return 1;
|
|
2601
|
-
}
|
|
2602
|
-
const directory = restArgs.find((a) => !a.startsWith("-"));
|
|
2603
|
-
if (!directory) {
|
|
2604
|
-
console.error("Missing directory. Usage: kweaver bkn validate <directory> [options]");
|
|
2605
|
-
return 1;
|
|
2606
|
-
}
|
|
2607
|
-
const absDir = resolve(directory);
|
|
2608
|
-
try {
|
|
2609
|
-
const stat = statSync(absDir);
|
|
2610
|
-
if (!stat.isDirectory()) {
|
|
2611
|
-
console.error(`Not a directory: ${directory}`);
|
|
2612
|
-
return 1;
|
|
2613
|
-
}
|
|
2614
|
-
}
|
|
2615
|
-
catch (err) {
|
|
2616
|
-
if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
|
|
2617
|
-
console.error(`Directory not found: ${directory}`);
|
|
2618
|
-
return 1;
|
|
2619
|
-
}
|
|
2620
|
-
throw err;
|
|
2621
|
-
}
|
|
2622
|
-
const prepared = prepareBknDirectoryForImport(absDir, encodingOptions);
|
|
2623
|
-
try {
|
|
2624
|
-
const network = await loadNetwork(prepared.dir);
|
|
2625
|
-
const result = validateNetwork(network);
|
|
2626
|
-
if (!result.ok) {
|
|
2627
|
-
for (const e of result.errors)
|
|
2628
|
-
console.error(` - ${e}`);
|
|
2629
|
-
console.error(`BKN validation failed: ${result.errors.length} error(s)`);
|
|
2630
|
-
return 1;
|
|
2631
|
-
}
|
|
2632
|
-
const objs = allObjects(network);
|
|
2633
|
-
const rels = allRelations(network);
|
|
2634
|
-
const acts = allActions(network);
|
|
2635
|
-
console.log(`Valid: ${objs.length} object types, ${rels.length} relation types, ${acts.length} action types`);
|
|
2636
|
-
return 0;
|
|
2637
|
-
}
|
|
2638
|
-
catch (error) {
|
|
2639
|
-
console.error(`BKN validation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2640
|
-
return 1;
|
|
2641
|
-
}
|
|
2642
|
-
finally {
|
|
2643
|
-
prepared.cleanup();
|
|
2644
|
-
}
|
|
2645
690
|
}
|
|
2646
|
-
async function
|
|
691
|
+
async function runKnDeleteCommand(args) {
|
|
2647
692
|
let options;
|
|
2648
693
|
try {
|
|
2649
|
-
options =
|
|
694
|
+
options = parseKnDeleteArgs(args);
|
|
2650
695
|
}
|
|
2651
696
|
catch (error) {
|
|
2652
697
|
if (error instanceof Error && error.message === "help") {
|
|
2653
|
-
console.log(
|
|
698
|
+
console.log(KN_DELETE_HELP);
|
|
2654
699
|
return 0;
|
|
2655
700
|
}
|
|
2656
701
|
console.error(formatHttpError(error));
|
|
2657
702
|
return 1;
|
|
2658
703
|
}
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
console.error(`Not a directory: ${options.directory}`);
|
|
2664
|
-
return 1;
|
|
2665
|
-
}
|
|
2666
|
-
}
|
|
2667
|
-
catch (err) {
|
|
2668
|
-
if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
|
|
2669
|
-
console.error(`Directory not found: ${options.directory}`);
|
|
2670
|
-
return 1;
|
|
2671
|
-
}
|
|
2672
|
-
throw err;
|
|
2673
|
-
}
|
|
2674
|
-
const prepared = prepareBknDirectoryForImport(absDir, options.encodingOptions);
|
|
2675
|
-
const workDir = prepared.dir;
|
|
2676
|
-
try {
|
|
2677
|
-
try {
|
|
2678
|
-
const network = await loadNetwork(workDir);
|
|
2679
|
-
const objs = allObjects(network);
|
|
2680
|
-
const rels = allRelations(network);
|
|
2681
|
-
const acts = allActions(network);
|
|
2682
|
-
console.error(`Validated: ${objs.length} object types, ${rels.length} relation types, ${acts.length} action types`);
|
|
2683
|
-
}
|
|
2684
|
-
catch (error) {
|
|
2685
|
-
console.error(`BKN validation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2686
|
-
return 1;
|
|
2687
|
-
}
|
|
2688
|
-
try {
|
|
2689
|
-
await generateChecksum(workDir);
|
|
2690
|
-
console.error("Checksum generated");
|
|
2691
|
-
}
|
|
2692
|
-
catch (error) {
|
|
2693
|
-
console.error(`Checksum generation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2694
|
-
return 1;
|
|
2695
|
-
}
|
|
2696
|
-
try {
|
|
2697
|
-
const tarBuffer = packDirectoryToTar(workDir);
|
|
2698
|
-
const token = await ensureValidToken();
|
|
2699
|
-
const body = await uploadBkn({
|
|
2700
|
-
baseUrl: token.baseUrl,
|
|
2701
|
-
accessToken: token.accessToken,
|
|
2702
|
-
tarBuffer,
|
|
2703
|
-
businessDomain: options.businessDomain,
|
|
2704
|
-
branch: options.branch,
|
|
2705
|
-
});
|
|
2706
|
-
console.log(formatCallOutput(body, options.pretty));
|
|
2707
|
-
return 0;
|
|
2708
|
-
}
|
|
2709
|
-
catch (error) {
|
|
2710
|
-
console.error(formatHttpError(error));
|
|
704
|
+
if (!options.yes) {
|
|
705
|
+
const confirmed = await confirmDelete(options.knId);
|
|
706
|
+
if (!confirmed) {
|
|
707
|
+
console.error("Aborted.");
|
|
2711
708
|
return 1;
|
|
2712
709
|
}
|
|
2713
710
|
}
|
|
2714
|
-
finally {
|
|
2715
|
-
prepared.cleanup();
|
|
2716
|
-
}
|
|
2717
|
-
}
|
|
2718
|
-
async function runKnPullCommand(args) {
|
|
2719
|
-
let options;
|
|
2720
|
-
try {
|
|
2721
|
-
options = parseKnPullArgs(args);
|
|
2722
|
-
}
|
|
2723
|
-
catch (error) {
|
|
2724
|
-
if (error instanceof Error && error.message === "help") {
|
|
2725
|
-
console.log(KN_PULL_HELP);
|
|
2726
|
-
return 0;
|
|
2727
|
-
}
|
|
2728
|
-
console.error(formatHttpError(error));
|
|
2729
|
-
return 1;
|
|
2730
|
-
}
|
|
2731
|
-
try {
|
|
2732
|
-
const token = await ensureValidToken();
|
|
2733
|
-
const tarBuffer = await downloadBkn({
|
|
2734
|
-
baseUrl: token.baseUrl,
|
|
2735
|
-
accessToken: token.accessToken,
|
|
2736
|
-
knId: options.knId,
|
|
2737
|
-
businessDomain: options.businessDomain,
|
|
2738
|
-
branch: options.branch,
|
|
2739
|
-
});
|
|
2740
|
-
const absDir = resolve(options.directory);
|
|
2741
|
-
extractTarToDirectory(tarBuffer, absDir);
|
|
2742
|
-
console.log(`Extracted to ${absDir}`);
|
|
2743
|
-
return 0;
|
|
2744
|
-
}
|
|
2745
|
-
catch (error) {
|
|
2746
|
-
console.error(formatHttpError(error));
|
|
2747
|
-
return 1;
|
|
2748
|
-
}
|
|
2749
|
-
}
|
|
2750
|
-
// ── search ──────────────────────────────────────────────────────────────────
|
|
2751
|
-
const KN_SEARCH_HELP = `kweaver bkn search <kn-id> <query> [--max-concepts <n>] [--mode <mode>] [--pretty] [-bd value]
|
|
2752
|
-
|
|
2753
|
-
Semantic search within a knowledge network via agent-retrieval API.
|
|
2754
|
-
Returns matched concepts (object types, relation types, action types).
|
|
2755
|
-
|
|
2756
|
-
Options:
|
|
2757
|
-
--max-concepts <n> Max concepts to return (default: 10)
|
|
2758
|
-
--mode <mode> Search mode (default: keyword_vector_retrieval)
|
|
2759
|
-
--pretty Pretty-print JSON output
|
|
2760
|
-
-bd, --biz-domain Override x-business-domain`;
|
|
2761
|
-
export function parseKnSearchArgs(args) {
|
|
2762
|
-
let knId = "";
|
|
2763
|
-
let query = "";
|
|
2764
|
-
let maxConcepts = 10;
|
|
2765
|
-
let mode = "keyword_vector_retrieval";
|
|
2766
|
-
let pretty = false;
|
|
2767
|
-
let businessDomain = process.env.KWEAVER_BUSINESS_DOMAIN ?? "";
|
|
2768
|
-
const positional = [];
|
|
2769
|
-
for (let i = 0; i < args.length; i++) {
|
|
2770
|
-
const arg = args[i];
|
|
2771
|
-
if (arg === "--max-concepts") {
|
|
2772
|
-
maxConcepts = Number(args[++i]);
|
|
2773
|
-
}
|
|
2774
|
-
else if (arg === "--mode") {
|
|
2775
|
-
mode = args[++i];
|
|
2776
|
-
}
|
|
2777
|
-
else if (arg === "--pretty") {
|
|
2778
|
-
pretty = true;
|
|
2779
|
-
}
|
|
2780
|
-
else if (arg === "-bd" || arg === "--biz-domain") {
|
|
2781
|
-
businessDomain = args[++i];
|
|
2782
|
-
}
|
|
2783
|
-
else if (arg === "--help" || arg === "-h") {
|
|
2784
|
-
throw Object.assign(new Error("help"), { isHelp: true });
|
|
2785
|
-
}
|
|
2786
|
-
else if (arg.startsWith("-")) {
|
|
2787
|
-
throw new Error(`Unknown flag: ${arg}`);
|
|
2788
|
-
}
|
|
2789
|
-
else {
|
|
2790
|
-
positional.push(arg);
|
|
2791
|
-
}
|
|
2792
|
-
}
|
|
2793
|
-
knId = positional[0] ?? "";
|
|
2794
|
-
query = positional.slice(1).join(" ");
|
|
2795
|
-
if (!knId || !query) {
|
|
2796
|
-
throw new Error("Usage: kweaver bkn search <kn-id> <query> [options]");
|
|
2797
|
-
}
|
|
2798
|
-
if (!businessDomain)
|
|
2799
|
-
businessDomain = resolveBusinessDomain();
|
|
2800
|
-
return { knId, query, maxConcepts, mode, pretty, businessDomain };
|
|
2801
|
-
}
|
|
2802
|
-
async function runKnSearchCommand(args) {
|
|
2803
|
-
let options;
|
|
2804
|
-
try {
|
|
2805
|
-
options = parseKnSearchArgs(args);
|
|
2806
|
-
}
|
|
2807
|
-
catch (error) {
|
|
2808
|
-
if (error instanceof Error && error.isHelp) {
|
|
2809
|
-
console.log(KN_SEARCH_HELP);
|
|
2810
|
-
return 0;
|
|
2811
|
-
}
|
|
2812
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
2813
|
-
return 1;
|
|
2814
|
-
}
|
|
2815
711
|
try {
|
|
2816
712
|
const token = await ensureValidToken();
|
|
2817
|
-
|
|
713
|
+
await deleteKnowledgeNetwork({
|
|
2818
714
|
baseUrl: token.baseUrl,
|
|
2819
715
|
accessToken: token.accessToken,
|
|
2820
716
|
knId: options.knId,
|
|
2821
|
-
query: options.query,
|
|
2822
717
|
businessDomain: options.businessDomain,
|
|
2823
|
-
maxConcepts: options.maxConcepts,
|
|
2824
|
-
mode: options.mode,
|
|
2825
718
|
});
|
|
2826
|
-
console.log(formatCallOutput(result, options.pretty));
|
|
2827
719
|
return 0;
|
|
2828
720
|
}
|
|
2829
721
|
catch (error) {
|
|
@@ -2831,149 +723,3 @@ async function runKnSearchCommand(args) {
|
|
|
2831
723
|
return 1;
|
|
2832
724
|
}
|
|
2833
725
|
}
|
|
2834
|
-
const KN_CREATE_FROM_CSV_HELP = `kweaver bkn create-from-csv <ds-id> --files <glob> --name X [options]
|
|
2835
|
-
|
|
2836
|
-
Import CSV files into datasource, then create a knowledge network.
|
|
2837
|
-
|
|
2838
|
-
Options:
|
|
2839
|
-
--files <s> CSV file paths (comma-separated or glob, required)
|
|
2840
|
-
--name <s> Knowledge network name (required)
|
|
2841
|
-
--table-prefix <s> Table name prefix (default: none)
|
|
2842
|
-
--batch-size <n> Rows per batch (default: 500)
|
|
2843
|
-
--tables <a,b> Tables to include in KN (default: all imported)
|
|
2844
|
-
--build (default) Build after creation
|
|
2845
|
-
--no-build Skip build
|
|
2846
|
-
--timeout <n> Build timeout in seconds (default: 300)
|
|
2847
|
-
-bd, --biz-domain Business domain (default: bd_public)`;
|
|
2848
|
-
function parseKnCreateFromCsvArgs(args) {
|
|
2849
|
-
let dsId = "";
|
|
2850
|
-
let files = "";
|
|
2851
|
-
let name = "";
|
|
2852
|
-
let tablePrefix = "";
|
|
2853
|
-
let batchSize = 500;
|
|
2854
|
-
let tablesStr = "";
|
|
2855
|
-
let build = true;
|
|
2856
|
-
let timeout = 300;
|
|
2857
|
-
let businessDomain = "";
|
|
2858
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
2859
|
-
const arg = args[i];
|
|
2860
|
-
if (arg === "--help" || arg === "-h")
|
|
2861
|
-
throw new Error("help");
|
|
2862
|
-
if (arg === "--files" && args[i + 1]) {
|
|
2863
|
-
files = args[++i];
|
|
2864
|
-
continue;
|
|
2865
|
-
}
|
|
2866
|
-
if (arg === "--name" && args[i + 1]) {
|
|
2867
|
-
name = args[++i];
|
|
2868
|
-
continue;
|
|
2869
|
-
}
|
|
2870
|
-
if (arg === "--table-prefix" && args[i + 1]) {
|
|
2871
|
-
tablePrefix = args[++i];
|
|
2872
|
-
continue;
|
|
2873
|
-
}
|
|
2874
|
-
if (arg === "--batch-size" && args[i + 1]) {
|
|
2875
|
-
batchSize = parseInt(args[++i], 10);
|
|
2876
|
-
if (Number.isNaN(batchSize) || batchSize < 1)
|
|
2877
|
-
batchSize = 500;
|
|
2878
|
-
continue;
|
|
2879
|
-
}
|
|
2880
|
-
if (arg === "--tables" && args[i + 1]) {
|
|
2881
|
-
tablesStr = args[++i];
|
|
2882
|
-
continue;
|
|
2883
|
-
}
|
|
2884
|
-
if (arg === "--build") {
|
|
2885
|
-
build = true;
|
|
2886
|
-
continue;
|
|
2887
|
-
}
|
|
2888
|
-
if (arg === "--no-build") {
|
|
2889
|
-
build = false;
|
|
2890
|
-
continue;
|
|
2891
|
-
}
|
|
2892
|
-
if (arg === "--timeout" && args[i + 1]) {
|
|
2893
|
-
timeout = parseInt(args[++i], 10);
|
|
2894
|
-
if (Number.isNaN(timeout) || timeout < 1)
|
|
2895
|
-
timeout = 300;
|
|
2896
|
-
continue;
|
|
2897
|
-
}
|
|
2898
|
-
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
2899
|
-
businessDomain = args[++i];
|
|
2900
|
-
continue;
|
|
2901
|
-
}
|
|
2902
|
-
if (!arg.startsWith("-") && !dsId) {
|
|
2903
|
-
dsId = arg;
|
|
2904
|
-
}
|
|
2905
|
-
}
|
|
2906
|
-
const tables = tablesStr ? tablesStr.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
2907
|
-
if (!dsId || !files || !name) {
|
|
2908
|
-
throw new Error("Usage: kweaver bkn create-from-csv <ds-id> --files <glob> --name X [options]");
|
|
2909
|
-
}
|
|
2910
|
-
if (!businessDomain)
|
|
2911
|
-
businessDomain = resolveBusinessDomain();
|
|
2912
|
-
return { dsId, files, name, tablePrefix, batchSize, tables, build, timeout, businessDomain };
|
|
2913
|
-
}
|
|
2914
|
-
async function runKnCreateFromCsvCommand(args) {
|
|
2915
|
-
let options;
|
|
2916
|
-
try {
|
|
2917
|
-
options = parseKnCreateFromCsvArgs(args);
|
|
2918
|
-
}
|
|
2919
|
-
catch (error) {
|
|
2920
|
-
if (error instanceof Error && error.message === "help") {
|
|
2921
|
-
console.log(KN_CREATE_FROM_CSV_HELP);
|
|
2922
|
-
return 0;
|
|
2923
|
-
}
|
|
2924
|
-
console.error(formatHttpError(error));
|
|
2925
|
-
return 1;
|
|
2926
|
-
}
|
|
2927
|
-
// Phase 1: Import CSVs
|
|
2928
|
-
console.error("Phase 1: Importing CSVs ...");
|
|
2929
|
-
const importArgs = [
|
|
2930
|
-
options.dsId,
|
|
2931
|
-
"--files", options.files,
|
|
2932
|
-
"--table-prefix", options.tablePrefix,
|
|
2933
|
-
"--batch-size", String(options.batchSize),
|
|
2934
|
-
"-bd", options.businessDomain,
|
|
2935
|
-
];
|
|
2936
|
-
const importResult = await runDsImportCsv(importArgs);
|
|
2937
|
-
if (importResult.code !== 0) {
|
|
2938
|
-
console.error("CSV import failed — aborting KN creation");
|
|
2939
|
-
return importResult.code;
|
|
2940
|
-
}
|
|
2941
|
-
// Phase 1.5: Scan datasource metadata so platform discovers newly imported tables
|
|
2942
|
-
console.error("Scanning datasource metadata ...");
|
|
2943
|
-
try {
|
|
2944
|
-
const token = await ensureValidToken();
|
|
2945
|
-
const dsBody = await getDatasource({
|
|
2946
|
-
baseUrl: token.baseUrl,
|
|
2947
|
-
accessToken: token.accessToken,
|
|
2948
|
-
id: options.dsId,
|
|
2949
|
-
businessDomain: options.businessDomain,
|
|
2950
|
-
});
|
|
2951
|
-
const dsParsed = JSON.parse(dsBody);
|
|
2952
|
-
await scanMetadata({
|
|
2953
|
-
baseUrl: token.baseUrl,
|
|
2954
|
-
accessToken: token.accessToken,
|
|
2955
|
-
id: options.dsId,
|
|
2956
|
-
dsType: dsParsed.type ?? "mysql",
|
|
2957
|
-
businessDomain: options.businessDomain,
|
|
2958
|
-
});
|
|
2959
|
-
}
|
|
2960
|
-
catch (err) {
|
|
2961
|
-
console.error(`Scan warning (continuing): ${String(err)}`);
|
|
2962
|
-
}
|
|
2963
|
-
// Phase 2: Create KN from datasource
|
|
2964
|
-
console.error("Phase 2: Creating knowledge network ...");
|
|
2965
|
-
const tableNames = options.tables.length > 0 ? options.tables : importResult.tables;
|
|
2966
|
-
if (tableNames.length === 0) {
|
|
2967
|
-
console.error("No tables available for KN creation — aborting");
|
|
2968
|
-
return 1;
|
|
2969
|
-
}
|
|
2970
|
-
const knArgs = [
|
|
2971
|
-
options.dsId,
|
|
2972
|
-
"--name", options.name,
|
|
2973
|
-
"--tables", tableNames.join(","),
|
|
2974
|
-
options.build ? "--build" : "--no-build",
|
|
2975
|
-
"--timeout", String(options.timeout),
|
|
2976
|
-
"-bd", options.businessDomain,
|
|
2977
|
-
];
|
|
2978
|
-
return runKnCreateFromDsCommand(knArgs, importResult.sampleRows);
|
|
2979
|
-
}
|