@kweaver-ai/kweaver-sdk 0.7.1 → 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 +28 -3
- package/README.zh.md +27 -2
- package/dist/api/skills.js +10 -8
- package/dist/cli.js +47 -15
- 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/config.js +8 -0
- package/dist/commands/context-loader.js +112 -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/config/stateless.d.ts +13 -0
- package/dist/config/stateless.js +20 -0
- 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/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
|
}
|
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})`);
|
|
@@ -2,12 +2,28 @@ import { ensureValidToken, formatHttpError, resolveActivePlatform, with401Refres
|
|
|
2
2
|
import { callTool, searchSchema, queryObjectInstance, queryInstanceSubgraph, getLogicPropertiesValues, getActionInfo, findSkills, listTools, listResources, readResource, listResourceTemplates, listPrompts, getPrompt, } from "../api/context-loader.js";
|
|
3
3
|
import { knSearchHttp, semanticSearch } from "../api/semantic-search.js";
|
|
4
4
|
import { addContextLoaderEntry, getCurrentContextLoaderKn, loadContextLoaderConfig, removeContextLoaderEntry, resolveBusinessDomain, setCurrentContextLoader, } from "../config/store.js";
|
|
5
|
+
import { assertNotStatelessForWrite } from "../config/stateless.js";
|
|
6
|
+
const CONTEXT_LOADER_CONFIG_DEPRECATION = "[deprecated] `kweaver context-loader config ...` will be removed in a future release. " +
|
|
7
|
+
"Pass <kn-id> as the first positional to runtime subcommands instead, e.g. " +
|
|
8
|
+
"`kweaver context-loader tools <kn-id>` (or use the `--kn-id <id>` flag).";
|
|
5
9
|
const MCP_NOT_CONFIGURED = "Context-loader MCP is not configured. Run: kweaver context-loader config set --kn-id <kn-id>";
|
|
6
|
-
|
|
10
|
+
const MCP_PATH = "/api/agent-retrieval/v1/mcp";
|
|
11
|
+
function ensureContextLoaderConfig(knIdOverride) {
|
|
7
12
|
const active = resolveActivePlatform();
|
|
8
13
|
if (!active) {
|
|
9
14
|
throw new Error("No platform selected. Set KWEAVER_BASE_URL or run: kweaver auth <platform-url>");
|
|
10
15
|
}
|
|
16
|
+
// Override path (positional <kn-id> or --kn-id flag): derive MCP URL from
|
|
17
|
+
// the active platform; do not touch the deprecated saved config.
|
|
18
|
+
if (knIdOverride) {
|
|
19
|
+
return {
|
|
20
|
+
baseUrl: active.url,
|
|
21
|
+
mcpUrl: active.url.replace(/\/+$/, "") + MCP_PATH,
|
|
22
|
+
knId: knIdOverride,
|
|
23
|
+
accessToken: "",
|
|
24
|
+
businessDomain: resolveBusinessDomain(active.url),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
11
27
|
const kn = getCurrentContextLoaderKn();
|
|
12
28
|
if (!kn) {
|
|
13
29
|
throw new Error(MCP_NOT_CONFIGURED);
|
|
@@ -20,6 +36,50 @@ function ensureContextLoaderConfig() {
|
|
|
20
36
|
businessDomain: resolveBusinessDomain(active.url),
|
|
21
37
|
};
|
|
22
38
|
}
|
|
39
|
+
// Subcommands that consult `ensureContextLoaderConfig`. The number is the
|
|
40
|
+
// minimum non-flag positional count expected by the handler itself (after
|
|
41
|
+
// kn-id is extracted). When the leading non-flag positional count exceeds
|
|
42
|
+
// this minimum, the first one is treated as <kn-id>.
|
|
43
|
+
const RUNTIME_MIN_POSITIONALS = {
|
|
44
|
+
tools: 0,
|
|
45
|
+
resources: 0,
|
|
46
|
+
templates: 0,
|
|
47
|
+
prompts: 0,
|
|
48
|
+
prompt: 1,
|
|
49
|
+
resource: 1,
|
|
50
|
+
"search-schema": 1,
|
|
51
|
+
"tool-call": 1,
|
|
52
|
+
"kn-search": 1,
|
|
53
|
+
"kn-schema-search": 1,
|
|
54
|
+
"query-object-instance": 1,
|
|
55
|
+
"query-instance-subgraph": 1,
|
|
56
|
+
"get-logic-properties": 1,
|
|
57
|
+
"get-action-info": 1,
|
|
58
|
+
"find-skills": 1,
|
|
59
|
+
};
|
|
60
|
+
function extractKnIdOverride(subcommand, rest) {
|
|
61
|
+
// 1) Explicit flag wins. `--kn-id <id>` / `-k <id>` is allowed for every
|
|
62
|
+
// runtime subcommand and is consumed before the handler sees `rest`.
|
|
63
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
64
|
+
if ((rest[i] === "--kn-id" || rest[i] === "-k") && rest[i + 1]) {
|
|
65
|
+
const id = rest[i + 1];
|
|
66
|
+
rest.splice(i, 2);
|
|
67
|
+
return id;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// 2) Positional <kn-id> as the first non-flag arg, when leading non-flag
|
|
71
|
+
// positional count exceeds what the handler itself requires.
|
|
72
|
+
const min = RUNTIME_MIN_POSITIONALS[subcommand];
|
|
73
|
+
if (min === undefined)
|
|
74
|
+
return undefined;
|
|
75
|
+
let cut = 0;
|
|
76
|
+
while (cut < rest.length && !rest[cut].startsWith("-"))
|
|
77
|
+
cut += 1;
|
|
78
|
+
if (cut > min) {
|
|
79
|
+
return rest.shift();
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
23
83
|
function formatOutput(value, pretty) {
|
|
24
84
|
const json = JSON.stringify(value, null, pretty ? 2 : 0);
|
|
25
85
|
return json;
|
|
@@ -29,34 +89,38 @@ export async function runContextLoaderCommand(args) {
|
|
|
29
89
|
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
30
90
|
console.log(`kweaver context-loader
|
|
31
91
|
|
|
92
|
+
KN selection (for runtime subcommands below):
|
|
93
|
+
Pass <kn-id> as the FIRST positional, e.g. \`kweaver context-loader tools <kn-id>\`,
|
|
94
|
+
or use the global \`--kn-id <id>\` / \`-k <id>\` flag. When omitted, falls back to
|
|
95
|
+
the deprecated saved config managed by \`kweaver context-loader config\`.
|
|
96
|
+
|
|
32
97
|
Subcommands:
|
|
33
|
-
config set --kn-id <id> [--name n] Add or update kn config
|
|
34
|
-
config use <name> Switch current config
|
|
35
|
-
config list
|
|
36
|
-
config remove <name> Remove a config
|
|
37
|
-
config show
|
|
38
|
-
tools
|
|
39
|
-
resources
|
|
40
|
-
resource <uri>
|
|
41
|
-
templates
|
|
42
|
-
prompts
|
|
43
|
-
prompt <name> [--args json]
|
|
44
|
-
search-schema <query> [
|
|
45
|
-
tool-call <name> --args '<json>'
|
|
46
|
-
kn-search <query> [--only-schema]
|
|
47
|
-
kn-schema-search <query> [--max N]
|
|
48
|
-
query-object-instance <json>
|
|
49
|
-
query-instance-subgraph <json>
|
|
50
|
-
get-logic-properties <json>
|
|
51
|
-
get-action-info <json>
|
|
52
|
-
find-skills <ot_id> [options]
|
|
98
|
+
config set --kn-id <id> [--name n] [deprecated] Add or update kn config
|
|
99
|
+
config use <name> [deprecated] Switch current config
|
|
100
|
+
config list [deprecated] List all configs and current
|
|
101
|
+
config remove <name> [deprecated] Remove a config
|
|
102
|
+
config show [deprecated] Show current config (knId + mcpUrl)
|
|
103
|
+
tools <kn-id> tools/list - list available tools
|
|
104
|
+
resources <kn-id> resources/list - list resources
|
|
105
|
+
resource <kn-id> <uri> resources/read - read resource by URI
|
|
106
|
+
templates <kn-id> resources/templates/list - list resource templates
|
|
107
|
+
prompts <kn-id> prompts/list - list prompts
|
|
108
|
+
prompt <kn-id> <name> [--args json] prompts/get - get prompt by name
|
|
109
|
+
search-schema <kn-id> <query> [opts] MCP search_schema (object/relation/action/metric)
|
|
110
|
+
tool-call <kn-id> <name> --args '<json>' MCP tools/call for any server tool
|
|
111
|
+
kn-search <kn-id> <query> [--only-schema] Compatibility: HTTP kn_search
|
|
112
|
+
kn-schema-search <kn-id> <query> [--max N] Compatibility: HTTP semantic-search
|
|
113
|
+
query-object-instance <kn-id> <json> Layer 2: Query instances
|
|
114
|
+
query-instance-subgraph <kn-id> <json> Layer 2: Query subgraph
|
|
115
|
+
get-logic-properties <kn-id> <json> Layer 3: Get logic property values
|
|
116
|
+
get-action-info <kn-id> <json> Layer 3: Get action info
|
|
117
|
+
find-skills <kn-id> <ot_id> [options] Layer 3: Recall skills for an object type
|
|
53
118
|
|
|
54
119
|
Examples:
|
|
55
|
-
kweaver context-loader
|
|
56
|
-
kweaver context-loader
|
|
57
|
-
kweaver context-loader
|
|
58
|
-
kweaver context-loader
|
|
59
|
-
kweaver context-loader kn-search "高血压 治疗 药品" --only-schema --pretty`);
|
|
120
|
+
kweaver context-loader tools d5iv6c9818p72mpje8pg
|
|
121
|
+
kweaver context-loader search-schema d5iv6c9818p72mpje8pg "利润率" --scope object,metric --max 5
|
|
122
|
+
kweaver context-loader tool-call d5iv6c9818p72mpje8pg search_schema --args '{"query":"利润率"}'
|
|
123
|
+
kweaver context-loader kn-search d5iv6c9818p72mpje8pg "高血压 治疗 药品" --only-schema --pretty`);
|
|
60
124
|
return 0;
|
|
61
125
|
}
|
|
62
126
|
if (subcommand === "config") {
|
|
@@ -68,9 +132,12 @@ Examples:
|
|
|
68
132
|
pretty = true;
|
|
69
133
|
rest.splice(prettyIdx, 1);
|
|
70
134
|
}
|
|
135
|
+
// Extract `<kn-id>` (positional or --kn-id/-k flag) before per-subcommand
|
|
136
|
+
// arg parsing. When provided it bypasses the deprecated saved config.
|
|
137
|
+
const knIdOverride = extractKnIdOverride(subcommand, rest);
|
|
71
138
|
const dispatch = async () => {
|
|
72
139
|
const token = await ensureValidToken();
|
|
73
|
-
const base = ensureContextLoaderConfig();
|
|
140
|
+
const base = ensureContextLoaderConfig(knIdOverride);
|
|
74
141
|
const options = { ...base, accessToken: token.accessToken };
|
|
75
142
|
if (subcommand === "tools")
|
|
76
143
|
return runListTools(options, rest, pretty);
|
|
@@ -122,16 +189,30 @@ Examples:
|
|
|
122
189
|
async function runConfigCommand(args) {
|
|
123
190
|
const [action, ...rest] = args;
|
|
124
191
|
if (!action || action === "--help" || action === "-h") {
|
|
125
|
-
console.log(`kweaver context-loader config
|
|
192
|
+
console.log(`kweaver context-loader config [deprecated]
|
|
126
193
|
|
|
127
194
|
Subcommands:
|
|
128
195
|
set --kn-id <id> [--name <name>] Add or update kn config (default name: default)
|
|
129
196
|
use <name> Switch current config
|
|
130
197
|
list List all configs and current
|
|
131
198
|
remove <name> Remove a config
|
|
132
|
-
show Show current config (knId + mcpUrl)
|
|
199
|
+
show Show current config (knId + mcpUrl)
|
|
200
|
+
|
|
201
|
+
Note: this command group is deprecated and will be removed in a future release.
|
|
202
|
+
It is disabled entirely in stateless mode (\`--token\`).`);
|
|
133
203
|
return 0;
|
|
134
204
|
}
|
|
205
|
+
// Stateless mode (`--token`) does not support any context-loader config
|
|
206
|
+
// operations; the saved config lives under `~/.kweaver/` and is foreign
|
|
207
|
+
// to the stateless paradigm.
|
|
208
|
+
try {
|
|
209
|
+
assertNotStatelessForWrite(`context-loader config ${action}`);
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
213
|
+
return 1;
|
|
214
|
+
}
|
|
215
|
+
console.warn(CONTEXT_LOADER_CONFIG_DEPRECATION);
|
|
135
216
|
const active = resolveActivePlatform();
|
|
136
217
|
if (!active) {
|
|
137
218
|
console.error("No platform selected. Set KWEAVER_BASE_URL or run: kweaver auth <platform-url>");
|
|
@@ -435,29 +516,24 @@ async function runToolCall(options, args, pretty) {
|
|
|
435
516
|
async function runKnSearch(options, args, pretty) {
|
|
436
517
|
let query;
|
|
437
518
|
let onlySchema = false;
|
|
438
|
-
let knIdOverride;
|
|
439
519
|
for (let i = 0; i < args.length; i += 1) {
|
|
440
520
|
const arg = args[i];
|
|
441
521
|
if (arg === "--only-schema") {
|
|
442
522
|
onlySchema = true;
|
|
443
523
|
}
|
|
444
|
-
else if ((arg === "--kn-id" || arg === "-k") && args[i + 1]) {
|
|
445
|
-
knIdOverride = args[i + 1];
|
|
446
|
-
i += 1;
|
|
447
|
-
}
|
|
448
524
|
else if (!arg.startsWith("-") && !query) {
|
|
449
525
|
query = arg;
|
|
450
526
|
}
|
|
451
527
|
}
|
|
452
528
|
if (!query) {
|
|
453
|
-
console.error("Usage: kweaver context-loader kn-search <
|
|
529
|
+
console.error("Usage: kweaver context-loader kn-search <kn-id> <query> [--only-schema]");
|
|
454
530
|
return 1;
|
|
455
531
|
}
|
|
456
532
|
const raw = await knSearchHttp({
|
|
457
533
|
baseUrl: options.baseUrl,
|
|
458
534
|
accessToken: options.accessToken,
|
|
459
535
|
businessDomain: options.businessDomain,
|
|
460
|
-
knId:
|
|
536
|
+
knId: options.knId,
|
|
461
537
|
query,
|
|
462
538
|
onlySchema,
|
|
463
539
|
});
|
package/dist/commands/ds.d.ts
CHANGED
|
@@ -5,6 +5,29 @@ export declare function parseDsListArgs(args: string[]): {
|
|
|
5
5
|
businessDomain: string;
|
|
6
6
|
pretty: boolean;
|
|
7
7
|
};
|
|
8
|
+
/**
|
|
9
|
+
* Match candidate signature against a list response (the kind returned by
|
|
10
|
+
* `listDatasources`). Connection metadata lives under `bin_data` — host,
|
|
11
|
+
* port, account, plus type-specific fields (`database_name` for MySQL etc.).
|
|
12
|
+
*
|
|
13
|
+
* Exported for unit testing.
|
|
14
|
+
*/
|
|
15
|
+
export interface DsMatchSignature {
|
|
16
|
+
type: string;
|
|
17
|
+
host: string;
|
|
18
|
+
port: number;
|
|
19
|
+
database: string;
|
|
20
|
+
account: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface DsMatchHit {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
matchedByName: boolean;
|
|
27
|
+
matchedByTuple: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function findExistingDatasource(listBody: string, sig: DsMatchSignature): DsMatchHit | undefined;
|
|
30
|
+
export declare function findDatasourceIdByName(listBody: string, name: string): string | undefined;
|
|
8
31
|
export declare function parseImportCsvArgs(args: string[]): {
|
|
9
32
|
datasourceId: string;
|
|
10
33
|
files: string;
|