@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
|
@@ -0,0 +1,1461 @@
|
|
|
1
|
+
import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
|
|
2
|
+
import { listConceptGroups, getConceptGroup, createConceptGroup, updateConceptGroup, deleteConceptGroup, addConceptGroupMembers, removeConceptGroupMembers, } from "../api/bkn-backend.js";
|
|
3
|
+
import { listObjectTypes, getObjectType, createObjectTypes, updateObjectType, deleteObjectTypes, listRelationTypes, getRelationType, createRelationTypes, updateRelationType, deleteRelationTypes, listActionTypes, getActionType, createActionTypes, updateActionType, deleteActionTypes, } from "../api/knowledge-networks.js";
|
|
4
|
+
import { objectTypeQuery, objectTypeProperties, actionTypeQuery, actionTypeExecute, actionExecutionGet, } from "../api/ontology-query.js";
|
|
5
|
+
import { getDataView } from "../api/dataviews.js";
|
|
6
|
+
import { formatCallOutput } from "./call.js";
|
|
7
|
+
import { resolveBusinessDomain } from "../config/store.js";
|
|
8
|
+
import { parseOntologyQueryFlags, parseJsonObject, parseSearchAfterArray, confirmYes, pollWithBackoff, } from "./bkn-utils.js";
|
|
9
|
+
const MAX_OUTPUT_BYTES = 100_000;
|
|
10
|
+
/**
|
|
11
|
+
* If a query response exceeds MAX_OUTPUT_BYTES, trim the datas array
|
|
12
|
+
* to fit, preserving valid JSON and the search_after cursor for pagination.
|
|
13
|
+
*/
|
|
14
|
+
function truncateQueryResult(raw) {
|
|
15
|
+
if (raw.length <= MAX_OUTPUT_BYTES) {
|
|
16
|
+
return raw;
|
|
17
|
+
}
|
|
18
|
+
let parsed;
|
|
19
|
+
try {
|
|
20
|
+
parsed = JSON.parse(raw);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return raw;
|
|
24
|
+
}
|
|
25
|
+
const datas = parsed.datas;
|
|
26
|
+
if (!Array.isArray(datas) || datas.length === 0) {
|
|
27
|
+
return raw;
|
|
28
|
+
}
|
|
29
|
+
const originalCount = datas.length;
|
|
30
|
+
while (datas.length > 1) {
|
|
31
|
+
datas.pop();
|
|
32
|
+
const candidate = JSON.stringify(parsed);
|
|
33
|
+
if (candidate.length <= MAX_OUTPUT_BYTES) {
|
|
34
|
+
const remaining = originalCount - datas.length;
|
|
35
|
+
const sa = parsed.search_after;
|
|
36
|
+
parsed._truncated = {
|
|
37
|
+
returned: datas.length,
|
|
38
|
+
total_fetched: originalCount,
|
|
39
|
+
remaining,
|
|
40
|
+
next_search_after: sa ?? null,
|
|
41
|
+
hint: sa
|
|
42
|
+
? `Pass --search-after '${JSON.stringify(sa)}' --limit ${datas.length} to fetch the next page.`
|
|
43
|
+
: `Reduce --limit to ${datas.length} or less to avoid truncation.`,
|
|
44
|
+
};
|
|
45
|
+
console.error(`[warn] Truncated ${originalCount} → ${datas.length} records (output exceeded ${Math.round(MAX_OUTPUT_BYTES / 1024)}KB). ${parsed._truncated.hint}`);
|
|
46
|
+
return JSON.stringify(parsed);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const sa = parsed.search_after;
|
|
50
|
+
parsed._truncated = {
|
|
51
|
+
returned: 1,
|
|
52
|
+
total_fetched: originalCount,
|
|
53
|
+
remaining: originalCount - 1,
|
|
54
|
+
next_search_after: sa ?? null,
|
|
55
|
+
hint: `Single record is very large. Use --limit 1 and --search-after to iterate.`,
|
|
56
|
+
};
|
|
57
|
+
console.error(`[warn] Truncated ${originalCount} → 1 record. Single record is very large. Use --limit 1 and --search-after to iterate.`);
|
|
58
|
+
return JSON.stringify(parsed);
|
|
59
|
+
}
|
|
60
|
+
export function parseKnObjectTypeQueryArgs(args) {
|
|
61
|
+
let pretty = true;
|
|
62
|
+
let businessDomain = "";
|
|
63
|
+
let limit;
|
|
64
|
+
let searchAfter;
|
|
65
|
+
const positionalArgs = [];
|
|
66
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
67
|
+
const arg = args[i];
|
|
68
|
+
if (arg === "--help" || arg === "-h") {
|
|
69
|
+
throw new Error("help");
|
|
70
|
+
}
|
|
71
|
+
if (arg === "--pretty") {
|
|
72
|
+
pretty = true;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (arg === "-bd" || arg === "--biz-domain") {
|
|
76
|
+
businessDomain = args[i + 1] ?? "bd_public";
|
|
77
|
+
if (!businessDomain || businessDomain.startsWith("-")) {
|
|
78
|
+
throw new Error("Missing value for biz-domain flag");
|
|
79
|
+
}
|
|
80
|
+
i += 1;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (arg === "--limit") {
|
|
84
|
+
const rawLimit = args[i + 1];
|
|
85
|
+
const parsedLimit = parseInt(rawLimit ?? "", 10);
|
|
86
|
+
if (!rawLimit || rawLimit.startsWith("-") || Number.isNaN(parsedLimit) || parsedLimit < 1) {
|
|
87
|
+
throw new Error("Invalid value for --limit. Expected a positive integer.");
|
|
88
|
+
}
|
|
89
|
+
limit = parsedLimit;
|
|
90
|
+
i += 1;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (arg === "--search-after") {
|
|
94
|
+
const rawSearchAfter = args[i + 1];
|
|
95
|
+
if (!rawSearchAfter) {
|
|
96
|
+
throw new Error("Missing value for --search-after. Expected a JSON array string.");
|
|
97
|
+
}
|
|
98
|
+
searchAfter = parseSearchAfterArray(rawSearchAfter);
|
|
99
|
+
i += 1;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
positionalArgs.push(arg);
|
|
103
|
+
}
|
|
104
|
+
const [knId, otId, bodyText = "{}"] = positionalArgs;
|
|
105
|
+
if (!knId || !otId) {
|
|
106
|
+
throw new Error("Usage: kweaver bkn object-type query <kn-id> <ot-id> ['<json>'] [--limit <n>] [--search-after '<json-array>'] [--pretty] [-bd value]");
|
|
107
|
+
}
|
|
108
|
+
if (positionalArgs.length > 3) {
|
|
109
|
+
throw new Error("Usage: kweaver bkn object-type query <kn-id> <ot-id> ['<json>'] [--limit <n>] [--search-after '<json-array>'] [--pretty] [-bd value]");
|
|
110
|
+
}
|
|
111
|
+
const body = parseJsonObject(bodyText, "object-type query body must be a JSON object.");
|
|
112
|
+
if (limit !== undefined) {
|
|
113
|
+
body.limit = limit;
|
|
114
|
+
}
|
|
115
|
+
if (searchAfter !== undefined) {
|
|
116
|
+
body.search_after = searchAfter;
|
|
117
|
+
}
|
|
118
|
+
if (typeof body.limit !== "number" || !Number.isFinite(body.limit) || body.limit < 1) {
|
|
119
|
+
body.limit = 50;
|
|
120
|
+
}
|
|
121
|
+
if (!businessDomain)
|
|
122
|
+
businessDomain = resolveBusinessDomain();
|
|
123
|
+
return {
|
|
124
|
+
knId,
|
|
125
|
+
otId,
|
|
126
|
+
body: JSON.stringify(body),
|
|
127
|
+
pretty,
|
|
128
|
+
businessDomain,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// ── Object-type create/update/delete ───────────────────────────────────────────
|
|
132
|
+
/** Map database / dataview field types to ADP-accepted types (aligned with Python SDK). */
|
|
133
|
+
const ADP_FIELD_TYPE_MAP = {
|
|
134
|
+
varchar: "string",
|
|
135
|
+
char: "string",
|
|
136
|
+
nvarchar: "string",
|
|
137
|
+
longtext: "text",
|
|
138
|
+
mediumtext: "text",
|
|
139
|
+
tinytext: "text",
|
|
140
|
+
bigint: "integer",
|
|
141
|
+
int: "integer",
|
|
142
|
+
smallint: "integer",
|
|
143
|
+
tinyint: "integer",
|
|
144
|
+
double: "float",
|
|
145
|
+
real: "float",
|
|
146
|
+
numeric: "decimal",
|
|
147
|
+
number: "decimal",
|
|
148
|
+
blob: "binary",
|
|
149
|
+
longblob: "binary",
|
|
150
|
+
bit: "boolean",
|
|
151
|
+
bool: "boolean",
|
|
152
|
+
};
|
|
153
|
+
export function normalizeAdpFieldType(raw) {
|
|
154
|
+
if (!raw)
|
|
155
|
+
return "string";
|
|
156
|
+
const lower = raw.toLowerCase().trim();
|
|
157
|
+
return ADP_FIELD_TYPE_MAP[lower] ?? lower;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Ensure each data_property has mapped_field (same-name mapping) for build engine compatibility.
|
|
161
|
+
*/
|
|
162
|
+
export function ensureMappedFieldOnDataProperty(prop) {
|
|
163
|
+
const name = String(prop.name ?? "");
|
|
164
|
+
const ptype = normalizeAdpFieldType(prop.type != null ? String(prop.type) : undefined);
|
|
165
|
+
const display = String(prop.display_name ?? name);
|
|
166
|
+
const existing = prop.mapped_field;
|
|
167
|
+
if (existing && typeof existing === "object" && !Array.isArray(existing)) {
|
|
168
|
+
const mf = existing;
|
|
169
|
+
const mfName = String(mf.name ?? name);
|
|
170
|
+
const mfType = normalizeAdpFieldType(mf.type != null ? String(mf.type) : undefined) || ptype;
|
|
171
|
+
const mfDisplay = String(mf.display_name ?? display);
|
|
172
|
+
return {
|
|
173
|
+
...prop,
|
|
174
|
+
type: ptype,
|
|
175
|
+
mapped_field: { name: mfName, type: mfType, display_name: mfDisplay },
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
...prop,
|
|
180
|
+
type: ptype,
|
|
181
|
+
mapped_field: { name, type: ptype, display_name: display },
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function dataPropertiesFromViewFields(fields) {
|
|
185
|
+
return fields.map((f) => {
|
|
186
|
+
const t = normalizeAdpFieldType(f.type);
|
|
187
|
+
const display = f.display_name?.trim() || f.name;
|
|
188
|
+
return {
|
|
189
|
+
name: f.name,
|
|
190
|
+
display_name: display,
|
|
191
|
+
type: t,
|
|
192
|
+
mapped_field: { name: f.name, type: t, display_name: display },
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
function fallbackDataPropertiesFromKeys(primaryKeys, displayKey) {
|
|
197
|
+
const names = [...new Set([...primaryKeys, displayKey])];
|
|
198
|
+
return names.map((n) => {
|
|
199
|
+
const t = "string";
|
|
200
|
+
return {
|
|
201
|
+
name: n,
|
|
202
|
+
display_name: n,
|
|
203
|
+
type: t,
|
|
204
|
+
mapped_field: { name: n, type: t, display_name: n },
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/** Parse object-type create args: --name --dataview-id --primary-key --display-key [--property '<json>' ...] */
|
|
209
|
+
export function parseObjectTypeCreateArgs(args) {
|
|
210
|
+
let name = "";
|
|
211
|
+
let dataviewId = "";
|
|
212
|
+
let primaryKey = "";
|
|
213
|
+
let displayKey = "";
|
|
214
|
+
let businessDomain = "";
|
|
215
|
+
let branch = "main";
|
|
216
|
+
let pretty = true;
|
|
217
|
+
const properties = [];
|
|
218
|
+
const positional = [];
|
|
219
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
220
|
+
const arg = args[i];
|
|
221
|
+
if (arg === "--help" || arg === "-h")
|
|
222
|
+
throw new Error("help");
|
|
223
|
+
if (arg === "--name" && args[i + 1]) {
|
|
224
|
+
name = args[++i];
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (arg === "--dataview-id" && args[i + 1]) {
|
|
228
|
+
dataviewId = args[++i];
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (arg === "--primary-key" && args[i + 1]) {
|
|
232
|
+
primaryKey = args[++i];
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (arg === "--display-key" && args[i + 1]) {
|
|
236
|
+
displayKey = args[++i];
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (arg === "--property" && args[i + 1]) {
|
|
240
|
+
properties.push(args[++i]);
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
244
|
+
businessDomain = args[++i];
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (arg === "--branch" && args[i + 1]) {
|
|
248
|
+
branch = args[++i];
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (arg === "--pretty") {
|
|
252
|
+
pretty = true;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (!arg.startsWith("-"))
|
|
256
|
+
positional.push(arg);
|
|
257
|
+
}
|
|
258
|
+
const knId = positional[0];
|
|
259
|
+
if (!knId || !name || !dataviewId || !primaryKey || !displayKey) {
|
|
260
|
+
throw new Error("Usage: kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W");
|
|
261
|
+
}
|
|
262
|
+
const entry = {
|
|
263
|
+
branch,
|
|
264
|
+
name,
|
|
265
|
+
data_source: { type: "data_view", id: dataviewId },
|
|
266
|
+
primary_keys: [primaryKey],
|
|
267
|
+
display_key: displayKey,
|
|
268
|
+
};
|
|
269
|
+
if (properties.length > 0) {
|
|
270
|
+
const raw = properties.map((p) => JSON.parse(p));
|
|
271
|
+
entry.data_properties = raw.map((row) => ensureMappedFieldOnDataProperty(row));
|
|
272
|
+
const body = JSON.stringify({ entries: [entry] });
|
|
273
|
+
if (!businessDomain)
|
|
274
|
+
businessDomain = resolveBusinessDomain();
|
|
275
|
+
return { mode: "complete", knId, body, businessDomain, branch, pretty };
|
|
276
|
+
}
|
|
277
|
+
if (!businessDomain)
|
|
278
|
+
businessDomain = resolveBusinessDomain();
|
|
279
|
+
return {
|
|
280
|
+
mode: "needsDataview",
|
|
281
|
+
knId,
|
|
282
|
+
dataviewId,
|
|
283
|
+
entry,
|
|
284
|
+
businessDomain,
|
|
285
|
+
branch,
|
|
286
|
+
pretty,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Load dataview fields and build data_properties (with mapped_field). Used when no --property flags.
|
|
291
|
+
*/
|
|
292
|
+
export async function finalizeObjectTypeCreateFromDataview(options) {
|
|
293
|
+
const { baseUrl, accessToken, dataviewId, entry, businessDomain } = options;
|
|
294
|
+
const dv = await getDataView({
|
|
295
|
+
baseUrl,
|
|
296
|
+
accessToken,
|
|
297
|
+
id: dataviewId,
|
|
298
|
+
businessDomain,
|
|
299
|
+
});
|
|
300
|
+
const fields = dv.fields ?? [];
|
|
301
|
+
const primaryKeys = Array.isArray(entry.primary_keys)
|
|
302
|
+
? entry.primary_keys
|
|
303
|
+
: [];
|
|
304
|
+
const displayKey = String(entry.display_key ?? "");
|
|
305
|
+
const next = { ...entry };
|
|
306
|
+
next.data_properties =
|
|
307
|
+
fields.length > 0
|
|
308
|
+
? dataPropertiesFromViewFields(fields)
|
|
309
|
+
: fallbackDataPropertiesFromKeys(primaryKeys, displayKey);
|
|
310
|
+
return JSON.stringify({ entries: [next] });
|
|
311
|
+
}
|
|
312
|
+
const OBJECT_TYPE_PUT_STRIP_KEYS = new Set([
|
|
313
|
+
"status",
|
|
314
|
+
"creator",
|
|
315
|
+
"updater",
|
|
316
|
+
"create_time",
|
|
317
|
+
"update_time",
|
|
318
|
+
"module_type",
|
|
319
|
+
"kn_id",
|
|
320
|
+
]);
|
|
321
|
+
/** Prepare a GET response entry for PUT (drop read-only fields). */
|
|
322
|
+
export function stripObjectTypeForPut(entry) {
|
|
323
|
+
const out = { ...entry };
|
|
324
|
+
for (const k of OBJECT_TYPE_PUT_STRIP_KEYS) {
|
|
325
|
+
delete out[k];
|
|
326
|
+
}
|
|
327
|
+
return out;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Apply merge flags onto a stripped object-type object (mutates copy).
|
|
331
|
+
* - Add: property `name` not in list → append.
|
|
332
|
+
* - Update: property `name` exists → replace entry (same as add; CLI also accepts `--update-property`).
|
|
333
|
+
* - Delete: `--remove-property` removes by `name` before adds are applied.
|
|
334
|
+
*/
|
|
335
|
+
export function applyObjectTypeMerge(target, merge) {
|
|
336
|
+
if (merge.name !== undefined)
|
|
337
|
+
target.name = merge.name;
|
|
338
|
+
if (merge.displayKey !== undefined)
|
|
339
|
+
target.display_key = merge.displayKey;
|
|
340
|
+
if (merge.comment !== undefined)
|
|
341
|
+
target.comment = merge.comment;
|
|
342
|
+
if (merge.icon !== undefined)
|
|
343
|
+
target.icon = merge.icon;
|
|
344
|
+
if (merge.color !== undefined)
|
|
345
|
+
target.color = merge.color;
|
|
346
|
+
if (merge.tags !== undefined)
|
|
347
|
+
target.tags = merge.tags;
|
|
348
|
+
let props = target.data_properties;
|
|
349
|
+
if (!Array.isArray(props)) {
|
|
350
|
+
props = [];
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
props = props.map((p) => p && typeof p === "object" && !Array.isArray(p) ? { ...p } : p);
|
|
354
|
+
}
|
|
355
|
+
const list = props;
|
|
356
|
+
for (const rm of merge.removeProperties) {
|
|
357
|
+
for (let j = list.length - 1; j >= 0; j -= 1) {
|
|
358
|
+
const n = list[j]?.name;
|
|
359
|
+
if (typeof n === "string" && n === rm)
|
|
360
|
+
list.splice(j, 1);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
for (const add of merge.addProperties) {
|
|
364
|
+
const nm = add.name;
|
|
365
|
+
if (typeof nm !== "string" || !nm) {
|
|
366
|
+
throw new Error("--add-property / --update-property JSON must include a non-empty string \"name\" field.");
|
|
367
|
+
}
|
|
368
|
+
const idx = list.findIndex((p) => p?.name === nm);
|
|
369
|
+
if (idx >= 0)
|
|
370
|
+
list[idx] = add;
|
|
371
|
+
else
|
|
372
|
+
list.push(add);
|
|
373
|
+
}
|
|
374
|
+
target.data_properties = list;
|
|
375
|
+
return target;
|
|
376
|
+
}
|
|
377
|
+
/** Parse object-type update: raw JSON body OR merge flags (GET-merge-PUT). */
|
|
378
|
+
export function parseObjectTypeUpdateArgs(args) {
|
|
379
|
+
let name;
|
|
380
|
+
let displayKey;
|
|
381
|
+
let businessDomain = "";
|
|
382
|
+
let pretty = true;
|
|
383
|
+
let branch = "main";
|
|
384
|
+
let comment;
|
|
385
|
+
let icon;
|
|
386
|
+
let color;
|
|
387
|
+
let tagsJson;
|
|
388
|
+
const addProperties = [];
|
|
389
|
+
const removeProperties = [];
|
|
390
|
+
const positional = [];
|
|
391
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
392
|
+
const arg = args[i];
|
|
393
|
+
if (arg === "--help" || arg === "-h")
|
|
394
|
+
throw new Error("help");
|
|
395
|
+
if (arg === "--name" && args[i + 1]) {
|
|
396
|
+
name = args[++i];
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
if (arg === "--display-key" && args[i + 1]) {
|
|
400
|
+
displayKey = args[++i];
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
if ((arg === "--add-property" || arg === "--update-property") && args[i + 1]) {
|
|
404
|
+
const raw = args[++i];
|
|
405
|
+
addProperties.push(parseJsonObject(raw, `--add-property / --update-property must be valid JSON object: ${raw}`));
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
if (arg === "--remove-property" && args[i + 1]) {
|
|
409
|
+
removeProperties.push(args[++i]);
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
if (arg === "--tags" && args[i + 1]) {
|
|
413
|
+
tagsJson = args[++i];
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (arg === "--comment" && args[i + 1]) {
|
|
417
|
+
comment = args[++i];
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (arg === "--icon" && args[i + 1]) {
|
|
421
|
+
icon = args[++i];
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
if (arg === "--color" && args[i + 1]) {
|
|
425
|
+
color = args[++i];
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
if (arg === "--branch" && args[i + 1]) {
|
|
429
|
+
branch = args[++i];
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
433
|
+
businessDomain = args[++i];
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
if (arg === "--pretty") {
|
|
437
|
+
pretty = true;
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
if (!arg.startsWith("-"))
|
|
441
|
+
positional.push(arg);
|
|
442
|
+
}
|
|
443
|
+
const [knId, otId, maybeBody] = positional;
|
|
444
|
+
if (!knId || !otId) {
|
|
445
|
+
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> ...]");
|
|
446
|
+
}
|
|
447
|
+
const hasMergeFlags = name !== undefined ||
|
|
448
|
+
displayKey !== undefined ||
|
|
449
|
+
addProperties.length > 0 ||
|
|
450
|
+
removeProperties.length > 0 ||
|
|
451
|
+
tagsJson !== undefined ||
|
|
452
|
+
comment !== undefined ||
|
|
453
|
+
icon !== undefined ||
|
|
454
|
+
color !== undefined;
|
|
455
|
+
if (maybeBody !== undefined && maybeBody.trim().startsWith("{")) {
|
|
456
|
+
if (hasMergeFlags) {
|
|
457
|
+
throw new Error("Do not combine a raw JSON body with --name/--add-property/--update-property/--remove-property and other merge flags.");
|
|
458
|
+
}
|
|
459
|
+
if (!businessDomain)
|
|
460
|
+
businessDomain = resolveBusinessDomain();
|
|
461
|
+
return {
|
|
462
|
+
mode: "body",
|
|
463
|
+
knId,
|
|
464
|
+
otId,
|
|
465
|
+
body: maybeBody.trim(),
|
|
466
|
+
businessDomain,
|
|
467
|
+
pretty,
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
if (maybeBody !== undefined) {
|
|
471
|
+
throw new Error(`Unexpected third argument "${maybeBody}". For raw PUT body, pass a single JSON object starting with "{".`);
|
|
472
|
+
}
|
|
473
|
+
let tags;
|
|
474
|
+
if (tagsJson !== undefined) {
|
|
475
|
+
try {
|
|
476
|
+
const t = JSON.parse(tagsJson);
|
|
477
|
+
if (!Array.isArray(t) || !t.every((x) => typeof x === "string")) {
|
|
478
|
+
throw new Error("invalid");
|
|
479
|
+
}
|
|
480
|
+
tags = t;
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
throw new Error(`--tags must be a JSON array of strings, e.g. '["足球","球员"]'`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
const merge = {
|
|
487
|
+
addProperties,
|
|
488
|
+
removeProperties,
|
|
489
|
+
...(name !== undefined ? { name } : {}),
|
|
490
|
+
...(displayKey !== undefined ? { displayKey } : {}),
|
|
491
|
+
...(tags !== undefined ? { tags } : {}),
|
|
492
|
+
...(comment !== undefined ? { comment } : {}),
|
|
493
|
+
...(icon !== undefined ? { icon } : {}),
|
|
494
|
+
...(color !== undefined ? { color } : {}),
|
|
495
|
+
};
|
|
496
|
+
if (merge.name === undefined &&
|
|
497
|
+
merge.displayKey === undefined &&
|
|
498
|
+
merge.addProperties.length === 0 &&
|
|
499
|
+
merge.removeProperties.length === 0 &&
|
|
500
|
+
merge.tags === undefined &&
|
|
501
|
+
merge.comment === undefined &&
|
|
502
|
+
merge.icon === undefined &&
|
|
503
|
+
merge.color === undefined) {
|
|
504
|
+
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.");
|
|
505
|
+
}
|
|
506
|
+
if (!businessDomain)
|
|
507
|
+
businessDomain = resolveBusinessDomain();
|
|
508
|
+
return { mode: "merge", knId, otId, merge, businessDomain, pretty, branch };
|
|
509
|
+
}
|
|
510
|
+
/** Parse object-type delete args: <kn-id> <ot-ids> [-y] */
|
|
511
|
+
export function parseObjectTypeDeleteArgs(args) {
|
|
512
|
+
let businessDomain = "";
|
|
513
|
+
let yes = false;
|
|
514
|
+
const positional = [];
|
|
515
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
516
|
+
const arg = args[i];
|
|
517
|
+
if (arg === "--help" || arg === "-h")
|
|
518
|
+
throw new Error("help");
|
|
519
|
+
if (arg === "--yes" || arg === "-y") {
|
|
520
|
+
yes = true;
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
524
|
+
businessDomain = args[++i];
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
if (!arg.startsWith("-"))
|
|
528
|
+
positional.push(arg);
|
|
529
|
+
}
|
|
530
|
+
const [knId, otIds] = positional;
|
|
531
|
+
if (!knId || !otIds) {
|
|
532
|
+
throw new Error("Usage: kweaver bkn object-type delete <kn-id> <ot-ids> [-y]");
|
|
533
|
+
}
|
|
534
|
+
if (!businessDomain)
|
|
535
|
+
businessDomain = resolveBusinessDomain();
|
|
536
|
+
return { knId, otIds, businessDomain, yes };
|
|
537
|
+
}
|
|
538
|
+
export function parseKnActionTypeExecuteArgs(args) {
|
|
539
|
+
let pretty = true;
|
|
540
|
+
let businessDomain = "";
|
|
541
|
+
let wait = true;
|
|
542
|
+
let timeout = 300;
|
|
543
|
+
const positional = [];
|
|
544
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
545
|
+
const arg = args[i];
|
|
546
|
+
if (arg === "--help" || arg === "-h") {
|
|
547
|
+
throw new Error("help");
|
|
548
|
+
}
|
|
549
|
+
if (arg === "--pretty") {
|
|
550
|
+
pretty = true;
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
554
|
+
businessDomain = args[i + 1];
|
|
555
|
+
i += 1;
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
if (arg === "--wait") {
|
|
559
|
+
wait = true;
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
if (arg === "--no-wait") {
|
|
563
|
+
wait = false;
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
if (arg === "--timeout" && args[i + 1]) {
|
|
567
|
+
timeout = parseInt(args[i + 1], 10);
|
|
568
|
+
if (Number.isNaN(timeout) || timeout < 1)
|
|
569
|
+
timeout = 300;
|
|
570
|
+
i += 1;
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
positional.push(arg);
|
|
574
|
+
}
|
|
575
|
+
const [knId, atId, body] = positional;
|
|
576
|
+
if (!knId || !atId || !body) {
|
|
577
|
+
throw new Error("Missing kn-id, at-id, or body. Usage: kweaver bkn action-type execute <kn-id> <at-id> '<json>' [options]");
|
|
578
|
+
}
|
|
579
|
+
if (!businessDomain)
|
|
580
|
+
businessDomain = resolveBusinessDomain();
|
|
581
|
+
return {
|
|
582
|
+
knId,
|
|
583
|
+
atId,
|
|
584
|
+
body,
|
|
585
|
+
pretty,
|
|
586
|
+
businessDomain,
|
|
587
|
+
wait,
|
|
588
|
+
timeout,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
// ── Action-type execute helpers ────────────────────────────────────────────────
|
|
592
|
+
const TERMINAL_STATUSES = ["SUCCESS", "FAILED", "CANCELLED"];
|
|
593
|
+
function extractExecutionId(body) {
|
|
594
|
+
try {
|
|
595
|
+
const data = JSON.parse(body);
|
|
596
|
+
const id = data.execution_id ?? data.id;
|
|
597
|
+
return typeof id === "string" ? id : null;
|
|
598
|
+
}
|
|
599
|
+
catch {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function extractStatus(body) {
|
|
604
|
+
try {
|
|
605
|
+
const data = JSON.parse(body);
|
|
606
|
+
const status = data.status;
|
|
607
|
+
return typeof status === "string" ? status : "";
|
|
608
|
+
}
|
|
609
|
+
catch {
|
|
610
|
+
return "";
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
// ── Relation-type create/update/delete ─────────────────────────────────────────
|
|
614
|
+
/** Parse relation-type create args: --name --source --target [--mapping src:tgt ...] */
|
|
615
|
+
export function parseRelationTypeCreateArgs(args) {
|
|
616
|
+
let name = "";
|
|
617
|
+
let source = "";
|
|
618
|
+
let target = "";
|
|
619
|
+
let businessDomain = "";
|
|
620
|
+
let branch = "main";
|
|
621
|
+
let pretty = true;
|
|
622
|
+
const mappings = [];
|
|
623
|
+
const positional = [];
|
|
624
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
625
|
+
const arg = args[i];
|
|
626
|
+
if (arg === "--help" || arg === "-h")
|
|
627
|
+
throw new Error("help");
|
|
628
|
+
if (arg === "--name" && args[i + 1]) {
|
|
629
|
+
name = args[++i];
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
if (arg === "--source" && args[i + 1]) {
|
|
633
|
+
source = args[++i];
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
if (arg === "--target" && args[i + 1]) {
|
|
637
|
+
target = args[++i];
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
if (arg === "--mapping" && args[i + 1]) {
|
|
641
|
+
const m = args[++i];
|
|
642
|
+
if (!m.includes(":")) {
|
|
643
|
+
throw new Error(`Invalid mapping format '${m}'. Expected source_prop:target_prop.`);
|
|
644
|
+
}
|
|
645
|
+
const [s, t] = m.split(":", 2);
|
|
646
|
+
mappings.push([s, t]);
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
650
|
+
businessDomain = args[++i];
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
if (arg === "--branch" && args[i + 1]) {
|
|
654
|
+
branch = args[++i];
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
if (arg === "--pretty") {
|
|
658
|
+
pretty = true;
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if (!arg.startsWith("-"))
|
|
662
|
+
positional.push(arg);
|
|
663
|
+
}
|
|
664
|
+
const knId = positional[0];
|
|
665
|
+
if (!knId || !name || !source || !target) {
|
|
666
|
+
throw new Error("Usage: kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]");
|
|
667
|
+
}
|
|
668
|
+
const entry = {
|
|
669
|
+
branch,
|
|
670
|
+
name,
|
|
671
|
+
source_object_type_id: source,
|
|
672
|
+
target_object_type_id: target,
|
|
673
|
+
type: "direct",
|
|
674
|
+
mapping_rules: mappings.map(([s, t]) => ({
|
|
675
|
+
source_property: { name: s },
|
|
676
|
+
target_property: { name: t },
|
|
677
|
+
})),
|
|
678
|
+
};
|
|
679
|
+
const body = JSON.stringify({ entries: [entry] });
|
|
680
|
+
if (!businessDomain)
|
|
681
|
+
businessDomain = resolveBusinessDomain();
|
|
682
|
+
return { knId, body, businessDomain, branch, pretty };
|
|
683
|
+
}
|
|
684
|
+
/** Parse relation-type update args: --source and --target are required by the API */
|
|
685
|
+
export function parseRelationTypeUpdateArgs(args) {
|
|
686
|
+
let name;
|
|
687
|
+
let source;
|
|
688
|
+
let target;
|
|
689
|
+
let type;
|
|
690
|
+
const mappings = [];
|
|
691
|
+
let businessDomain = "";
|
|
692
|
+
let pretty = true;
|
|
693
|
+
const positional = [];
|
|
694
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
695
|
+
const arg = args[i];
|
|
696
|
+
if (arg === "--help" || arg === "-h")
|
|
697
|
+
throw new Error("help");
|
|
698
|
+
if (arg === "--name" && args[i + 1]) {
|
|
699
|
+
name = args[++i];
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
if (arg === "--source" && args[i + 1]) {
|
|
703
|
+
source = args[++i];
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
if (arg === "--target" && args[i + 1]) {
|
|
707
|
+
target = args[++i];
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
if (arg === "--type" && args[i + 1]) {
|
|
711
|
+
type = args[++i];
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
if (arg === "--mapping" && args[i + 1]) {
|
|
715
|
+
const m = args[++i];
|
|
716
|
+
if (!m.includes(":")) {
|
|
717
|
+
throw new Error(`Invalid mapping format '${m}'. Expected source_prop:target_prop.`);
|
|
718
|
+
}
|
|
719
|
+
const [s, t] = m.split(":", 2);
|
|
720
|
+
mappings.push([s, t]);
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
724
|
+
businessDomain = args[++i];
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
if (arg === "--pretty") {
|
|
728
|
+
pretty = true;
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
if (!arg.startsWith("-"))
|
|
732
|
+
positional.push(arg);
|
|
733
|
+
}
|
|
734
|
+
const [knId, rtId] = positional;
|
|
735
|
+
if (!knId || !rtId) {
|
|
736
|
+
throw new Error("Usage: kweaver bkn relation-type update <kn-id> <rt-id> --source <ot-id> --target <ot-id> [--name X] [--type direct|data_view] [--mapping src:tgt ...] [--type direct|data_view] [--mapping src:tgt ...]");
|
|
737
|
+
}
|
|
738
|
+
if (!source || !target) {
|
|
739
|
+
throw new Error("--source and --target are required for relation-type update (API requires source_object_type_id and target_object_type_id).");
|
|
740
|
+
}
|
|
741
|
+
const body = {
|
|
742
|
+
source_object_type_id: source,
|
|
743
|
+
target_object_type_id: target,
|
|
744
|
+
type: type || "direct",
|
|
745
|
+
mapping_rules: mappings.map(([s, t]) => ({
|
|
746
|
+
source_property: { name: s },
|
|
747
|
+
target_property: { name: t },
|
|
748
|
+
})),
|
|
749
|
+
};
|
|
750
|
+
if (name !== undefined)
|
|
751
|
+
body.name = name;
|
|
752
|
+
if (!businessDomain)
|
|
753
|
+
businessDomain = resolveBusinessDomain();
|
|
754
|
+
return { knId, rtId, body: JSON.stringify(body), businessDomain, pretty };
|
|
755
|
+
}
|
|
756
|
+
/** Parse relation-type delete args: <kn-id> <rt-ids> [-y] */
|
|
757
|
+
export function parseRelationTypeDeleteArgs(args) {
|
|
758
|
+
let businessDomain = "";
|
|
759
|
+
let yes = false;
|
|
760
|
+
const positional = [];
|
|
761
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
762
|
+
const arg = args[i];
|
|
763
|
+
if (arg === "--help" || arg === "-h")
|
|
764
|
+
throw new Error("help");
|
|
765
|
+
if (arg === "--yes" || arg === "-y") {
|
|
766
|
+
yes = true;
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
769
|
+
if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
|
|
770
|
+
businessDomain = args[++i];
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
if (!arg.startsWith("-"))
|
|
774
|
+
positional.push(arg);
|
|
775
|
+
}
|
|
776
|
+
const [knId, rtIds] = positional;
|
|
777
|
+
if (!knId || !rtIds) {
|
|
778
|
+
throw new Error("Usage: kweaver bkn relation-type delete <kn-id> <rt-ids> [-y]");
|
|
779
|
+
}
|
|
780
|
+
if (!businessDomain)
|
|
781
|
+
businessDomain = resolveBusinessDomain();
|
|
782
|
+
return { knId, rtIds, businessDomain, yes };
|
|
783
|
+
}
|
|
784
|
+
// ── Command handlers ───────────────────────────────────────────────────────────
|
|
785
|
+
export async function runKnObjectTypeCommand(args) {
|
|
786
|
+
const [action, ...rest] = args;
|
|
787
|
+
if (!action || action === "--help" || action === "-h") {
|
|
788
|
+
console.log(`kweaver bkn object-type list <kn-id> [--pretty] [-bd value]
|
|
789
|
+
kweaver bkn object-type get <kn-id> <ot-id> [--pretty] [-bd value]
|
|
790
|
+
kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W [--property '<json>' ...]
|
|
791
|
+
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]
|
|
792
|
+
kweaver bkn object-type update <kn-id> <ot-id> '<full-json-body>'
|
|
793
|
+
kweaver bkn object-type delete <kn-id> <ot-ids> [-y]
|
|
794
|
+
kweaver bkn object-type query <kn-id> <ot-id> ['<json>'] [--limit <n>] [--search-after '<json-array>'] [--pretty] [-bd value]
|
|
795
|
+
kweaver bkn object-type properties <kn-id> <ot-id> '<json>' [--pretty] [-bd value]
|
|
796
|
+
|
|
797
|
+
list: List object types (schema) from ontology-manager.
|
|
798
|
+
get: Get single object type details.
|
|
799
|
+
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.
|
|
800
|
+
query: Query via ontology-query API. Default limit is 50 if not specified. Use --search-after for pagination.
|
|
801
|
+
properties: Query instance properties by primary key.
|
|
802
|
+
|
|
803
|
+
properties JSON format: {"_instance_identities":[{"<primary-key>":"<value>"}],"properties":["prop1","prop2"]}`);
|
|
804
|
+
return 0;
|
|
805
|
+
}
|
|
806
|
+
try {
|
|
807
|
+
if (action === "get") {
|
|
808
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
809
|
+
const [knId, otId] = parsed.filteredArgs;
|
|
810
|
+
if (!knId || !otId) {
|
|
811
|
+
console.error("Usage: kweaver bkn object-type get <kn-id> <ot-id> [options]");
|
|
812
|
+
return 1;
|
|
813
|
+
}
|
|
814
|
+
const token = await ensureValidToken();
|
|
815
|
+
const body = await getObjectType({
|
|
816
|
+
baseUrl: token.baseUrl,
|
|
817
|
+
accessToken: token.accessToken,
|
|
818
|
+
knId,
|
|
819
|
+
otId,
|
|
820
|
+
businessDomain: parsed.businessDomain,
|
|
821
|
+
});
|
|
822
|
+
console.log(formatCallOutput(body, parsed.pretty));
|
|
823
|
+
return 0;
|
|
824
|
+
}
|
|
825
|
+
if (action === "create") {
|
|
826
|
+
const opts = parseObjectTypeCreateArgs(rest);
|
|
827
|
+
const token = await ensureValidToken();
|
|
828
|
+
let bodyStr;
|
|
829
|
+
if (opts.mode === "needsDataview") {
|
|
830
|
+
try {
|
|
831
|
+
bodyStr = await finalizeObjectTypeCreateFromDataview({
|
|
832
|
+
baseUrl: token.baseUrl,
|
|
833
|
+
accessToken: token.accessToken,
|
|
834
|
+
dataviewId: opts.dataviewId,
|
|
835
|
+
entry: opts.entry,
|
|
836
|
+
businessDomain: opts.businessDomain,
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
catch (e) {
|
|
840
|
+
console.error(formatHttpError(e));
|
|
841
|
+
return 1;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
bodyStr = opts.body;
|
|
846
|
+
}
|
|
847
|
+
const body = await createObjectTypes({
|
|
848
|
+
baseUrl: token.baseUrl,
|
|
849
|
+
accessToken: token.accessToken,
|
|
850
|
+
knId: opts.knId,
|
|
851
|
+
body: bodyStr,
|
|
852
|
+
businessDomain: opts.businessDomain,
|
|
853
|
+
branch: opts.branch,
|
|
854
|
+
});
|
|
855
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
856
|
+
return 0;
|
|
857
|
+
}
|
|
858
|
+
if (action === "update") {
|
|
859
|
+
const opts = parseObjectTypeUpdateArgs(rest);
|
|
860
|
+
const token = await ensureValidToken();
|
|
861
|
+
let putBody;
|
|
862
|
+
if (opts.mode === "body") {
|
|
863
|
+
putBody = opts.body;
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
const raw = await getObjectType({
|
|
867
|
+
baseUrl: token.baseUrl,
|
|
868
|
+
accessToken: token.accessToken,
|
|
869
|
+
knId: opts.knId,
|
|
870
|
+
otId: opts.otId,
|
|
871
|
+
businessDomain: opts.businessDomain,
|
|
872
|
+
branch: opts.branch,
|
|
873
|
+
});
|
|
874
|
+
const parsed = JSON.parse(raw);
|
|
875
|
+
const entryUnknown = parsed.entries;
|
|
876
|
+
const entry = Array.isArray(entryUnknown) && entryUnknown.length > 0 && entryUnknown[0] && typeof entryUnknown[0] === "object"
|
|
877
|
+
? entryUnknown[0]
|
|
878
|
+
: parsed;
|
|
879
|
+
if (!entry || typeof entry !== "object") {
|
|
880
|
+
throw new Error("Unexpected object-type GET response shape.");
|
|
881
|
+
}
|
|
882
|
+
const stripped = stripObjectTypeForPut(entry);
|
|
883
|
+
applyObjectTypeMerge(stripped, opts.merge);
|
|
884
|
+
putBody = JSON.stringify(stripped);
|
|
885
|
+
}
|
|
886
|
+
const body = await updateObjectType({
|
|
887
|
+
baseUrl: token.baseUrl,
|
|
888
|
+
accessToken: token.accessToken,
|
|
889
|
+
knId: opts.knId,
|
|
890
|
+
otId: opts.otId,
|
|
891
|
+
body: putBody,
|
|
892
|
+
businessDomain: opts.businessDomain,
|
|
893
|
+
});
|
|
894
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
895
|
+
return 0;
|
|
896
|
+
}
|
|
897
|
+
if (action === "delete") {
|
|
898
|
+
const opts = parseObjectTypeDeleteArgs(rest);
|
|
899
|
+
if (!opts.yes) {
|
|
900
|
+
const confirmed = await confirmYes(`Delete object type(s) ${opts.otIds}?`);
|
|
901
|
+
if (!confirmed) {
|
|
902
|
+
console.error("Aborted.");
|
|
903
|
+
return 1;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
const token = await ensureValidToken();
|
|
907
|
+
await deleteObjectTypes({
|
|
908
|
+
baseUrl: token.baseUrl,
|
|
909
|
+
accessToken: token.accessToken,
|
|
910
|
+
knId: opts.knId,
|
|
911
|
+
otIds: opts.otIds,
|
|
912
|
+
businessDomain: opts.businessDomain,
|
|
913
|
+
});
|
|
914
|
+
console.log(`Deleted ${opts.otIds}`);
|
|
915
|
+
return 0;
|
|
916
|
+
}
|
|
917
|
+
if (action === "list") {
|
|
918
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
919
|
+
const [knId] = parsed.filteredArgs;
|
|
920
|
+
if (!knId) {
|
|
921
|
+
console.error("Usage: kweaver bkn object-type list <kn-id> [options]");
|
|
922
|
+
return 1;
|
|
923
|
+
}
|
|
924
|
+
const token = await ensureValidToken();
|
|
925
|
+
const body = await listObjectTypes({
|
|
926
|
+
baseUrl: token.baseUrl,
|
|
927
|
+
accessToken: token.accessToken,
|
|
928
|
+
knId,
|
|
929
|
+
businessDomain: parsed.businessDomain,
|
|
930
|
+
});
|
|
931
|
+
console.log(formatCallOutput(body, parsed.pretty));
|
|
932
|
+
return 0;
|
|
933
|
+
}
|
|
934
|
+
if (action === "query") {
|
|
935
|
+
const options = parseKnObjectTypeQueryArgs(rest);
|
|
936
|
+
const token = await ensureValidToken();
|
|
937
|
+
const result = await objectTypeQuery({
|
|
938
|
+
baseUrl: token.baseUrl,
|
|
939
|
+
accessToken: token.accessToken,
|
|
940
|
+
knId: options.knId,
|
|
941
|
+
otId: options.otId,
|
|
942
|
+
body: options.body,
|
|
943
|
+
businessDomain: options.businessDomain,
|
|
944
|
+
});
|
|
945
|
+
console.log(formatCallOutput(truncateQueryResult(result), options.pretty));
|
|
946
|
+
return 0;
|
|
947
|
+
}
|
|
948
|
+
if (action === "properties") {
|
|
949
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
950
|
+
const [knId, otId, body] = parsed.filteredArgs;
|
|
951
|
+
if (!knId || !otId || !body) {
|
|
952
|
+
console.error(`Usage: kweaver bkn object-type properties <kn-id> <ot-id> '<json>' [options]
|
|
953
|
+
JSON: {"_instance_identities":[{"<primary-key>":"<value>"}],"properties":["prop1","prop2"]}`);
|
|
954
|
+
return 1;
|
|
955
|
+
}
|
|
956
|
+
const token = await ensureValidToken();
|
|
957
|
+
const result = await objectTypeProperties({
|
|
958
|
+
baseUrl: token.baseUrl,
|
|
959
|
+
accessToken: token.accessToken,
|
|
960
|
+
knId,
|
|
961
|
+
otId,
|
|
962
|
+
body,
|
|
963
|
+
businessDomain: parsed.businessDomain,
|
|
964
|
+
});
|
|
965
|
+
console.log(formatCallOutput(result, parsed.pretty));
|
|
966
|
+
return 0;
|
|
967
|
+
}
|
|
968
|
+
console.error(`Unknown object-type action: ${action}. Use list, get, create, update, delete, query, or properties.`);
|
|
969
|
+
return 1;
|
|
970
|
+
}
|
|
971
|
+
catch (error) {
|
|
972
|
+
if (error instanceof Error && error.message === "help") {
|
|
973
|
+
console.log(`kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W [--property '<json>' ...]
|
|
974
|
+
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]
|
|
975
|
+
kweaver bkn object-type update <kn-id> <ot-id> '<full-json-body>'
|
|
976
|
+
kweaver bkn object-type delete <kn-id> <ot-ids> [-y]`);
|
|
977
|
+
return 0;
|
|
978
|
+
}
|
|
979
|
+
console.error(formatHttpError(error));
|
|
980
|
+
return 1;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
export async function runKnRelationTypeCommand(args) {
|
|
984
|
+
const [action, ...rest] = args;
|
|
985
|
+
if (!action || action === "--help" || action === "-h") {
|
|
986
|
+
console.log(`kweaver bkn relation-type list <kn-id> [--pretty] [-bd value]
|
|
987
|
+
kweaver bkn relation-type get <kn-id> <rt-id> [--pretty] [-bd value]
|
|
988
|
+
kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]
|
|
989
|
+
kweaver bkn relation-type update <kn-id> <rt-id> --source <ot-id> --target <ot-id> [--name X] [--type direct|data_view] [--mapping src:tgt ...]
|
|
990
|
+
kweaver bkn relation-type delete <kn-id> <rt-ids> [-y]
|
|
991
|
+
|
|
992
|
+
list: List relation types (schema) from ontology-manager.
|
|
993
|
+
get: Get single relation type details.
|
|
994
|
+
create/update/delete: Schema CRUD.`);
|
|
995
|
+
return 0;
|
|
996
|
+
}
|
|
997
|
+
try {
|
|
998
|
+
if (action === "get") {
|
|
999
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1000
|
+
const [knId, rtId] = parsed.filteredArgs;
|
|
1001
|
+
if (!knId || !rtId) {
|
|
1002
|
+
console.error("Usage: kweaver bkn relation-type get <kn-id> <rt-id> [options]");
|
|
1003
|
+
return 1;
|
|
1004
|
+
}
|
|
1005
|
+
const token = await ensureValidToken();
|
|
1006
|
+
const body = await getRelationType({
|
|
1007
|
+
baseUrl: token.baseUrl,
|
|
1008
|
+
accessToken: token.accessToken,
|
|
1009
|
+
knId,
|
|
1010
|
+
rtId,
|
|
1011
|
+
businessDomain: parsed.businessDomain,
|
|
1012
|
+
});
|
|
1013
|
+
console.log(formatCallOutput(body, parsed.pretty));
|
|
1014
|
+
return 0;
|
|
1015
|
+
}
|
|
1016
|
+
if (action === "create") {
|
|
1017
|
+
const opts = parseRelationTypeCreateArgs(rest);
|
|
1018
|
+
const token = await ensureValidToken();
|
|
1019
|
+
const body = await createRelationTypes({
|
|
1020
|
+
baseUrl: token.baseUrl,
|
|
1021
|
+
accessToken: token.accessToken,
|
|
1022
|
+
knId: opts.knId,
|
|
1023
|
+
body: opts.body,
|
|
1024
|
+
businessDomain: opts.businessDomain,
|
|
1025
|
+
branch: opts.branch,
|
|
1026
|
+
});
|
|
1027
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
1028
|
+
return 0;
|
|
1029
|
+
}
|
|
1030
|
+
if (action === "update") {
|
|
1031
|
+
const opts = parseRelationTypeUpdateArgs(rest);
|
|
1032
|
+
const token = await ensureValidToken();
|
|
1033
|
+
const body = await updateRelationType({
|
|
1034
|
+
baseUrl: token.baseUrl,
|
|
1035
|
+
accessToken: token.accessToken,
|
|
1036
|
+
knId: opts.knId,
|
|
1037
|
+
rtId: opts.rtId,
|
|
1038
|
+
body: opts.body,
|
|
1039
|
+
businessDomain: opts.businessDomain,
|
|
1040
|
+
});
|
|
1041
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
1042
|
+
return 0;
|
|
1043
|
+
}
|
|
1044
|
+
if (action === "delete") {
|
|
1045
|
+
const opts = parseRelationTypeDeleteArgs(rest);
|
|
1046
|
+
if (!opts.yes) {
|
|
1047
|
+
const confirmed = await confirmYes(`Delete relation type(s) ${opts.rtIds}?`);
|
|
1048
|
+
if (!confirmed) {
|
|
1049
|
+
console.error("Aborted.");
|
|
1050
|
+
return 1;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
const token = await ensureValidToken();
|
|
1054
|
+
await deleteRelationTypes({
|
|
1055
|
+
baseUrl: token.baseUrl,
|
|
1056
|
+
accessToken: token.accessToken,
|
|
1057
|
+
knId: opts.knId,
|
|
1058
|
+
rtIds: opts.rtIds,
|
|
1059
|
+
businessDomain: opts.businessDomain,
|
|
1060
|
+
});
|
|
1061
|
+
console.log(`Deleted ${opts.rtIds}`);
|
|
1062
|
+
return 0;
|
|
1063
|
+
}
|
|
1064
|
+
if (action === "list") {
|
|
1065
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1066
|
+
const [knId] = parsed.filteredArgs;
|
|
1067
|
+
if (!knId) {
|
|
1068
|
+
console.error("Usage: kweaver bkn relation-type list <kn-id> [options]");
|
|
1069
|
+
return 1;
|
|
1070
|
+
}
|
|
1071
|
+
const token = await ensureValidToken();
|
|
1072
|
+
const body = await listRelationTypes({
|
|
1073
|
+
baseUrl: token.baseUrl,
|
|
1074
|
+
accessToken: token.accessToken,
|
|
1075
|
+
knId,
|
|
1076
|
+
businessDomain: parsed.businessDomain,
|
|
1077
|
+
});
|
|
1078
|
+
console.log(formatCallOutput(body, parsed.pretty));
|
|
1079
|
+
return 0;
|
|
1080
|
+
}
|
|
1081
|
+
console.error(`Unknown relation-type action: ${action}. Use list, get, create, update, or delete.`);
|
|
1082
|
+
return 1;
|
|
1083
|
+
}
|
|
1084
|
+
catch (error) {
|
|
1085
|
+
if (error instanceof Error && error.message === "help") {
|
|
1086
|
+
console.log(`kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]
|
|
1087
|
+
kweaver bkn relation-type update <kn-id> <rt-id> --source <ot-id> --target <ot-id> [--name X] [--type direct|data_view] [--mapping src:tgt ...]
|
|
1088
|
+
kweaver bkn relation-type delete <kn-id> <rt-ids> [-y]`);
|
|
1089
|
+
return 0;
|
|
1090
|
+
}
|
|
1091
|
+
console.error(formatHttpError(error));
|
|
1092
|
+
return 1;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
export async function runKnActionTypeCommand(args) {
|
|
1096
|
+
const [action, ...rest] = args;
|
|
1097
|
+
if (!action || action === "--help" || action === "-h") {
|
|
1098
|
+
console.log(`kweaver bkn action-type list <kn-id> [--pretty] [-bd value]
|
|
1099
|
+
kweaver bkn action-type get <kn-id> <at-id> [--pretty] [-bd value]
|
|
1100
|
+
kweaver bkn action-type create <kn-id> '<json>' [--pretty] [-bd value]
|
|
1101
|
+
kweaver bkn action-type update <kn-id> <at-id> '<json>' [--pretty] [-bd value]
|
|
1102
|
+
kweaver bkn action-type delete <kn-id> <at-ids> [-y] [--pretty] [-bd value]
|
|
1103
|
+
kweaver bkn action-type query <kn-id> <at-id> '<json>' [--pretty] [-bd value]
|
|
1104
|
+
kweaver bkn action-type execute <kn-id> <at-id> '<json>' [--pretty] [-bd value] [--wait|--no-wait] [--timeout n]
|
|
1105
|
+
|
|
1106
|
+
list: List action types (schema) from ontology-manager.
|
|
1107
|
+
get: Get a single action type by ID.
|
|
1108
|
+
create: Create action type(s) (POST JSON body).
|
|
1109
|
+
update: Update an action type (PUT JSON body).
|
|
1110
|
+
delete: Delete action type(s) by ID(s).
|
|
1111
|
+
query/execute: Query or execute actions. execute has side effects - only use when explicitly requested.
|
|
1112
|
+
--wait (default) Poll until execution completes
|
|
1113
|
+
--no-wait Return immediately after starting execution
|
|
1114
|
+
--timeout <seconds> Max wait time when --wait (default: 300)`);
|
|
1115
|
+
return 0;
|
|
1116
|
+
}
|
|
1117
|
+
if (action === "list") {
|
|
1118
|
+
try {
|
|
1119
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1120
|
+
const [knId] = parsed.filteredArgs;
|
|
1121
|
+
if (!knId) {
|
|
1122
|
+
console.error("Usage: kweaver bkn action-type list <kn-id> [options]");
|
|
1123
|
+
return 1;
|
|
1124
|
+
}
|
|
1125
|
+
const token = await ensureValidToken();
|
|
1126
|
+
const body = await listActionTypes({
|
|
1127
|
+
baseUrl: token.baseUrl,
|
|
1128
|
+
accessToken: token.accessToken,
|
|
1129
|
+
knId,
|
|
1130
|
+
businessDomain: parsed.businessDomain,
|
|
1131
|
+
});
|
|
1132
|
+
console.log(formatCallOutput(body, parsed.pretty));
|
|
1133
|
+
return 0;
|
|
1134
|
+
}
|
|
1135
|
+
catch (error) {
|
|
1136
|
+
console.error(formatHttpError(error));
|
|
1137
|
+
return 1;
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
if (action === "get") {
|
|
1141
|
+
try {
|
|
1142
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1143
|
+
const [knId, atId] = parsed.filteredArgs;
|
|
1144
|
+
if (!knId || !atId) {
|
|
1145
|
+
console.error("Usage: kweaver bkn action-type get <kn-id> <at-id>");
|
|
1146
|
+
return 1;
|
|
1147
|
+
}
|
|
1148
|
+
const token = await ensureValidToken();
|
|
1149
|
+
const body = await getActionType({ baseUrl: token.baseUrl, accessToken: token.accessToken, knId, atId, businessDomain: parsed.businessDomain });
|
|
1150
|
+
console.log(formatCallOutput(body, parsed.pretty));
|
|
1151
|
+
return 0;
|
|
1152
|
+
}
|
|
1153
|
+
catch (error) {
|
|
1154
|
+
console.error(formatHttpError(error));
|
|
1155
|
+
return 1;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
if (action === "create") {
|
|
1159
|
+
try {
|
|
1160
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1161
|
+
const [knId, bodyJson] = parsed.filteredArgs;
|
|
1162
|
+
if (!knId || !bodyJson) {
|
|
1163
|
+
console.error("Usage: kweaver bkn action-type create <kn-id> '<json>'");
|
|
1164
|
+
return 1;
|
|
1165
|
+
}
|
|
1166
|
+
const token = await ensureValidToken();
|
|
1167
|
+
const result = await createActionTypes({ baseUrl: token.baseUrl, accessToken: token.accessToken, knId, body: bodyJson, businessDomain: parsed.businessDomain });
|
|
1168
|
+
console.log(formatCallOutput(result, parsed.pretty));
|
|
1169
|
+
return 0;
|
|
1170
|
+
}
|
|
1171
|
+
catch (error) {
|
|
1172
|
+
console.error(formatHttpError(error));
|
|
1173
|
+
return 1;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
if (action === "update") {
|
|
1177
|
+
try {
|
|
1178
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1179
|
+
const [knId, atId, bodyJson] = parsed.filteredArgs;
|
|
1180
|
+
if (!knId || !atId || !bodyJson) {
|
|
1181
|
+
console.error("Usage: kweaver bkn action-type update <kn-id> <at-id> '<json>'");
|
|
1182
|
+
return 1;
|
|
1183
|
+
}
|
|
1184
|
+
const token = await ensureValidToken();
|
|
1185
|
+
const result = await updateActionType({ baseUrl: token.baseUrl, accessToken: token.accessToken, knId, atId, body: bodyJson, businessDomain: parsed.businessDomain });
|
|
1186
|
+
console.log(formatCallOutput(result, parsed.pretty));
|
|
1187
|
+
return 0;
|
|
1188
|
+
}
|
|
1189
|
+
catch (error) {
|
|
1190
|
+
console.error(formatHttpError(error));
|
|
1191
|
+
return 1;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
if (action === "delete") {
|
|
1195
|
+
try {
|
|
1196
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1197
|
+
const yes = parsed.filteredArgs.includes("-y") || parsed.filteredArgs.includes("--yes");
|
|
1198
|
+
const positional = parsed.filteredArgs.filter(a => a !== "-y" && a !== "--yes");
|
|
1199
|
+
const [knId, atIds] = positional;
|
|
1200
|
+
if (!knId || !atIds) {
|
|
1201
|
+
console.error("Usage: kweaver bkn action-type delete <kn-id> <at-ids> [-y]");
|
|
1202
|
+
return 1;
|
|
1203
|
+
}
|
|
1204
|
+
if (!yes) {
|
|
1205
|
+
const confirmed = await confirmYes(`Delete action type(s) ${atIds}?`);
|
|
1206
|
+
if (!confirmed) {
|
|
1207
|
+
console.log("Cancelled.");
|
|
1208
|
+
return 0;
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
const token = await ensureValidToken();
|
|
1212
|
+
await deleteActionTypes({ baseUrl: token.baseUrl, accessToken: token.accessToken, knId, atIds, businessDomain: parsed.businessDomain });
|
|
1213
|
+
console.log("Deleted.");
|
|
1214
|
+
return 0;
|
|
1215
|
+
}
|
|
1216
|
+
catch (error) {
|
|
1217
|
+
console.error(formatHttpError(error));
|
|
1218
|
+
return 1;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
if (action === "query") {
|
|
1222
|
+
let filteredArgs;
|
|
1223
|
+
let pretty;
|
|
1224
|
+
let businessDomain;
|
|
1225
|
+
try {
|
|
1226
|
+
const parsed = parseOntologyQueryFlags(rest);
|
|
1227
|
+
filteredArgs = parsed.filteredArgs;
|
|
1228
|
+
pretty = parsed.pretty;
|
|
1229
|
+
businessDomain = parsed.businessDomain;
|
|
1230
|
+
}
|
|
1231
|
+
catch (error) {
|
|
1232
|
+
if (error instanceof Error && error.message === "help")
|
|
1233
|
+
return 0;
|
|
1234
|
+
throw error;
|
|
1235
|
+
}
|
|
1236
|
+
const [knId, atId, body] = filteredArgs;
|
|
1237
|
+
if (!knId || !atId || !body) {
|
|
1238
|
+
console.error("Usage: kweaver bkn action-type query <kn-id> <at-id> '<json>' [options]");
|
|
1239
|
+
return 1;
|
|
1240
|
+
}
|
|
1241
|
+
try {
|
|
1242
|
+
const token = await ensureValidToken();
|
|
1243
|
+
const result = await actionTypeQuery({
|
|
1244
|
+
baseUrl: token.baseUrl,
|
|
1245
|
+
accessToken: token.accessToken,
|
|
1246
|
+
knId,
|
|
1247
|
+
atId,
|
|
1248
|
+
body,
|
|
1249
|
+
businessDomain,
|
|
1250
|
+
});
|
|
1251
|
+
console.log(formatCallOutput(result, pretty));
|
|
1252
|
+
return 0;
|
|
1253
|
+
}
|
|
1254
|
+
catch (error) {
|
|
1255
|
+
console.error(formatHttpError(error));
|
|
1256
|
+
return 1;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
if (action === "execute") {
|
|
1260
|
+
let options;
|
|
1261
|
+
try {
|
|
1262
|
+
options = parseKnActionTypeExecuteArgs(rest);
|
|
1263
|
+
}
|
|
1264
|
+
catch (error) {
|
|
1265
|
+
if (error instanceof Error && error.message === "help")
|
|
1266
|
+
return 0;
|
|
1267
|
+
console.error(formatHttpError(error));
|
|
1268
|
+
return 1;
|
|
1269
|
+
}
|
|
1270
|
+
try {
|
|
1271
|
+
const token = await ensureValidToken();
|
|
1272
|
+
const base = {
|
|
1273
|
+
baseUrl: token.baseUrl,
|
|
1274
|
+
accessToken: token.accessToken,
|
|
1275
|
+
knId: options.knId,
|
|
1276
|
+
atId: options.atId,
|
|
1277
|
+
body: options.body,
|
|
1278
|
+
businessDomain: options.businessDomain,
|
|
1279
|
+
};
|
|
1280
|
+
const result = await actionTypeExecute(base);
|
|
1281
|
+
if (!options.wait) {
|
|
1282
|
+
console.log(formatCallOutput(result, options.pretty));
|
|
1283
|
+
return 0;
|
|
1284
|
+
}
|
|
1285
|
+
const executionId = extractExecutionId(result);
|
|
1286
|
+
if (!executionId) {
|
|
1287
|
+
console.log(formatCallOutput(result, options.pretty));
|
|
1288
|
+
return 0;
|
|
1289
|
+
}
|
|
1290
|
+
let lastBody = result;
|
|
1291
|
+
try {
|
|
1292
|
+
lastBody = await pollWithBackoff({
|
|
1293
|
+
fn: async () => {
|
|
1294
|
+
const status = extractStatus(lastBody);
|
|
1295
|
+
if (TERMINAL_STATUSES.includes(status.toUpperCase())) {
|
|
1296
|
+
return { done: true, value: lastBody };
|
|
1297
|
+
}
|
|
1298
|
+
lastBody = await actionExecutionGet({
|
|
1299
|
+
baseUrl: token.baseUrl,
|
|
1300
|
+
accessToken: token.accessToken,
|
|
1301
|
+
knId: options.knId,
|
|
1302
|
+
executionId,
|
|
1303
|
+
businessDomain: options.businessDomain,
|
|
1304
|
+
});
|
|
1305
|
+
return { done: false, value: lastBody };
|
|
1306
|
+
},
|
|
1307
|
+
interval: 2000,
|
|
1308
|
+
timeout: options.timeout * 1000,
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
catch {
|
|
1312
|
+
console.error(`Action execution did not complete within ${options.timeout}s`);
|
|
1313
|
+
console.log(formatCallOutput(lastBody, options.pretty));
|
|
1314
|
+
return 1;
|
|
1315
|
+
}
|
|
1316
|
+
const finalStatus = extractStatus(lastBody);
|
|
1317
|
+
console.log(formatCallOutput(lastBody, options.pretty));
|
|
1318
|
+
return finalStatus.toUpperCase() === "SUCCESS" ? 0 : 1;
|
|
1319
|
+
}
|
|
1320
|
+
catch (error) {
|
|
1321
|
+
console.error(formatHttpError(error));
|
|
1322
|
+
return 1;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
console.error(`Unknown action-type action: ${action}. Use list, get, create, update, delete, query, or execute.`);
|
|
1326
|
+
return 1;
|
|
1327
|
+
}
|
|
1328
|
+
export function parseConceptGroupArgs(args) {
|
|
1329
|
+
const [action, ...rest] = args;
|
|
1330
|
+
if (!action || action === "--help" || action === "-h")
|
|
1331
|
+
throw new Error("help");
|
|
1332
|
+
let pretty = true;
|
|
1333
|
+
let businessDomain = "";
|
|
1334
|
+
let yes = false;
|
|
1335
|
+
const positional = [];
|
|
1336
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
1337
|
+
const arg = rest[i];
|
|
1338
|
+
if (arg === "--help" || arg === "-h")
|
|
1339
|
+
throw new Error("help");
|
|
1340
|
+
if (arg === "--pretty") {
|
|
1341
|
+
pretty = true;
|
|
1342
|
+
continue;
|
|
1343
|
+
}
|
|
1344
|
+
if ((arg === "-bd" || arg === "--biz-domain") && rest[i + 1]) {
|
|
1345
|
+
businessDomain = rest[++i];
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1348
|
+
if (arg === "-y" || arg === "--yes") {
|
|
1349
|
+
yes = true;
|
|
1350
|
+
continue;
|
|
1351
|
+
}
|
|
1352
|
+
positional.push(arg);
|
|
1353
|
+
}
|
|
1354
|
+
const [knId, itemId, extra] = positional;
|
|
1355
|
+
if (!knId)
|
|
1356
|
+
throw new Error("Missing kn-id. Usage: kweaver bkn concept-group <action> <kn-id> ...");
|
|
1357
|
+
if (!businessDomain)
|
|
1358
|
+
businessDomain = resolveBusinessDomain();
|
|
1359
|
+
return { action, knId, itemId: itemId || "", body: itemId || "", extra: extra || "", yes, pretty, businessDomain };
|
|
1360
|
+
}
|
|
1361
|
+
export async function runKnConceptGroupCommand(args) {
|
|
1362
|
+
let parsed;
|
|
1363
|
+
try {
|
|
1364
|
+
parsed = parseConceptGroupArgs(args);
|
|
1365
|
+
}
|
|
1366
|
+
catch (error) {
|
|
1367
|
+
if (error instanceof Error && error.message === "help") {
|
|
1368
|
+
console.log(`kweaver bkn concept-group <action> <kn-id> [args] [--pretty] [-bd value]
|
|
1369
|
+
|
|
1370
|
+
Actions:
|
|
1371
|
+
list <kn-id> List concept groups
|
|
1372
|
+
get <kn-id> <cg-id> Get concept group details
|
|
1373
|
+
create <kn-id> '<json>' Create concept group
|
|
1374
|
+
update <kn-id> <cg-id> '<json>' Update concept group
|
|
1375
|
+
delete <kn-id> <cg-id> [-y] Delete concept group
|
|
1376
|
+
add-members <kn-id> <cg-id> <ot-ids> Add object type members (comma-separated)
|
|
1377
|
+
remove-members <kn-id> <cg-id> <ot-ids> [-y] Remove object type members`);
|
|
1378
|
+
return 0;
|
|
1379
|
+
}
|
|
1380
|
+
console.error(formatHttpError(error));
|
|
1381
|
+
return 1;
|
|
1382
|
+
}
|
|
1383
|
+
const { action, knId, itemId, body, extra, yes, pretty, businessDomain } = parsed;
|
|
1384
|
+
const token = await ensureValidToken();
|
|
1385
|
+
const base = { baseUrl: token.baseUrl, accessToken: token.accessToken, businessDomain };
|
|
1386
|
+
if (action === "list") {
|
|
1387
|
+
const result = await listConceptGroups({ ...base, knId });
|
|
1388
|
+
console.log(formatCallOutput(result, pretty));
|
|
1389
|
+
return 0;
|
|
1390
|
+
}
|
|
1391
|
+
if (action === "get") {
|
|
1392
|
+
if (!itemId) {
|
|
1393
|
+
console.error("Missing cg-id");
|
|
1394
|
+
return 1;
|
|
1395
|
+
}
|
|
1396
|
+
const result = await getConceptGroup({ ...base, knId, cgId: itemId });
|
|
1397
|
+
console.log(formatCallOutput(result, pretty));
|
|
1398
|
+
return 0;
|
|
1399
|
+
}
|
|
1400
|
+
if (action === "create") {
|
|
1401
|
+
if (!itemId) {
|
|
1402
|
+
console.error("Missing JSON body");
|
|
1403
|
+
return 1;
|
|
1404
|
+
}
|
|
1405
|
+
const result = await createConceptGroup({ ...base, knId, body });
|
|
1406
|
+
console.log(formatCallOutput(result, pretty));
|
|
1407
|
+
return 0;
|
|
1408
|
+
}
|
|
1409
|
+
if (action === "update") {
|
|
1410
|
+
if (!itemId || !extra) {
|
|
1411
|
+
console.error("Missing cg-id or JSON body");
|
|
1412
|
+
return 1;
|
|
1413
|
+
}
|
|
1414
|
+
const result = await updateConceptGroup({ ...base, knId, cgId: itemId, body: extra });
|
|
1415
|
+
console.log(formatCallOutput(result, pretty));
|
|
1416
|
+
return 0;
|
|
1417
|
+
}
|
|
1418
|
+
if (action === "delete") {
|
|
1419
|
+
if (!itemId) {
|
|
1420
|
+
console.error("Missing cg-id");
|
|
1421
|
+
return 1;
|
|
1422
|
+
}
|
|
1423
|
+
if (!yes) {
|
|
1424
|
+
const confirmed = await confirmYes(`Delete concept group ${itemId}?`);
|
|
1425
|
+
if (!confirmed) {
|
|
1426
|
+
console.log("Cancelled.");
|
|
1427
|
+
return 0;
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
const result = await deleteConceptGroup({ ...base, knId, cgId: itemId });
|
|
1431
|
+
console.log(formatCallOutput(result, pretty));
|
|
1432
|
+
return 0;
|
|
1433
|
+
}
|
|
1434
|
+
if (action === "add-members") {
|
|
1435
|
+
if (!itemId || !extra) {
|
|
1436
|
+
console.error("Missing cg-id or ot-ids");
|
|
1437
|
+
return 1;
|
|
1438
|
+
}
|
|
1439
|
+
const result = await addConceptGroupMembers({ ...base, knId, cgId: itemId, body: JSON.stringify({ ot_ids: extra.split(",") }) });
|
|
1440
|
+
console.log(formatCallOutput(result, pretty));
|
|
1441
|
+
return 0;
|
|
1442
|
+
}
|
|
1443
|
+
if (action === "remove-members") {
|
|
1444
|
+
if (!itemId || !extra) {
|
|
1445
|
+
console.error("Missing cg-id or ot-ids");
|
|
1446
|
+
return 1;
|
|
1447
|
+
}
|
|
1448
|
+
if (!yes) {
|
|
1449
|
+
const confirmed = await confirmYes(`Remove members ${extra} from concept group ${itemId}?`);
|
|
1450
|
+
if (!confirmed) {
|
|
1451
|
+
console.log("Cancelled.");
|
|
1452
|
+
return 0;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
const result = await removeConceptGroupMembers({ ...base, knId, cgId: itemId, otIds: extra });
|
|
1456
|
+
console.log(formatCallOutput(result, pretty));
|
|
1457
|
+
return 0;
|
|
1458
|
+
}
|
|
1459
|
+
console.error(`Unknown concept-group action: ${action}`);
|
|
1460
|
+
return 1;
|
|
1461
|
+
}
|