@kweaver-ai/kweaver-sdk 0.6.10 → 0.7.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 +35 -5
- package/README.zh.md +34 -4
- package/dist/api/context-loader.d.ts +45 -10
- package/dist/api/context-loader.js +43 -8
- package/dist/api/semantic-search.d.ts +9 -0
- package/dist/api/semantic-search.js +19 -0
- package/dist/api/skills.js +10 -8
- package/dist/api/toolboxes.d.ts +12 -0
- package/dist/api/toolboxes.js +43 -1
- package/dist/cli.js +67 -28
- package/dist/commands/auth.js +43 -3
- package/dist/commands/bkn-ops.d.ts +4 -0
- package/dist/commands/bkn-ops.js +136 -62
- package/dist/commands/bkn-query.js +7 -2
- package/dist/commands/config.js +8 -0
- package/dist/commands/context-loader.js +340 -36
- package/dist/commands/ds.d.ts +23 -0
- package/dist/commands/ds.js +116 -18
- package/dist/commands/skill.js +26 -6
- package/dist/commands/toolbox.d.ts +15 -0
- package/dist/commands/toolbox.js +131 -1
- package/dist/config/stateless.d.ts +13 -0
- package/dist/config/stateless.js +20 -0
- package/dist/config/store.js +7 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/resources/bkn.d.ts +2 -1
- package/dist/resources/bkn.js +19 -7
- package/dist/resources/context-loader.d.ts +4 -3
- package/dist/resources/context-loader.js +8 -5
- package/dist/resources/toolboxes.d.ts +15 -0
- package/dist/resources/toolboxes.js +15 -1
- package/dist/utils/skill-bundle.d.ts +5 -0
- package/dist/utils/skill-bundle.js +74 -0
- package/package.json +2 -1
package/dist/commands/auth.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isNoAuth } from "../config/no-auth.js";
|
|
2
|
+
import { assertNotStatelessForWrite } from "../config/stateless.js";
|
|
2
3
|
import { autoSelectBusinessDomain, clearPlatformSession, deletePlatform, deleteUser, getActiveUser, getConfigDir, getCurrentPlatform, getPlatformAlias, hasPlatform, listPlatforms, listUserProfiles, loadClientConfig, loadTokenConfig, loadUserTokenConfig, resolveBusinessDomain, resolvePlatformIdentifier, resolveUserId, saveNoAuthPlatform, setActiveUser, setCurrentPlatform, setPlatformAlias, } from "../config/store.js";
|
|
3
4
|
import { decodeJwtPayload } from "../config/jwt.js";
|
|
4
5
|
import { eacpModifyPassword } from "../auth/eacp-modify-password.js";
|
|
@@ -71,6 +72,13 @@ Login options:
|
|
|
71
72
|
const LOGIN_SUBCOMMANDS = new Set(["status", "list", "use", "delete", "logout", "export", "whoami", "users", "switch"]);
|
|
72
73
|
if (target && !LOGIN_SUBCOMMANDS.has(target)) {
|
|
73
74
|
try {
|
|
75
|
+
try {
|
|
76
|
+
assertNotStatelessForWrite("auth login");
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
74
82
|
const normalizedTarget = normalizeBaseUrl(target);
|
|
75
83
|
const alias = readOption(args, "--alias");
|
|
76
84
|
let username = readOption(args, "--username") ?? readOption(args, "-u");
|
|
@@ -268,7 +276,8 @@ Login options:
|
|
|
268
276
|
}
|
|
269
277
|
console.log(`Config directory: ${getConfigDir()}`);
|
|
270
278
|
console.log(`Platform: ${active.url} (KWEAVER_BASE_URL)`);
|
|
271
|
-
|
|
279
|
+
const tokenProvenance = process.env.KWEAVER_TOKEN_SOURCE === "flag" ? "CLI (flag: --token)" : "KWEAVER_TOKEN";
|
|
280
|
+
console.log(`Token present: yes (${tokenProvenance})`);
|
|
272
281
|
console.log(`Refresh token: n/a (env)`);
|
|
273
282
|
return 0;
|
|
274
283
|
}
|
|
@@ -358,6 +367,13 @@ Login options:
|
|
|
358
367
|
console.error(`No saved token for ${useTarget}. Run \`kweaver auth login ${useTarget}\` first.`);
|
|
359
368
|
return 1;
|
|
360
369
|
}
|
|
370
|
+
try {
|
|
371
|
+
assertNotStatelessForWrite("auth use");
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
375
|
+
return 1;
|
|
376
|
+
}
|
|
361
377
|
setCurrentPlatform(useTarget);
|
|
362
378
|
console.log(`Current platform: ${useTarget}`);
|
|
363
379
|
return 0;
|
|
@@ -375,6 +391,13 @@ Login options:
|
|
|
375
391
|
console.error(`No saved token for ${deleteTarget}.`);
|
|
376
392
|
return 1;
|
|
377
393
|
}
|
|
394
|
+
try {
|
|
395
|
+
assertNotStatelessForWrite("auth delete");
|
|
396
|
+
}
|
|
397
|
+
catch (err) {
|
|
398
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
399
|
+
return 1;
|
|
400
|
+
}
|
|
378
401
|
if (deleteUserArg) {
|
|
379
402
|
const deleteUserId = resolveUserId(deleteTarget, deleteUserArg) ?? deleteUserArg;
|
|
380
403
|
deleteUser(deleteTarget, deleteUserId);
|
|
@@ -404,6 +427,13 @@ Login options:
|
|
|
404
427
|
console.error(`No saved token for ${logoutTarget}.`);
|
|
405
428
|
return 1;
|
|
406
429
|
}
|
|
430
|
+
try {
|
|
431
|
+
assertNotStatelessForWrite("auth logout");
|
|
432
|
+
}
|
|
433
|
+
catch (err) {
|
|
434
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
435
|
+
return 1;
|
|
436
|
+
}
|
|
407
437
|
const logoutUserId = logoutUserArg ? resolveUserId(logoutTarget, logoutUserArg) ?? logoutUserArg : undefined;
|
|
408
438
|
clearPlatformSession(logoutTarget, logoutUserId);
|
|
409
439
|
const userHint = logoutUserId ? ` (user: ${logoutUserId})` : "";
|
|
@@ -487,6 +517,13 @@ You can specify either the userId (sub claim) or the username (preferred_usernam
|
|
|
487
517
|
}
|
|
488
518
|
return 1;
|
|
489
519
|
}
|
|
520
|
+
try {
|
|
521
|
+
assertNotStatelessForWrite("auth switch");
|
|
522
|
+
}
|
|
523
|
+
catch (err) {
|
|
524
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
525
|
+
return 1;
|
|
526
|
+
}
|
|
490
527
|
setActiveUser(platform, resolvedId);
|
|
491
528
|
const profiles = listUserProfiles(platform);
|
|
492
529
|
const profile = profiles.find((p) => p.userId === resolvedId);
|
|
@@ -535,7 +572,10 @@ Options:
|
|
|
535
572
|
// complete picture without forcing them to pick a mode.
|
|
536
573
|
const jwtPayload = decodeJwtPayload(accessToken);
|
|
537
574
|
if (jsonOutput) {
|
|
538
|
-
const out = {
|
|
575
|
+
const out = {
|
|
576
|
+
platform: envUrl,
|
|
577
|
+
source: process.env.KWEAVER_TOKEN_SOURCE === "flag" ? "flag" : "env",
|
|
578
|
+
};
|
|
539
579
|
if (userInfo)
|
|
540
580
|
out.userInfo = userInfo;
|
|
541
581
|
if (jwtPayload)
|
|
@@ -544,7 +584,7 @@ Options:
|
|
|
544
584
|
return 0;
|
|
545
585
|
}
|
|
546
586
|
console.log(`Platform: ${envUrl}`);
|
|
547
|
-
console.log(`Source: env (KWEAVER_TOKEN)`);
|
|
587
|
+
console.log(`Source: ${process.env.KWEAVER_TOKEN_SOURCE === "flag" ? "CLI (flag: --token)" : "env (KWEAVER_TOKEN)"}`);
|
|
548
588
|
if (userInfo) {
|
|
549
589
|
console.log(`Type: ${userInfo.type}`);
|
|
550
590
|
console.log(`User ID: ${userInfo.id}`);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type BknEncodingImportOptions } from "../utils/bkn-encoding.js";
|
|
2
|
+
export declare const BKN_OBJECT_NAME_MAX_LENGTH = 40;
|
|
3
|
+
export declare function assertValidBknObjectNames(names: string[], context: string): void;
|
|
2
4
|
export declare function parseKnBuildArgs(args: string[]): {
|
|
3
5
|
knId: string;
|
|
4
6
|
wait: boolean;
|
|
@@ -34,6 +36,7 @@ export declare function parseKnCreateFromDsArgs(args: string[]): {
|
|
|
34
36
|
timeout: number;
|
|
35
37
|
businessDomain: string;
|
|
36
38
|
pretty: boolean;
|
|
39
|
+
noRollback: boolean;
|
|
37
40
|
};
|
|
38
41
|
/** Generate a BKN ObjectType YAML markdown file for a table. */
|
|
39
42
|
export declare function generateObjectTypeBkn(tableName: string, dvId: string, pk: string, dk: string, columns: Array<{
|
|
@@ -52,6 +55,7 @@ export declare function parseKnCreateFromCsvArgs(args: string[]): {
|
|
|
52
55
|
recreate: boolean;
|
|
53
56
|
timeout: number;
|
|
54
57
|
businessDomain: string;
|
|
58
|
+
noRollback: boolean;
|
|
55
59
|
};
|
|
56
60
|
export declare function runKnCreateFromCsvCommand(args: string[]): Promise<number>;
|
|
57
61
|
export interface ActionScheduleParsed {
|
package/dist/commands/bkn-ops.js
CHANGED
|
@@ -4,14 +4,36 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { loadNetwork, allObjects, allRelations, allActions, generateChecksum, validateNetwork } from "@kweaver-ai/bkn";
|
|
5
5
|
import { prepareBknDirectoryForImport, stripBknEncodingCliArgs, } from "../utils/bkn-encoding.js";
|
|
6
6
|
import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
|
|
7
|
-
import { createKnowledgeNetwork, createObjectTypes, buildKnowledgeNetwork, getBuildStatus, } from "../api/knowledge-networks.js";
|
|
7
|
+
import { createKnowledgeNetwork, createObjectTypes, deleteKnowledgeNetwork, buildKnowledgeNetwork, getBuildStatus, } from "../api/knowledge-networks.js";
|
|
8
8
|
import { listTablesWithColumns, scanMetadata, getDatasource } from "../api/datasources.js";
|
|
9
9
|
import { createDataView, findDataView } from "../api/dataviews.js";
|
|
10
|
+
import { resolveFiles } from "./ds.js";
|
|
11
|
+
import { buildTableName } from "./import-csv.js";
|
|
10
12
|
import { downloadBkn, uploadBkn, listActionSchedules, getActionSchedule, createActionSchedule, updateActionSchedule, setActionScheduleStatus, deleteActionSchedules, listJobs, getJob, getJobTasks, deleteJobs, } from "../api/bkn-backend.js";
|
|
11
13
|
import { formatCallOutput } from "./call.js";
|
|
12
14
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
13
15
|
import { runDsImportCsv } from "./ds.js";
|
|
14
16
|
import { pollWithBackoff, detectPrimaryKey, detectDisplayKey, confirmYes, } from "./bkn-utils.js";
|
|
17
|
+
// ── BKN object name validation ──────────────────────────────────────────────
|
|
18
|
+
// Mirrors bkn-backend OBJECT_NAME_MAX_LENGTH (interfaces/common.go:28) and
|
|
19
|
+
// validateObjectName (driveradapters/validate.go:85). 40 utf-8 codepoints,
|
|
20
|
+
// non-empty. Backend rejects the whole batch on first violation, so we surface
|
|
21
|
+
// every offender locally before any side-effecting call.
|
|
22
|
+
export const BKN_OBJECT_NAME_MAX_LENGTH = 40;
|
|
23
|
+
export function assertValidBknObjectNames(names, context) {
|
|
24
|
+
const offenders = [];
|
|
25
|
+
for (const name of names) {
|
|
26
|
+
const len = [...name].length;
|
|
27
|
+
if (len === 0 || len > BKN_OBJECT_NAME_MAX_LENGTH) {
|
|
28
|
+
offenders.push({ name, length: len });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (offenders.length === 0)
|
|
32
|
+
return;
|
|
33
|
+
const lines = offenders.map((o) => ` - ${o.name} (${o.length} chars)`);
|
|
34
|
+
throw new Error(`${context}: ${offenders.length} name(s) violate BKN object-name limit ` +
|
|
35
|
+
`(1..${BKN_OBJECT_NAME_MAX_LENGTH} utf-8 chars):\n${lines.join("\n")}`);
|
|
36
|
+
}
|
|
15
37
|
// ── Build ───────────────────────────────────────────────────────────────────
|
|
16
38
|
const KN_BUILD_HELP = `kweaver bkn build <kn-id> [options]
|
|
17
39
|
|
|
@@ -461,6 +483,7 @@ Options:
|
|
|
461
483
|
--build (default) Build after creation
|
|
462
484
|
--no-build Skip build after creation
|
|
463
485
|
--timeout <n> Build timeout in seconds (default: 300)
|
|
486
|
+
--no-rollback Keep partially-created KN on failure (debug; default: rollback)
|
|
464
487
|
-bd, --biz-domain Business domain (default: bd_public)
|
|
465
488
|
--pretty Pretty-print output (default)`;
|
|
466
489
|
export function parseKnCreateFromDsArgs(args) {
|
|
@@ -471,6 +494,7 @@ export function parseKnCreateFromDsArgs(args) {
|
|
|
471
494
|
let timeout = 300;
|
|
472
495
|
let businessDomain = "";
|
|
473
496
|
let pretty = true;
|
|
497
|
+
let noRollback = false;
|
|
474
498
|
for (let i = 0; i < args.length; i += 1) {
|
|
475
499
|
const arg = args[i];
|
|
476
500
|
if (arg === "--help" || arg === "-h")
|
|
@@ -491,6 +515,10 @@ export function parseKnCreateFromDsArgs(args) {
|
|
|
491
515
|
build = false;
|
|
492
516
|
continue;
|
|
493
517
|
}
|
|
518
|
+
if (arg === "--no-rollback") {
|
|
519
|
+
noRollback = true;
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
494
522
|
if (arg === "--timeout" && args[i + 1]) {
|
|
495
523
|
timeout = parseInt(args[++i], 10);
|
|
496
524
|
if (Number.isNaN(timeout) || timeout < 1)
|
|
@@ -515,7 +543,7 @@ export function parseKnCreateFromDsArgs(args) {
|
|
|
515
543
|
}
|
|
516
544
|
if (!businessDomain)
|
|
517
545
|
businessDomain = resolveBusinessDomain();
|
|
518
|
-
return { dsId, name, tables, build, timeout, businessDomain, pretty };
|
|
546
|
+
return { dsId, name, tables, build, timeout, businessDomain, pretty, noRollback };
|
|
519
547
|
}
|
|
520
548
|
/** Sanitize a table name into a BKN-safe ID (alphanumeric + underscore). */
|
|
521
549
|
function sanitizeBknId(name) {
|
|
@@ -576,7 +604,12 @@ export async function runKnCreateFromDsCommand(args, sampleRows) {
|
|
|
576
604
|
console.error("No tables available");
|
|
577
605
|
return 1;
|
|
578
606
|
}
|
|
579
|
-
//
|
|
607
|
+
// Pre-flight: catch every offending OT name before any side effect.
|
|
608
|
+
// Backend rejects the whole batch on first violation (validate.go:90),
|
|
609
|
+
// so retroactive rollback is wasted work if we can fail fast here.
|
|
610
|
+
assertValidBknObjectNames(targetTables.map((t) => t.name), "Object type names derived from table names");
|
|
611
|
+
// Phase 1: Create DataViews for each table. findDataView is idempotent;
|
|
612
|
+
// not tracked for rollback so a retry can reuse what's already there.
|
|
580
613
|
console.error(`Creating data views for ${targetTables.length} table(s) ...`);
|
|
581
614
|
const viewMap = {};
|
|
582
615
|
for (const t of targetTables) {
|
|
@@ -597,7 +630,8 @@ export async function runKnCreateFromDsCommand(args, sampleRows) {
|
|
|
597
630
|
}));
|
|
598
631
|
viewMap[t.name] = dvId;
|
|
599
632
|
}
|
|
600
|
-
// Phase 2: Create the KN
|
|
633
|
+
// Phase 2: Create the KN. If any subsequent step fails we DELETE this
|
|
634
|
+
// KN — backend cascades to OTs (knowledge_network_service.go:917-969).
|
|
601
635
|
const knBody = JSON.stringify({
|
|
602
636
|
name: options.name,
|
|
603
637
|
branch: "main",
|
|
@@ -611,72 +645,91 @@ export async function runKnCreateFromDsCommand(args, sampleRows) {
|
|
|
611
645
|
const knItem = Array.isArray(knParsed) ? knParsed[0] : knParsed;
|
|
612
646
|
const knId = String(knItem?.id ?? "");
|
|
613
647
|
console.error(`Knowledge network created: ${knId}`);
|
|
614
|
-
|
|
615
|
-
console.error(`Creating ${targetTables.length} object type(s) ...`);
|
|
648
|
+
let createdKnId = knId;
|
|
616
649
|
const otResults = [];
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
650
|
+
let statusStr = "skipped";
|
|
651
|
+
try {
|
|
652
|
+
// Phase 3: Single batched POST. Backend wraps all entries in one tx
|
|
653
|
+
// (object_type_service.go:213-355) — all-or-nothing.
|
|
654
|
+
console.error(`Creating ${targetTables.length} object type(s) ...`);
|
|
655
|
+
const entries = targetTables.map((t) => {
|
|
656
|
+
const pk = detectPrimaryKey(t, sampleRows?.[t.name]);
|
|
657
|
+
const dk = detectDisplayKey(t, pk);
|
|
658
|
+
return {
|
|
659
|
+
branch: "main",
|
|
660
|
+
name: t.name,
|
|
661
|
+
data_source: { type: "data_view", id: viewMap[t.name] },
|
|
662
|
+
primary_keys: [pk],
|
|
663
|
+
display_key: dk,
|
|
664
|
+
data_properties: t.columns.map((c) => ({
|
|
665
|
+
name: c.name,
|
|
666
|
+
display_name: c.name,
|
|
667
|
+
type: "string",
|
|
668
|
+
mapped_field: { name: c.name, type: c.type || "varchar" },
|
|
669
|
+
})),
|
|
670
|
+
_meta: { pk, dk },
|
|
671
|
+
};
|
|
672
|
+
});
|
|
673
|
+
const wireEntries = entries.map(({ _meta: _, ...rest }) => rest);
|
|
674
|
+
const otBody = JSON.stringify({ entries: wireEntries });
|
|
635
675
|
const otResponse = await createObjectTypes({
|
|
636
676
|
...base,
|
|
637
677
|
knId,
|
|
638
678
|
body: otBody,
|
|
639
679
|
});
|
|
640
680
|
const otParsed = JSON.parse(otResponse);
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
if (otResults.length === 0) {
|
|
650
|
-
const errorOutput = {
|
|
651
|
-
kn_id: knId,
|
|
652
|
-
kn_name: options.name,
|
|
653
|
-
error: "No object types were created",
|
|
654
|
-
};
|
|
655
|
-
console.log(JSON.stringify(errorOutput, null, options.pretty ? 2 : 0));
|
|
656
|
-
return 1;
|
|
657
|
-
}
|
|
658
|
-
let statusStr = "skipped";
|
|
659
|
-
if (options.build) {
|
|
660
|
-
console.error("Building ...");
|
|
661
|
-
await buildKnowledgeNetwork({ ...base, knId });
|
|
662
|
-
const TERMINAL = ["completed", "failed", "success"];
|
|
663
|
-
try {
|
|
664
|
-
statusStr = await pollWithBackoff({
|
|
665
|
-
fn: async () => {
|
|
666
|
-
const statusBody = await getBuildStatus({ ...base, knId });
|
|
667
|
-
const statusParsed = JSON.parse(statusBody);
|
|
668
|
-
const jobs = Array.isArray(statusParsed) ? statusParsed : (statusParsed.entries ?? []);
|
|
669
|
-
const state = (jobs[0]?.state ?? "running").toLowerCase();
|
|
670
|
-
if (TERMINAL.includes(state))
|
|
671
|
-
return { done: true, value: state };
|
|
672
|
-
return { done: false, value: "running" };
|
|
673
|
-
},
|
|
674
|
-
interval: 2000,
|
|
675
|
-
timeout: options.timeout * 1000,
|
|
681
|
+
const otItems = Array.isArray(otParsed) ? otParsed : (otParsed.entries ?? []);
|
|
682
|
+
for (let i = 0; i < entries.length; i += 1) {
|
|
683
|
+
const t = targetTables[i];
|
|
684
|
+
const meta = entries[i]._meta;
|
|
685
|
+
otResults.push({
|
|
686
|
+
name: t.name,
|
|
687
|
+
id: otItems[i]?.id ?? "",
|
|
688
|
+
field_count: t.columns.length,
|
|
676
689
|
});
|
|
690
|
+
console.error(` Created: ${t.name} (${t.columns.length} fields, pk=${meta.pk}, dk=${meta.dk})`);
|
|
677
691
|
}
|
|
678
|
-
|
|
679
|
-
|
|
692
|
+
if (options.build) {
|
|
693
|
+
console.error("Building ...");
|
|
694
|
+
await buildKnowledgeNetwork({ ...base, knId });
|
|
695
|
+
const TERMINAL = ["completed", "failed", "success"];
|
|
696
|
+
try {
|
|
697
|
+
statusStr = await pollWithBackoff({
|
|
698
|
+
fn: async () => {
|
|
699
|
+
const statusBody = await getBuildStatus({ ...base, knId });
|
|
700
|
+
const statusParsed = JSON.parse(statusBody);
|
|
701
|
+
const jobs = Array.isArray(statusParsed) ? statusParsed : (statusParsed.entries ?? []);
|
|
702
|
+
const state = (jobs[0]?.state ?? "running").toLowerCase();
|
|
703
|
+
if (TERMINAL.includes(state))
|
|
704
|
+
return { done: true, value: state };
|
|
705
|
+
return { done: false, value: "running" };
|
|
706
|
+
},
|
|
707
|
+
interval: 2000,
|
|
708
|
+
timeout: options.timeout * 1000,
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
catch {
|
|
712
|
+
// build timeout — KN itself is fine, just mark skipped
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
// Reached the end without throwing — clear the rollback handle.
|
|
716
|
+
createdKnId = undefined;
|
|
717
|
+
}
|
|
718
|
+
finally {
|
|
719
|
+
if (createdKnId !== undefined) {
|
|
720
|
+
if (options.noRollback) {
|
|
721
|
+
console.error(`Leaving partial KN ${createdKnId} in place (--no-rollback)`);
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
console.error(`Rolling back KN ${createdKnId} ...`);
|
|
725
|
+
try {
|
|
726
|
+
await deleteKnowledgeNetwork({ ...base, knId: createdKnId });
|
|
727
|
+
console.error(`Rolled back KN ${createdKnId}`);
|
|
728
|
+
}
|
|
729
|
+
catch (rollbackErr) {
|
|
730
|
+
console.error(`Rollback failed for KN ${createdKnId}: ${formatHttpError(rollbackErr)}`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
680
733
|
}
|
|
681
734
|
}
|
|
682
735
|
const output = {
|
|
@@ -708,6 +761,7 @@ Options:
|
|
|
708
761
|
--no-build Skip build
|
|
709
762
|
--recreate Use "insert" mode on first batch (only effective for new tables)
|
|
710
763
|
--timeout <n> Build timeout in seconds (default: 300)
|
|
764
|
+
--no-rollback Keep partially-created KN on failure (debug; default: rollback)
|
|
711
765
|
-bd, --biz-domain Business domain (default: bd_public)`;
|
|
712
766
|
export function parseKnCreateFromCsvArgs(args) {
|
|
713
767
|
let dsId = "";
|
|
@@ -720,6 +774,7 @@ export function parseKnCreateFromCsvArgs(args) {
|
|
|
720
774
|
let recreate = false;
|
|
721
775
|
let timeout = 300;
|
|
722
776
|
let businessDomain = "";
|
|
777
|
+
let noRollback = false;
|
|
723
778
|
for (let i = 0; i < args.length; i += 1) {
|
|
724
779
|
const arg = args[i];
|
|
725
780
|
if (arg === "--help" || arg === "-h")
|
|
@@ -758,6 +813,10 @@ export function parseKnCreateFromCsvArgs(args) {
|
|
|
758
813
|
recreate = true;
|
|
759
814
|
continue;
|
|
760
815
|
}
|
|
816
|
+
if (arg === "--no-rollback") {
|
|
817
|
+
noRollback = true;
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
761
820
|
if (arg === "--timeout" && args[i + 1]) {
|
|
762
821
|
timeout = parseInt(args[++i], 10);
|
|
763
822
|
if (Number.isNaN(timeout) || timeout < 1)
|
|
@@ -778,7 +837,7 @@ export function parseKnCreateFromCsvArgs(args) {
|
|
|
778
837
|
}
|
|
779
838
|
if (!businessDomain)
|
|
780
839
|
businessDomain = resolveBusinessDomain();
|
|
781
|
-
return { dsId, files, name, tablePrefix, batchSize, tables, build, recreate, timeout, businessDomain };
|
|
840
|
+
return { dsId, files, name, tablePrefix, batchSize, tables, build, recreate, timeout, businessDomain, noRollback };
|
|
782
841
|
}
|
|
783
842
|
export async function runKnCreateFromCsvCommand(args) {
|
|
784
843
|
let options;
|
|
@@ -793,6 +852,20 @@ export async function runKnCreateFromCsvCommand(args) {
|
|
|
793
852
|
console.error(formatHttpError(error));
|
|
794
853
|
return 1;
|
|
795
854
|
}
|
|
855
|
+
// Pre-flight: predict OT names from (table-prefix + csv basename) and
|
|
856
|
+
// reject before any CSV is imported. CSV import is expensive; failing
|
|
857
|
+
// here saves the user a multi-minute round trip.
|
|
858
|
+
try {
|
|
859
|
+
const filePaths = await resolveFiles(options.files);
|
|
860
|
+
const predictedNames = options.tables.length > 0
|
|
861
|
+
? options.tables
|
|
862
|
+
: filePaths.map((p) => buildTableName(p, options.tablePrefix));
|
|
863
|
+
assertValidBknObjectNames(predictedNames, "Object type names derived from CSV file names");
|
|
864
|
+
}
|
|
865
|
+
catch (error) {
|
|
866
|
+
console.error(formatHttpError(error));
|
|
867
|
+
return 1;
|
|
868
|
+
}
|
|
796
869
|
// Phase 1: Import CSVs
|
|
797
870
|
console.error("Phase 1: Importing CSVs ...");
|
|
798
871
|
const importArgs = [
|
|
@@ -844,6 +917,7 @@ export async function runKnCreateFromCsvCommand(args) {
|
|
|
844
917
|
options.build ? "--build" : "--no-build",
|
|
845
918
|
"--timeout", String(options.timeout),
|
|
846
919
|
"-bd", options.businessDomain,
|
|
920
|
+
...(options.noRollback ? ["--no-rollback"] : []),
|
|
847
921
|
];
|
|
848
922
|
return runKnCreateFromDsCommand(knArgs, importResult.sampleRows);
|
|
849
923
|
}
|
|
@@ -31,13 +31,18 @@ Query subgraph via ontology-query API. JSON body format see references/json-form
|
|
|
31
31
|
return 1;
|
|
32
32
|
}
|
|
33
33
|
try {
|
|
34
|
-
//
|
|
34
|
+
// Map body shape to ontology-query subgraph query_type:
|
|
35
|
+
// - relation_type_paths mode → ?query_type=relation_path
|
|
36
|
+
// - source_object_type_id mode → omit query_type (default path; do not send relation_path)
|
|
35
37
|
let queryType;
|
|
36
38
|
try {
|
|
37
39
|
const parsedBody = JSON.parse(body);
|
|
38
|
-
if (parsedBody.
|
|
40
|
+
if (Array.isArray(parsedBody.relation_type_paths)) {
|
|
39
41
|
queryType = "relation_path";
|
|
40
42
|
}
|
|
43
|
+
else if (parsedBody.source_object_type_id) {
|
|
44
|
+
queryType = "";
|
|
45
|
+
}
|
|
41
46
|
}
|
|
42
47
|
catch {
|
|
43
48
|
// Not valid JSON — let the API return the error
|
package/dist/commands/config.js
CHANGED
|
@@ -2,6 +2,7 @@ import { listBusinessDomains } from "../api/business-domains.js";
|
|
|
2
2
|
import { fetchEacpUserInfo, resolveActivePlatform, withTokenRetry } from "../auth/oauth.js";
|
|
3
3
|
import { HttpError } from "../utils/http.js";
|
|
4
4
|
import { loadPlatformBusinessDomain, resolveBusinessDomain, savePlatformBusinessDomain, } from "../config/store.js";
|
|
5
|
+
import { assertNotStatelessForWrite } from "../config/stateless.js";
|
|
5
6
|
const HELP = `kweaver config
|
|
6
7
|
|
|
7
8
|
Subcommands:
|
|
@@ -50,6 +51,13 @@ export async function runConfigCommand(args) {
|
|
|
50
51
|
return 1;
|
|
51
52
|
}
|
|
52
53
|
const platform = active.url;
|
|
54
|
+
try {
|
|
55
|
+
assertNotStatelessForWrite("config set-bd");
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
59
|
+
return 1;
|
|
60
|
+
}
|
|
53
61
|
savePlatformBusinessDomain(platform, value);
|
|
54
62
|
const provenance = active.source === "env" ? `${platform} via KWEAVER_BASE_URL` : platform;
|
|
55
63
|
console.log(`Business domain set to: ${value} (${provenance})`);
|