@kweaver-ai/kweaver-sdk 0.7.3 → 0.7.4
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 +29 -0
- package/README.zh.md +26 -0
- package/bin/kweaver.js +12 -11
- package/dist/api/bkn-backend.d.ts +1 -0
- package/dist/api/bkn-backend.js +1 -1
- package/dist/api/bkn-metrics.d.ts +59 -0
- package/dist/api/bkn-metrics.js +129 -0
- package/dist/api/conversations.d.ts +47 -2
- package/dist/api/conversations.js +113 -17
- package/dist/api/datasources.js +43 -6
- package/dist/api/model-invocation.d.ts +58 -0
- package/dist/api/model-invocation.js +203 -0
- package/dist/api/models.d.ts +79 -0
- package/dist/api/models.js +183 -0
- package/dist/api/ontology-query-metrics.d.ts +14 -0
- package/dist/api/ontology-query-metrics.js +30 -0
- package/dist/bundled-model-templates.d.ts +17 -0
- package/dist/bundled-model-templates.js +24 -0
- package/dist/cli.js +10 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.js +5 -0
- package/dist/commands/agent.d.ts +7 -1
- package/dist/commands/agent.js +75 -21
- package/dist/commands/bkn-metric.d.ts +1 -0
- package/dist/commands/bkn-metric.js +406 -0
- package/dist/commands/bkn-ops.js +17 -11
- package/dist/commands/bkn-utils.d.ts +29 -0
- package/dist/commands/bkn-utils.js +37 -0
- package/dist/commands/bkn.js +4 -0
- package/dist/commands/ds.js +7 -1
- package/dist/commands/explore-chat.js +2 -2
- package/dist/commands/model.d.ts +72 -0
- package/dist/commands/model.js +1315 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +5 -0
- package/dist/resources/models.d.ts +40 -0
- package/dist/resources/models.js +88 -0
- package/dist/templates/model/llm-basic.json +13 -0
- package/dist/templates/model/manifest.json +16 -0
- package/dist/templates/model/small-basic.json +6 -0
- package/dist/utils/trace-views.d.ts +44 -0
- package/dist/utils/trace-views.js +425 -0
- package/package.json +3 -3
package/dist/client.js
CHANGED
|
@@ -14,6 +14,7 @@ import { BknResource } from "./resources/bkn.js";
|
|
|
14
14
|
import { SkillsResource } from "./resources/skills.js";
|
|
15
15
|
import { ToolboxesResource } from "./resources/toolboxes.js";
|
|
16
16
|
import { VegaResource } from "./resources/vega.js";
|
|
17
|
+
import { ModelsResource } from "./resources/models.js";
|
|
17
18
|
// ── KWeaverClient ─────────────────────────────────────────────────────────────
|
|
18
19
|
/**
|
|
19
20
|
* Main entry point for the KWeaver TypeScript SDK.
|
|
@@ -67,6 +68,8 @@ export class KWeaverClient {
|
|
|
67
68
|
skills;
|
|
68
69
|
/** Toolbox / tool management plus execute & debug invocation. */
|
|
69
70
|
toolboxes;
|
|
71
|
+
/** Model factory (mf-model-manager CRUD + mf-model-api chat / embedding / rerank). */
|
|
72
|
+
models;
|
|
70
73
|
constructor(opts = {}) {
|
|
71
74
|
const envDomain = process.env.KWEAVER_BUSINESS_DOMAIN;
|
|
72
75
|
if (opts.auth === false && opts.config) {
|
|
@@ -101,6 +104,7 @@ export class KWeaverClient {
|
|
|
101
104
|
this.vega = new VegaResource(this);
|
|
102
105
|
this.skills = new SkillsResource(this);
|
|
103
106
|
this.toolboxes = new ToolboxesResource(this);
|
|
107
|
+
this.models = new ModelsResource(this);
|
|
104
108
|
return;
|
|
105
109
|
}
|
|
106
110
|
if (opts.config) {
|
|
@@ -156,6 +160,7 @@ export class KWeaverClient {
|
|
|
156
160
|
this.vega = new VegaResource(this);
|
|
157
161
|
this.skills = new SkillsResource(this);
|
|
158
162
|
this.toolboxes = new ToolboxesResource(this);
|
|
163
|
+
this.models = new ModelsResource(this);
|
|
159
164
|
}
|
|
160
165
|
/**
|
|
161
166
|
* Async factory that auto-refreshes expired or revoked tokens.
|
package/dist/commands/agent.d.ts
CHANGED
|
@@ -65,8 +65,14 @@ export interface AgentHistoryOptions {
|
|
|
65
65
|
}
|
|
66
66
|
export declare function parseAgentHistoryArgs(args: string[]): AgentHistoryOptions;
|
|
67
67
|
export interface AgentTraceOptions {
|
|
68
|
-
|
|
68
|
+
/** Optional. Retained as positional arg for backward compatibility; trace-ai keys by conversation_id only. */
|
|
69
|
+
agentId?: string;
|
|
69
70
|
conversationId: string;
|
|
71
|
+
view: "tree" | "perf" | "evidence" | "reasoning" | "all";
|
|
72
|
+
/** When true, emit raw JSON of the TracesByConversationResult instead of a rendered view. */
|
|
73
|
+
json: boolean;
|
|
74
|
+
/** Disable per-message truncation in the reasoning view. */
|
|
75
|
+
full: boolean;
|
|
70
76
|
pretty: boolean;
|
|
71
77
|
}
|
|
72
78
|
export declare function parseAgentTraceArgs(args: string[]): AgentTraceOptions;
|
package/dist/commands/agent.js
CHANGED
|
@@ -468,21 +468,43 @@ export function parseAgentHistoryArgs(args) {
|
|
|
468
468
|
const finalConversationId = optionStartIndex === 2 ? args[1] : args[0];
|
|
469
469
|
return { agentId: finalAgentId, conversationId: finalConversationId, businessDomain, pretty, limit };
|
|
470
470
|
}
|
|
471
|
+
const TRACE_VIEWS = new Set(["tree", "perf", "evidence", "reasoning", "all"]);
|
|
471
472
|
export function parseAgentTraceArgs(args) {
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const conversationId = args[1];
|
|
477
|
-
if (!conversationId || conversationId.startsWith("-")) {
|
|
478
|
-
throw new Error("Missing conversation_id");
|
|
479
|
-
}
|
|
473
|
+
const positional = [];
|
|
474
|
+
let view = "tree";
|
|
475
|
+
let json = false;
|
|
476
|
+
let full = false;
|
|
480
477
|
let pretty = true;
|
|
481
|
-
for (let i =
|
|
478
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
482
479
|
const arg = args[i];
|
|
483
480
|
if (arg === "--help" || arg === "-h") {
|
|
484
481
|
throw new Error("help");
|
|
485
482
|
}
|
|
483
|
+
if (arg === "--view") {
|
|
484
|
+
const next = args[i + 1];
|
|
485
|
+
if (!next || !TRACE_VIEWS.has(next)) {
|
|
486
|
+
throw new Error(`--view requires one of: tree, perf, evidence, reasoning, all`);
|
|
487
|
+
}
|
|
488
|
+
view = next;
|
|
489
|
+
i += 1;
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
if (arg.startsWith("--view=")) {
|
|
493
|
+
const value = arg.slice("--view=".length);
|
|
494
|
+
if (!TRACE_VIEWS.has(value)) {
|
|
495
|
+
throw new Error(`--view requires one of: tree, perf, evidence, reasoning, all`);
|
|
496
|
+
}
|
|
497
|
+
view = value;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (arg === "--json") {
|
|
501
|
+
json = true;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (arg === "--full") {
|
|
505
|
+
full = true;
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
486
508
|
if (arg === "--pretty") {
|
|
487
509
|
pretty = true;
|
|
488
510
|
continue;
|
|
@@ -491,9 +513,26 @@ export function parseAgentTraceArgs(args) {
|
|
|
491
513
|
pretty = false;
|
|
492
514
|
continue;
|
|
493
515
|
}
|
|
494
|
-
|
|
516
|
+
if (arg.startsWith("-")) {
|
|
517
|
+
throw new Error(`Unsupported agent trace argument: ${arg}`);
|
|
518
|
+
}
|
|
519
|
+
positional.push(arg);
|
|
520
|
+
}
|
|
521
|
+
// Backward-compat: legacy form is `trace <agent_id> <conversation_id>`.
|
|
522
|
+
// New form: `trace <conversation_id>`. We disambiguate by argument count.
|
|
523
|
+
let agentId;
|
|
524
|
+
let conversationId;
|
|
525
|
+
if (positional.length === 0) {
|
|
526
|
+
throw new Error("Missing conversation_id");
|
|
527
|
+
}
|
|
528
|
+
else if (positional.length === 1) {
|
|
529
|
+
conversationId = positional[0];
|
|
495
530
|
}
|
|
496
|
-
|
|
531
|
+
else {
|
|
532
|
+
agentId = positional[0];
|
|
533
|
+
conversationId = positional[1];
|
|
534
|
+
}
|
|
535
|
+
return { agentId, conversationId, view, json, full, pretty };
|
|
497
536
|
}
|
|
498
537
|
export async function runAgentCommand(args) {
|
|
499
538
|
const [subcommand, ...rest] = args;
|
|
@@ -520,7 +559,8 @@ Subcommands:
|
|
|
520
559
|
skill <verb> ... Manage skills attached to an agent (add/remove/list)
|
|
521
560
|
sessions <agent_id> List all conversations for an agent
|
|
522
561
|
history <agent_id> <conversation_id> Show message history for a conversation
|
|
523
|
-
trace <
|
|
562
|
+
trace <conversation_id> [--view tree|perf|evidence|reasoning|all] [--json]
|
|
563
|
+
Get trace data for a conversation`);
|
|
524
564
|
return Promise.resolve(0);
|
|
525
565
|
}
|
|
526
566
|
const dispatch = async () => {
|
|
@@ -724,13 +764,16 @@ Options:
|
|
|
724
764
|
}
|
|
725
765
|
if (subcommand === "trace") {
|
|
726
766
|
if (rest.length === 1 && (rest[0] === "--help" || rest[0] === "-h")) {
|
|
727
|
-
console.log(`kweaver agent trace <
|
|
767
|
+
console.log(`kweaver agent trace <conversation_id> [options]
|
|
768
|
+
kweaver agent trace <agent_id> <conversation_id> [options] (legacy)
|
|
728
769
|
|
|
729
770
|
Get trace data for a conversation.
|
|
730
771
|
|
|
731
772
|
Options:
|
|
732
|
-
--
|
|
733
|
-
--
|
|
773
|
+
--view tree|perf|evidence|reasoning|all Render style (default: tree)
|
|
774
|
+
--json Emit raw TracesByConversationResult JSON
|
|
775
|
+
--pretty Pretty-print JSON output (default)
|
|
776
|
+
--compact Compact JSON output`);
|
|
734
777
|
return 0;
|
|
735
778
|
}
|
|
736
779
|
}
|
|
@@ -1031,13 +1074,18 @@ async function runAgentTraceCommand(args) {
|
|
|
1031
1074
|
}
|
|
1032
1075
|
catch (error) {
|
|
1033
1076
|
if (error instanceof Error && error.message === "help") {
|
|
1034
|
-
console.log(`kweaver agent trace <
|
|
1077
|
+
console.log(`kweaver agent trace <conversation_id> [options]
|
|
1078
|
+
kweaver agent trace <agent_id> <conversation_id> [options] (legacy)
|
|
1035
1079
|
|
|
1036
|
-
Get trace data for a conversation.
|
|
1080
|
+
Get trace data for a conversation. Spans are fetched from trace-ai via a 2-jump
|
|
1081
|
+
lookup that recovers pipeline spans (HTTP entry, internal RPCs, prompt-build)
|
|
1082
|
+
which the simpler /by-conversation endpoint omits.
|
|
1037
1083
|
|
|
1038
1084
|
Options:
|
|
1039
|
-
--
|
|
1040
|
-
--
|
|
1085
|
+
--view tree|perf|evidence|reasoning|all Render style (default: tree)
|
|
1086
|
+
--json Emit raw TracesByConversationResult JSON
|
|
1087
|
+
--pretty Pretty-print JSON output (default)
|
|
1088
|
+
--compact Compact JSON output`);
|
|
1041
1089
|
return 0;
|
|
1042
1090
|
}
|
|
1043
1091
|
console.error(formatHttpError(error));
|
|
@@ -1045,13 +1093,19 @@ Options:
|
|
|
1045
1093
|
}
|
|
1046
1094
|
try {
|
|
1047
1095
|
const token = await ensureValidToken();
|
|
1048
|
-
const
|
|
1096
|
+
const result = await getTracesByConversation({
|
|
1049
1097
|
baseUrl: token.baseUrl,
|
|
1050
1098
|
accessToken: token.accessToken,
|
|
1051
1099
|
agentId: options.agentId,
|
|
1052
1100
|
conversationId: options.conversationId,
|
|
1053
1101
|
});
|
|
1054
|
-
|
|
1102
|
+
if (options.json) {
|
|
1103
|
+
console.log(formatCallOutput(JSON.stringify(result), options.pretty));
|
|
1104
|
+
}
|
|
1105
|
+
else {
|
|
1106
|
+
const { formatTraceResult } = await import("../utils/trace-views.js");
|
|
1107
|
+
console.log(formatTraceResult(result, options.view, { full: options.full }));
|
|
1108
|
+
}
|
|
1055
1109
|
return 0;
|
|
1056
1110
|
}
|
|
1057
1111
|
catch (error) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runKnMetricCommand(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
|
|
2
|
+
import { listMetrics, createMetrics, searchMetrics, validateMetrics, getMetric, updateMetric, deleteMetric, getMetrics, deleteMetrics, } from "../api/bkn-metrics.js";
|
|
3
|
+
import { metricQueryData, metricDryRun } from "../api/ontology-query-metrics.js";
|
|
4
|
+
import { formatCallOutput } from "./call.js";
|
|
5
|
+
import { resolveBusinessDomain } from "../config/store.js";
|
|
6
|
+
import { parseJsonObject, parseSearchAfterArray, confirmYes } from "./bkn-utils.js";
|
|
7
|
+
function parseCommaSeparatedIds(raw) {
|
|
8
|
+
return raw
|
|
9
|
+
.split(",")
|
|
10
|
+
.map((s) => s.trim())
|
|
11
|
+
.filter((s) => s.length > 0);
|
|
12
|
+
}
|
|
13
|
+
const METRIC_HELP = `kweaver bkn metric <action> [args] [--pretty] [-bd <domain>]
|
|
14
|
+
|
|
15
|
+
Management (bkn-backend):
|
|
16
|
+
list <kn-id> [--limit <n>] [--branch <b>] [--name-pattern <p>] [--sort update_time|name] [--direction asc|desc] [--offset <n>] [--tag <t>] [--group-id <id>]
|
|
17
|
+
get <kn-id> <metric-id(s)> [--branch <b>] (comma-separated for multiple)
|
|
18
|
+
create <kn-id> '<json>' [--branch] [--strict-mode true|false]
|
|
19
|
+
search <kn-id> '<json>' [--branch] [--strict-mode] [--limit <n>] [--search-after '<json>']
|
|
20
|
+
validate <kn-id> '<json>' [--branch] [--strict-mode] [--import-mode normal|ignore|overwrite]
|
|
21
|
+
update <kn-id> <metric-id> '<json>' [--branch] [--strict-mode]
|
|
22
|
+
delete <kn-id> <metric-id(s)> [-y] (comma-separated for multiple)
|
|
23
|
+
|
|
24
|
+
Query (ontology-query):
|
|
25
|
+
query <kn-id> <metric-id> ['<json-body>'] [--branch] [--fill-null]
|
|
26
|
+
dry-run <kn-id> '<json>' [--branch] [--fill-null]
|
|
27
|
+
|
|
28
|
+
list: default --limit 30. search/query JSON: default limit 50 in body when not set.`;
|
|
29
|
+
function parseListArgs(args) {
|
|
30
|
+
let pretty = true;
|
|
31
|
+
let businessDomain = "";
|
|
32
|
+
let limit = 30;
|
|
33
|
+
let branch;
|
|
34
|
+
let namePattern;
|
|
35
|
+
let sort;
|
|
36
|
+
let direction;
|
|
37
|
+
let offset;
|
|
38
|
+
let tag;
|
|
39
|
+
let groupId;
|
|
40
|
+
const pos = [];
|
|
41
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
42
|
+
const a = args[i];
|
|
43
|
+
if (a === "--help" || a === "-h")
|
|
44
|
+
throw new Error("help");
|
|
45
|
+
if (a === "--pretty") {
|
|
46
|
+
pretty = true;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
50
|
+
businessDomain = args[i + 1];
|
|
51
|
+
i += 1;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (a === "--limit" && args[i + 1]) {
|
|
55
|
+
const n = parseInt(args[i + 1], 10);
|
|
56
|
+
if (Number.isNaN(n) || n < 1)
|
|
57
|
+
throw new Error("Invalid --limit");
|
|
58
|
+
limit = n;
|
|
59
|
+
i += 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (a === "--branch" && args[i + 1]) {
|
|
63
|
+
branch = args[i + 1];
|
|
64
|
+
i += 1;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (a === "--name-pattern" && args[i + 1]) {
|
|
68
|
+
namePattern = args[i + 1];
|
|
69
|
+
i += 1;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (a === "--sort" && args[i + 1]) {
|
|
73
|
+
const s = args[i + 1];
|
|
74
|
+
if (s !== "update_time" && s !== "name")
|
|
75
|
+
throw new Error("--sort must be update_time|name");
|
|
76
|
+
sort = s;
|
|
77
|
+
i += 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (a === "--direction" && args[i + 1]) {
|
|
81
|
+
const d = args[i + 1];
|
|
82
|
+
if (d !== "asc" && d !== "desc")
|
|
83
|
+
throw new Error("--direction must be asc|desc");
|
|
84
|
+
direction = d;
|
|
85
|
+
i += 1;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (a === "--offset" && args[i + 1]) {
|
|
89
|
+
offset = parseInt(args[i + 1], 10);
|
|
90
|
+
i += 1;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (a === "--tag" && args[i + 1]) {
|
|
94
|
+
tag = args[i + 1];
|
|
95
|
+
i += 1;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (a === "--group-id" && args[i + 1]) {
|
|
99
|
+
groupId = args[i + 1];
|
|
100
|
+
i += 1;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
pos.push(a);
|
|
104
|
+
}
|
|
105
|
+
if (!businessDomain)
|
|
106
|
+
businessDomain = resolveBusinessDomain();
|
|
107
|
+
const [knId] = pos;
|
|
108
|
+
if (!knId)
|
|
109
|
+
throw new Error("Usage: kweaver bkn metric list <kn-id> [options]");
|
|
110
|
+
return {
|
|
111
|
+
knId,
|
|
112
|
+
limit,
|
|
113
|
+
pretty,
|
|
114
|
+
businessDomain,
|
|
115
|
+
branch,
|
|
116
|
+
namePattern,
|
|
117
|
+
sort,
|
|
118
|
+
direction,
|
|
119
|
+
offset,
|
|
120
|
+
tag,
|
|
121
|
+
groupId,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function parseCommonKnFlags(rest, withYes) {
|
|
125
|
+
let pretty = true;
|
|
126
|
+
let businessDomain = "";
|
|
127
|
+
let branch;
|
|
128
|
+
let strictMode;
|
|
129
|
+
let importMode;
|
|
130
|
+
let fillNull;
|
|
131
|
+
let yes = false;
|
|
132
|
+
const out = [];
|
|
133
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
134
|
+
const a = rest[i];
|
|
135
|
+
if (a === "--help" || a === "-h")
|
|
136
|
+
throw new Error("help");
|
|
137
|
+
if (a === "--pretty") {
|
|
138
|
+
pretty = true;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (withYes && (a === "-y" || a === "--yes")) {
|
|
142
|
+
yes = true;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if ((a === "-bd" || a === "--biz-domain") && rest[i + 1]) {
|
|
146
|
+
businessDomain = rest[i + 1];
|
|
147
|
+
i += 1;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (a === "--branch" && rest[i + 1]) {
|
|
151
|
+
branch = rest[i + 1];
|
|
152
|
+
i += 1;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (a === "--strict-mode" && rest[i + 1]) {
|
|
156
|
+
strictMode = rest[i + 1] === "true" || rest[i + 1] === "1";
|
|
157
|
+
i += 1;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (a === "--import-mode" && rest[i + 1]) {
|
|
161
|
+
const m = rest[i + 1];
|
|
162
|
+
if (m !== "normal" && m !== "ignore" && m !== "overwrite") {
|
|
163
|
+
throw new Error("--import-mode must be normal|ignore|overwrite");
|
|
164
|
+
}
|
|
165
|
+
importMode = m;
|
|
166
|
+
i += 1;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (a === "--fill-null") {
|
|
170
|
+
fillNull = true;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
out.push(a);
|
|
174
|
+
}
|
|
175
|
+
if (!businessDomain)
|
|
176
|
+
businessDomain = resolveBusinessDomain();
|
|
177
|
+
return { filtered: out, pretty, businessDomain, branch, strictMode, importMode, fillNull, yes };
|
|
178
|
+
}
|
|
179
|
+
export async function runKnMetricCommand(args) {
|
|
180
|
+
const [action, ...rest] = args;
|
|
181
|
+
if (!action || action === "--help" || action === "-h") {
|
|
182
|
+
console.log(METRIC_HELP);
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
const token = await ensureValidToken();
|
|
187
|
+
const b = { baseUrl: token.baseUrl, accessToken: token.accessToken };
|
|
188
|
+
if (action === "list") {
|
|
189
|
+
const p = parseListArgs(rest);
|
|
190
|
+
const out = await listMetrics({
|
|
191
|
+
...b,
|
|
192
|
+
knId: p.knId,
|
|
193
|
+
businessDomain: p.businessDomain,
|
|
194
|
+
limit: p.limit,
|
|
195
|
+
branch: p.branch,
|
|
196
|
+
namePattern: p.namePattern,
|
|
197
|
+
sort: p.sort,
|
|
198
|
+
direction: p.direction,
|
|
199
|
+
offset: p.offset,
|
|
200
|
+
tag: p.tag,
|
|
201
|
+
groupId: p.groupId,
|
|
202
|
+
});
|
|
203
|
+
console.log(formatCallOutput(out, p.pretty));
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
if (action === "get") {
|
|
207
|
+
const o = parseCommonKnFlags(rest, false);
|
|
208
|
+
const [knId, metricIdArg] = o.filtered;
|
|
209
|
+
if (!knId || !metricIdArg) {
|
|
210
|
+
console.error("Usage: kweaver bkn metric get <kn-id> <metric-id(s)> [options]");
|
|
211
|
+
return 1;
|
|
212
|
+
}
|
|
213
|
+
const ids = parseCommaSeparatedIds(metricIdArg);
|
|
214
|
+
if (ids.length === 0) {
|
|
215
|
+
console.error("metric-id(s): need at least one id");
|
|
216
|
+
return 1;
|
|
217
|
+
}
|
|
218
|
+
const out = ids.length === 1
|
|
219
|
+
? await getMetric({ ...b, knId, businessDomain: o.businessDomain, metricId: ids[0], branch: o.branch })
|
|
220
|
+
: await getMetrics({ ...b, knId, businessDomain: o.businessDomain, metricIds: ids.join(","), branch: o.branch });
|
|
221
|
+
console.log(formatCallOutput(out, o.pretty));
|
|
222
|
+
return 0;
|
|
223
|
+
}
|
|
224
|
+
if (action === "create") {
|
|
225
|
+
const o = parseCommonKnFlags(rest, false);
|
|
226
|
+
const [knId, bodyJson] = o.filtered;
|
|
227
|
+
if (!knId || !bodyJson) {
|
|
228
|
+
console.error("Usage: kweaver bkn metric create <kn-id> '<json>' [options]");
|
|
229
|
+
return 1;
|
|
230
|
+
}
|
|
231
|
+
const out = await createMetrics({
|
|
232
|
+
...b,
|
|
233
|
+
knId,
|
|
234
|
+
businessDomain: o.businessDomain,
|
|
235
|
+
body: bodyJson,
|
|
236
|
+
branch: o.branch,
|
|
237
|
+
strictMode: o.strictMode,
|
|
238
|
+
});
|
|
239
|
+
console.log(formatCallOutput(out, o.pretty));
|
|
240
|
+
return 0;
|
|
241
|
+
}
|
|
242
|
+
if (action === "search") {
|
|
243
|
+
let limit;
|
|
244
|
+
let searchAfter;
|
|
245
|
+
const r = [];
|
|
246
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
247
|
+
const a = rest[i];
|
|
248
|
+
if (a === "--limit" && rest[i + 1]) {
|
|
249
|
+
limit = parseInt(rest[i + 1], 10);
|
|
250
|
+
if (Number.isNaN(limit) || limit < 1)
|
|
251
|
+
throw new Error("Invalid --limit");
|
|
252
|
+
i += 1;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (a === "--search-after" && rest[i + 1]) {
|
|
256
|
+
searchAfter = parseSearchAfterArray(rest[i + 1]);
|
|
257
|
+
i += 1;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
r.push(a);
|
|
261
|
+
}
|
|
262
|
+
const o = parseCommonKnFlags(r, false);
|
|
263
|
+
const [knId, bodyText] = o.filtered;
|
|
264
|
+
if (!knId || !bodyText) {
|
|
265
|
+
console.error("Usage: kweaver bkn metric search <kn-id> '<json>' [options]");
|
|
266
|
+
return 1;
|
|
267
|
+
}
|
|
268
|
+
const obj = parseJsonObject(bodyText, "search body must be a JSON object.");
|
|
269
|
+
if (limit !== undefined)
|
|
270
|
+
obj.limit = limit;
|
|
271
|
+
if (searchAfter !== undefined)
|
|
272
|
+
obj.search_after = searchAfter;
|
|
273
|
+
if (typeof obj.limit !== "number" || !Number.isFinite(obj.limit)) {
|
|
274
|
+
obj.limit = 50;
|
|
275
|
+
}
|
|
276
|
+
const out = await searchMetrics({
|
|
277
|
+
...b,
|
|
278
|
+
knId,
|
|
279
|
+
businessDomain: o.businessDomain,
|
|
280
|
+
body: JSON.stringify(obj),
|
|
281
|
+
branch: o.branch,
|
|
282
|
+
strictMode: o.strictMode,
|
|
283
|
+
});
|
|
284
|
+
console.log(formatCallOutput(out, o.pretty));
|
|
285
|
+
return 0;
|
|
286
|
+
}
|
|
287
|
+
if (action === "validate") {
|
|
288
|
+
const o = parseCommonKnFlags(rest, false);
|
|
289
|
+
const [knId, bodyJson] = o.filtered;
|
|
290
|
+
if (!knId || !bodyJson) {
|
|
291
|
+
console.error("Usage: kweaver bkn metric validate <kn-id> '<json>' [options]");
|
|
292
|
+
return 1;
|
|
293
|
+
}
|
|
294
|
+
const out = await validateMetrics({
|
|
295
|
+
...b,
|
|
296
|
+
knId,
|
|
297
|
+
businessDomain: o.businessDomain,
|
|
298
|
+
body: bodyJson,
|
|
299
|
+
branch: o.branch,
|
|
300
|
+
strictMode: o.strictMode,
|
|
301
|
+
importMode: o.importMode,
|
|
302
|
+
});
|
|
303
|
+
console.log(formatCallOutput(out, o.pretty));
|
|
304
|
+
return 0;
|
|
305
|
+
}
|
|
306
|
+
if (action === "update") {
|
|
307
|
+
const o = parseCommonKnFlags(rest, false);
|
|
308
|
+
const [knId, metricId, bodyJson] = o.filtered;
|
|
309
|
+
if (!knId || !metricId || !bodyJson) {
|
|
310
|
+
console.error("Usage: kweaver bkn metric update <kn-id> <metric-id> '<json>' [options]");
|
|
311
|
+
return 1;
|
|
312
|
+
}
|
|
313
|
+
const out = await updateMetric({
|
|
314
|
+
...b,
|
|
315
|
+
knId,
|
|
316
|
+
businessDomain: o.businessDomain,
|
|
317
|
+
metricId,
|
|
318
|
+
body: bodyJson,
|
|
319
|
+
branch: o.branch,
|
|
320
|
+
strictMode: o.strictMode,
|
|
321
|
+
});
|
|
322
|
+
console.log(formatCallOutput(out, o.pretty));
|
|
323
|
+
return 0;
|
|
324
|
+
}
|
|
325
|
+
if (action === "delete") {
|
|
326
|
+
const o = parseCommonKnFlags(rest, true);
|
|
327
|
+
const [knId, metricIdArg] = o.filtered;
|
|
328
|
+
if (!knId || !metricIdArg) {
|
|
329
|
+
console.error("Usage: kweaver bkn metric delete <kn-id> <metric-id(s)> [-y]");
|
|
330
|
+
return 1;
|
|
331
|
+
}
|
|
332
|
+
const ids = parseCommaSeparatedIds(metricIdArg);
|
|
333
|
+
if (ids.length === 0) {
|
|
334
|
+
console.error("metric-id(s): need at least one id");
|
|
335
|
+
return 1;
|
|
336
|
+
}
|
|
337
|
+
if (!o.yes) {
|
|
338
|
+
const label = ids.length === 1 ? ids[0] : ids.join(",");
|
|
339
|
+
const ok = await confirmYes(`Delete metric(s) ${label}?`);
|
|
340
|
+
if (!ok) {
|
|
341
|
+
console.log("Cancelled.");
|
|
342
|
+
return 0;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const out = ids.length === 1
|
|
346
|
+
? await deleteMetric({ ...b, knId, businessDomain: o.businessDomain, metricId: ids[0], branch: o.branch })
|
|
347
|
+
: await deleteMetrics({ ...b, knId, businessDomain: o.businessDomain, metricIds: ids.join(","), branch: o.branch });
|
|
348
|
+
console.log(formatCallOutput(out, o.pretty));
|
|
349
|
+
return 0;
|
|
350
|
+
}
|
|
351
|
+
if (action === "query") {
|
|
352
|
+
const o = parseCommonKnFlags(rest, false);
|
|
353
|
+
const { fillNull, branch, filtered, pretty, businessDomain } = o;
|
|
354
|
+
const [knId, metricId, bodyText = "{}"] = filtered;
|
|
355
|
+
if (!knId || !metricId) {
|
|
356
|
+
console.error("Usage: kweaver bkn metric query <kn-id> <metric-id> ['<json>'] [--branch] [--fill-null]");
|
|
357
|
+
return 1;
|
|
358
|
+
}
|
|
359
|
+
const body = parseJsonObject(bodyText, "metric query body must be a JSON object.");
|
|
360
|
+
if (typeof body.limit !== "number" || !Number.isFinite(body.limit)) {
|
|
361
|
+
body.limit = 50;
|
|
362
|
+
}
|
|
363
|
+
const out = await metricQueryData({
|
|
364
|
+
...b,
|
|
365
|
+
knId,
|
|
366
|
+
businessDomain,
|
|
367
|
+
metricId,
|
|
368
|
+
body: JSON.stringify(body),
|
|
369
|
+
branch,
|
|
370
|
+
fillNull,
|
|
371
|
+
});
|
|
372
|
+
console.log(formatCallOutput(out, pretty));
|
|
373
|
+
return 0;
|
|
374
|
+
}
|
|
375
|
+
if (action === "dry-run") {
|
|
376
|
+
const o = parseCommonKnFlags(rest, false);
|
|
377
|
+
const { fillNull, branch, filtered, pretty, businessDomain } = o;
|
|
378
|
+
const [knId, bodyText] = filtered;
|
|
379
|
+
if (!knId || !bodyText) {
|
|
380
|
+
console.error("Usage: kweaver bkn metric dry-run <kn-id> '<json>' [--branch] [--fill-null]");
|
|
381
|
+
return 1;
|
|
382
|
+
}
|
|
383
|
+
parseJsonObject(bodyText, "dry-run body must be a JSON object.");
|
|
384
|
+
const out = await metricDryRun({
|
|
385
|
+
...b,
|
|
386
|
+
knId,
|
|
387
|
+
businessDomain,
|
|
388
|
+
body: bodyText,
|
|
389
|
+
branch,
|
|
390
|
+
fillNull,
|
|
391
|
+
});
|
|
392
|
+
console.log(formatCallOutput(out, pretty));
|
|
393
|
+
return 0;
|
|
394
|
+
}
|
|
395
|
+
console.error(`Unknown bkn metric action: ${action}. Use --help.`);
|
|
396
|
+
return 1;
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
if (error instanceof Error && error.message === "help") {
|
|
400
|
+
console.log(METRIC_HELP);
|
|
401
|
+
return 0;
|
|
402
|
+
}
|
|
403
|
+
console.error(formatHttpError(error));
|
|
404
|
+
return 1;
|
|
405
|
+
}
|
|
406
|
+
}
|
package/dist/commands/bkn-ops.js
CHANGED
|
@@ -13,7 +13,7 @@ import { downloadBkn, uploadBkn, listActionSchedules, getActionSchedule, createA
|
|
|
13
13
|
import { formatCallOutput } from "./call.js";
|
|
14
14
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
15
15
|
import { runDsImportCsv } from "./ds.js";
|
|
16
|
-
import { pollWithBackoff,
|
|
16
|
+
import { pollWithBackoff, detectDisplayKey, formatPkDetectionError, parsePkMap, resolvePrimaryKey, confirmYes, } from "./bkn-utils.js";
|
|
17
17
|
// ── BKN object name validation ──────────────────────────────────────────────
|
|
18
18
|
// Mirrors bkn-backend OBJECT_NAME_MAX_LENGTH (interfaces/common.go:28) and
|
|
19
19
|
// validateObjectName (driveradapters/validate.go:85). 40 utf-8 codepoints,
|
|
@@ -644,19 +644,25 @@ export async function runKnCreateFromDsCommand(args, sampleRows) {
|
|
|
644
644
|
}
|
|
645
645
|
for (const t of targetTables) {
|
|
646
646
|
const override = options.pkMap[t.name];
|
|
647
|
-
if (override) {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
647
|
+
if (override && !t.columns.some((c) => c.name === override)) {
|
|
648
|
+
throw new Error(`--pk-map specifies '${override}' for table '${t.name}', but no such column. ` +
|
|
649
|
+
`Columns: ${t.columns.map((c) => c.name).join(", ")}`);
|
|
650
|
+
}
|
|
651
|
+
const resolution = resolvePrimaryKey(t, sampleRows?.[t.name], override);
|
|
652
|
+
if (resolution.pk) {
|
|
653
|
+
tablePks[t.name] = resolution.pk;
|
|
653
654
|
continue;
|
|
654
655
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
throw new Error(
|
|
656
|
+
if (resolution.source === "ambiguous") {
|
|
657
|
+
const cols = (resolution.ambiguous ?? []).join(", ");
|
|
658
|
+
throw new Error(`Table '${t.name}' has a composite PRIMARY KEY (${cols}). ` +
|
|
659
|
+
`BKN object types take a single primary key — pick one with --pk-map ${t.name}:<column>.`);
|
|
658
660
|
}
|
|
659
|
-
|
|
661
|
+
throw new Error(formatPkDetectionError(t.name, {
|
|
662
|
+
pk: null,
|
|
663
|
+
candidates: resolution.candidates ?? [],
|
|
664
|
+
sampleSize: resolution.sampleSize ?? 0,
|
|
665
|
+
}));
|
|
660
666
|
}
|
|
661
667
|
// Phase 1: Create DataViews for each table. findDataView is idempotent;
|
|
662
668
|
// not tracked for rollback so a retry can reuse what's already there.
|