@kweaver-ai/kweaver-sdk 0.7.1 → 0.7.3
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 +34 -4
- package/README.zh.md +27 -2
- package/dist/api/datasources.d.ts +7 -0
- package/dist/api/datasources.js +8 -0
- package/dist/api/skills.js +10 -8
- package/dist/api/toolboxes.d.ts +2 -0
- package/dist/api/toolboxes.js +2 -1
- package/dist/cli.js +65 -17
- package/dist/commands/auth.js +85 -10
- package/dist/commands/bkn-ops.d.ts +6 -1
- package/dist/commands/bkn-ops.js +202 -93
- package/dist/commands/bkn-utils.d.ts +26 -2
- package/dist/commands/bkn-utils.js +66 -9
- package/dist/commands/config.js +8 -0
- package/dist/commands/context-loader.js +112 -36
- package/dist/commands/dataflow.js +194 -20
- package/dist/commands/ds.d.ts +23 -1
- package/dist/commands/ds.js +135 -27
- package/dist/commands/import-csv.d.ts +0 -2
- package/dist/commands/import-csv.js +2 -4
- package/dist/commands/skill.js +26 -6
- package/dist/commands/tool.d.ts +1 -0
- package/dist/commands/tool.js +12 -0
- package/dist/config/stateless.d.ts +13 -0
- package/dist/config/stateless.js +20 -0
- package/dist/config/store.d.ts +1 -0
- package/dist/config/store.js +17 -0
- package/dist/resources/toolboxes.d.ts +2 -0
- package/dist/templates/bkn/document/manifest.json +12 -0
- package/dist/templates/bkn/document/template.json +757 -0
- package/dist/templates/dataflow/unstructured/manifest.json +11 -0
- package/dist/templates/dataflow/unstructured/template.json +63 -0
- package/dist/templates/dataset/document/manifest.json +10 -0
- package/dist/templates/dataset/document/template.json +23 -0
- package/dist/templates/dataset/document-content/manifest.json +10 -0
- package/dist/templates/dataset/document-content/template.json +29 -0
- package/dist/templates/dataset/document-element/manifest.json +10 -0
- package/dist/templates/dataset/document-element/template.json +21 -0
- package/dist/utils/skill-bundle.d.ts +5 -0
- package/dist/utils/skill-bundle.js +74 -0
- package/dist/utils/template-loader.d.ts +40 -0
- package/dist/utils/template-loader.js +129 -0
- package/package.json +2 -1
|
@@ -2,12 +2,28 @@ import { ensureValidToken, formatHttpError, resolveActivePlatform, with401Refres
|
|
|
2
2
|
import { callTool, searchSchema, queryObjectInstance, queryInstanceSubgraph, getLogicPropertiesValues, getActionInfo, findSkills, listTools, listResources, readResource, listResourceTemplates, listPrompts, getPrompt, } from "../api/context-loader.js";
|
|
3
3
|
import { knSearchHttp, semanticSearch } from "../api/semantic-search.js";
|
|
4
4
|
import { addContextLoaderEntry, getCurrentContextLoaderKn, loadContextLoaderConfig, removeContextLoaderEntry, resolveBusinessDomain, setCurrentContextLoader, } from "../config/store.js";
|
|
5
|
+
import { assertNotStatelessForWrite } from "../config/stateless.js";
|
|
6
|
+
const CONTEXT_LOADER_CONFIG_DEPRECATION = "[deprecated] `kweaver context-loader config ...` will be removed in a future release. " +
|
|
7
|
+
"Pass <kn-id> as the first positional to runtime subcommands instead, e.g. " +
|
|
8
|
+
"`kweaver context-loader tools <kn-id>` (or use the `--kn-id <id>` flag).";
|
|
5
9
|
const MCP_NOT_CONFIGURED = "Context-loader MCP is not configured. Run: kweaver context-loader config set --kn-id <kn-id>";
|
|
6
|
-
|
|
10
|
+
const MCP_PATH = "/api/agent-retrieval/v1/mcp";
|
|
11
|
+
function ensureContextLoaderConfig(knIdOverride) {
|
|
7
12
|
const active = resolveActivePlatform();
|
|
8
13
|
if (!active) {
|
|
9
14
|
throw new Error("No platform selected. Set KWEAVER_BASE_URL or run: kweaver auth <platform-url>");
|
|
10
15
|
}
|
|
16
|
+
// Override path (positional <kn-id> or --kn-id flag): derive MCP URL from
|
|
17
|
+
// the active platform; do not touch the deprecated saved config.
|
|
18
|
+
if (knIdOverride) {
|
|
19
|
+
return {
|
|
20
|
+
baseUrl: active.url,
|
|
21
|
+
mcpUrl: active.url.replace(/\/+$/, "") + MCP_PATH,
|
|
22
|
+
knId: knIdOverride,
|
|
23
|
+
accessToken: "",
|
|
24
|
+
businessDomain: resolveBusinessDomain(active.url),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
11
27
|
const kn = getCurrentContextLoaderKn();
|
|
12
28
|
if (!kn) {
|
|
13
29
|
throw new Error(MCP_NOT_CONFIGURED);
|
|
@@ -20,6 +36,50 @@ function ensureContextLoaderConfig() {
|
|
|
20
36
|
businessDomain: resolveBusinessDomain(active.url),
|
|
21
37
|
};
|
|
22
38
|
}
|
|
39
|
+
// Subcommands that consult `ensureContextLoaderConfig`. The number is the
|
|
40
|
+
// minimum non-flag positional count expected by the handler itself (after
|
|
41
|
+
// kn-id is extracted). When the leading non-flag positional count exceeds
|
|
42
|
+
// this minimum, the first one is treated as <kn-id>.
|
|
43
|
+
const RUNTIME_MIN_POSITIONALS = {
|
|
44
|
+
tools: 0,
|
|
45
|
+
resources: 0,
|
|
46
|
+
templates: 0,
|
|
47
|
+
prompts: 0,
|
|
48
|
+
prompt: 1,
|
|
49
|
+
resource: 1,
|
|
50
|
+
"search-schema": 1,
|
|
51
|
+
"tool-call": 1,
|
|
52
|
+
"kn-search": 1,
|
|
53
|
+
"kn-schema-search": 1,
|
|
54
|
+
"query-object-instance": 1,
|
|
55
|
+
"query-instance-subgraph": 1,
|
|
56
|
+
"get-logic-properties": 1,
|
|
57
|
+
"get-action-info": 1,
|
|
58
|
+
"find-skills": 1,
|
|
59
|
+
};
|
|
60
|
+
function extractKnIdOverride(subcommand, rest) {
|
|
61
|
+
// 1) Explicit flag wins. `--kn-id <id>` / `-k <id>` is allowed for every
|
|
62
|
+
// runtime subcommand and is consumed before the handler sees `rest`.
|
|
63
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
64
|
+
if ((rest[i] === "--kn-id" || rest[i] === "-k") && rest[i + 1]) {
|
|
65
|
+
const id = rest[i + 1];
|
|
66
|
+
rest.splice(i, 2);
|
|
67
|
+
return id;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// 2) Positional <kn-id> as the first non-flag arg, when leading non-flag
|
|
71
|
+
// positional count exceeds what the handler itself requires.
|
|
72
|
+
const min = RUNTIME_MIN_POSITIONALS[subcommand];
|
|
73
|
+
if (min === undefined)
|
|
74
|
+
return undefined;
|
|
75
|
+
let cut = 0;
|
|
76
|
+
while (cut < rest.length && !rest[cut].startsWith("-"))
|
|
77
|
+
cut += 1;
|
|
78
|
+
if (cut > min) {
|
|
79
|
+
return rest.shift();
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
23
83
|
function formatOutput(value, pretty) {
|
|
24
84
|
const json = JSON.stringify(value, null, pretty ? 2 : 0);
|
|
25
85
|
return json;
|
|
@@ -29,34 +89,38 @@ export async function runContextLoaderCommand(args) {
|
|
|
29
89
|
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
30
90
|
console.log(`kweaver context-loader
|
|
31
91
|
|
|
92
|
+
KN selection (for runtime subcommands below):
|
|
93
|
+
Pass <kn-id> as the FIRST positional, e.g. \`kweaver context-loader tools <kn-id>\`,
|
|
94
|
+
or use the global \`--kn-id <id>\` / \`-k <id>\` flag. When omitted, falls back to
|
|
95
|
+
the deprecated saved config managed by \`kweaver context-loader config\`.
|
|
96
|
+
|
|
32
97
|
Subcommands:
|
|
33
|
-
config set --kn-id <id> [--name n] Add or update kn config
|
|
34
|
-
config use <name> Switch current config
|
|
35
|
-
config list
|
|
36
|
-
config remove <name> Remove a config
|
|
37
|
-
config show
|
|
38
|
-
tools
|
|
39
|
-
resources
|
|
40
|
-
resource <uri>
|
|
41
|
-
templates
|
|
42
|
-
prompts
|
|
43
|
-
prompt <name> [--args json]
|
|
44
|
-
search-schema <query> [
|
|
45
|
-
tool-call <name> --args '<json>'
|
|
46
|
-
kn-search <query> [--only-schema]
|
|
47
|
-
kn-schema-search <query> [--max N]
|
|
48
|
-
query-object-instance <json>
|
|
49
|
-
query-instance-subgraph <json>
|
|
50
|
-
get-logic-properties <json>
|
|
51
|
-
get-action-info <json>
|
|
52
|
-
find-skills <ot_id> [options]
|
|
98
|
+
config set --kn-id <id> [--name n] [deprecated] Add or update kn config
|
|
99
|
+
config use <name> [deprecated] Switch current config
|
|
100
|
+
config list [deprecated] List all configs and current
|
|
101
|
+
config remove <name> [deprecated] Remove a config
|
|
102
|
+
config show [deprecated] Show current config (knId + mcpUrl)
|
|
103
|
+
tools <kn-id> tools/list - list available tools
|
|
104
|
+
resources <kn-id> resources/list - list resources
|
|
105
|
+
resource <kn-id> <uri> resources/read - read resource by URI
|
|
106
|
+
templates <kn-id> resources/templates/list - list resource templates
|
|
107
|
+
prompts <kn-id> prompts/list - list prompts
|
|
108
|
+
prompt <kn-id> <name> [--args json] prompts/get - get prompt by name
|
|
109
|
+
search-schema <kn-id> <query> [opts] MCP search_schema (object/relation/action/metric)
|
|
110
|
+
tool-call <kn-id> <name> --args '<json>' MCP tools/call for any server tool
|
|
111
|
+
kn-search <kn-id> <query> [--only-schema] Compatibility: HTTP kn_search
|
|
112
|
+
kn-schema-search <kn-id> <query> [--max N] Compatibility: HTTP semantic-search
|
|
113
|
+
query-object-instance <kn-id> <json> Layer 2: Query instances
|
|
114
|
+
query-instance-subgraph <kn-id> <json> Layer 2: Query subgraph
|
|
115
|
+
get-logic-properties <kn-id> <json> Layer 3: Get logic property values
|
|
116
|
+
get-action-info <kn-id> <json> Layer 3: Get action info
|
|
117
|
+
find-skills <kn-id> <ot_id> [options] Layer 3: Recall skills for an object type
|
|
53
118
|
|
|
54
119
|
Examples:
|
|
55
|
-
kweaver context-loader
|
|
56
|
-
kweaver context-loader
|
|
57
|
-
kweaver context-loader
|
|
58
|
-
kweaver context-loader
|
|
59
|
-
kweaver context-loader kn-search "高血压 治疗 药品" --only-schema --pretty`);
|
|
120
|
+
kweaver context-loader tools d5iv6c9818p72mpje8pg
|
|
121
|
+
kweaver context-loader search-schema d5iv6c9818p72mpje8pg "利润率" --scope object,metric --max 5
|
|
122
|
+
kweaver context-loader tool-call d5iv6c9818p72mpje8pg search_schema --args '{"query":"利润率"}'
|
|
123
|
+
kweaver context-loader kn-search d5iv6c9818p72mpje8pg "高血压 治疗 药品" --only-schema --pretty`);
|
|
60
124
|
return 0;
|
|
61
125
|
}
|
|
62
126
|
if (subcommand === "config") {
|
|
@@ -68,9 +132,12 @@ Examples:
|
|
|
68
132
|
pretty = true;
|
|
69
133
|
rest.splice(prettyIdx, 1);
|
|
70
134
|
}
|
|
135
|
+
// Extract `<kn-id>` (positional or --kn-id/-k flag) before per-subcommand
|
|
136
|
+
// arg parsing. When provided it bypasses the deprecated saved config.
|
|
137
|
+
const knIdOverride = extractKnIdOverride(subcommand, rest);
|
|
71
138
|
const dispatch = async () => {
|
|
72
139
|
const token = await ensureValidToken();
|
|
73
|
-
const base = ensureContextLoaderConfig();
|
|
140
|
+
const base = ensureContextLoaderConfig(knIdOverride);
|
|
74
141
|
const options = { ...base, accessToken: token.accessToken };
|
|
75
142
|
if (subcommand === "tools")
|
|
76
143
|
return runListTools(options, rest, pretty);
|
|
@@ -122,16 +189,30 @@ Examples:
|
|
|
122
189
|
async function runConfigCommand(args) {
|
|
123
190
|
const [action, ...rest] = args;
|
|
124
191
|
if (!action || action === "--help" || action === "-h") {
|
|
125
|
-
console.log(`kweaver context-loader config
|
|
192
|
+
console.log(`kweaver context-loader config [deprecated]
|
|
126
193
|
|
|
127
194
|
Subcommands:
|
|
128
195
|
set --kn-id <id> [--name <name>] Add or update kn config (default name: default)
|
|
129
196
|
use <name> Switch current config
|
|
130
197
|
list List all configs and current
|
|
131
198
|
remove <name> Remove a config
|
|
132
|
-
show Show current config (knId + mcpUrl)
|
|
199
|
+
show Show current config (knId + mcpUrl)
|
|
200
|
+
|
|
201
|
+
Note: this command group is deprecated and will be removed in a future release.
|
|
202
|
+
It is disabled entirely in stateless mode (\`--token\`).`);
|
|
133
203
|
return 0;
|
|
134
204
|
}
|
|
205
|
+
// Stateless mode (`--token`) does not support any context-loader config
|
|
206
|
+
// operations; the saved config lives under `~/.kweaver/` and is foreign
|
|
207
|
+
// to the stateless paradigm.
|
|
208
|
+
try {
|
|
209
|
+
assertNotStatelessForWrite(`context-loader config ${action}`);
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
213
|
+
return 1;
|
|
214
|
+
}
|
|
215
|
+
console.warn(CONTEXT_LOADER_CONFIG_DEPRECATION);
|
|
135
216
|
const active = resolveActivePlatform();
|
|
136
217
|
if (!active) {
|
|
137
218
|
console.error("No platform selected. Set KWEAVER_BASE_URL or run: kweaver auth <platform-url>");
|
|
@@ -435,29 +516,24 @@ async function runToolCall(options, args, pretty) {
|
|
|
435
516
|
async function runKnSearch(options, args, pretty) {
|
|
436
517
|
let query;
|
|
437
518
|
let onlySchema = false;
|
|
438
|
-
let knIdOverride;
|
|
439
519
|
for (let i = 0; i < args.length; i += 1) {
|
|
440
520
|
const arg = args[i];
|
|
441
521
|
if (arg === "--only-schema") {
|
|
442
522
|
onlySchema = true;
|
|
443
523
|
}
|
|
444
|
-
else if ((arg === "--kn-id" || arg === "-k") && args[i + 1]) {
|
|
445
|
-
knIdOverride = args[i + 1];
|
|
446
|
-
i += 1;
|
|
447
|
-
}
|
|
448
524
|
else if (!arg.startsWith("-") && !query) {
|
|
449
525
|
query = arg;
|
|
450
526
|
}
|
|
451
527
|
}
|
|
452
528
|
if (!query) {
|
|
453
|
-
console.error("Usage: kweaver context-loader kn-search <
|
|
529
|
+
console.error("Usage: kweaver context-loader kn-search <kn-id> <query> [--only-schema]");
|
|
454
530
|
return 1;
|
|
455
531
|
}
|
|
456
532
|
const raw = await knSearchHttp({
|
|
457
533
|
baseUrl: options.baseUrl,
|
|
458
534
|
accessToken: options.accessToken,
|
|
459
535
|
businessDomain: options.businessDomain,
|
|
460
|
-
knId:
|
|
536
|
+
knId: options.knId,
|
|
461
537
|
query,
|
|
462
538
|
onlySchema,
|
|
463
539
|
});
|
|
@@ -7,6 +7,9 @@ import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/
|
|
|
7
7
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
8
8
|
import { getDataflowLogsPage, listDataflowRuns, listDataflows, runDataflowWithFile, runDataflowWithRemoteUrl, } from "../api/dataflow2.js";
|
|
9
9
|
import { createDataflow } from "../api/dataflow.js";
|
|
10
|
+
import { createVegaResource } from "../api/vega.js";
|
|
11
|
+
import { createKnowledgeNetwork } from "../api/knowledge-networks.js";
|
|
12
|
+
import { loadTemplate, listTemplates, renderTemplate, generateSourceIdentifier, getTemplatesDir, } from "../utils/template-loader.js";
|
|
10
13
|
function renderTable(rows) {
|
|
11
14
|
if (rows.length === 0)
|
|
12
15
|
return "";
|
|
@@ -101,26 +104,6 @@ export async function runDataflowCommand(args) {
|
|
|
101
104
|
.strict()
|
|
102
105
|
.fail((message, error) => {
|
|
103
106
|
throw error ?? new Error(message);
|
|
104
|
-
})
|
|
105
|
-
.command("create <json>", "Create a new dataflow (DAG) from a JSON definition", (command) => command
|
|
106
|
-
.positional("json", {
|
|
107
|
-
type: "string",
|
|
108
|
-
describe: "JSON body string or @file-path to read from file",
|
|
109
|
-
})
|
|
110
|
-
.option("biz-domain", { alias: "bd", type: "string" }), async (argv) => {
|
|
111
|
-
exitCode = await with401RefreshRetry(async () => {
|
|
112
|
-
const base = await requireTokenAndBusinessDomain(argv.bizDomain);
|
|
113
|
-
let raw = argv.json;
|
|
114
|
-
if (raw.startsWith("@")) {
|
|
115
|
-
const filePath = raw.slice(1);
|
|
116
|
-
await access(filePath, constants.R_OK);
|
|
117
|
-
raw = (await readFile(filePath, "utf8")).toString();
|
|
118
|
-
}
|
|
119
|
-
const body = JSON.parse(raw);
|
|
120
|
-
const dagId = await createDataflow({ ...base, body });
|
|
121
|
-
console.log(JSON.stringify({ id: dagId }, null, 2));
|
|
122
|
-
return 0;
|
|
123
|
-
});
|
|
124
107
|
})
|
|
125
108
|
.command("list", "List all dataflows", (command) => command
|
|
126
109
|
.option("biz-domain", {
|
|
@@ -280,6 +263,197 @@ export async function runDataflowCommand(args) {
|
|
|
280
263
|
}
|
|
281
264
|
return 0;
|
|
282
265
|
});
|
|
266
|
+
})
|
|
267
|
+
.command("templates", "List all available templates", {
|
|
268
|
+
json: { type: "boolean", default: false, describe: "Output as JSON" },
|
|
269
|
+
}, (argv) => {
|
|
270
|
+
const templatesDir = getTemplatesDir();
|
|
271
|
+
return Promise.all([
|
|
272
|
+
listTemplates("dataset", templatesDir),
|
|
273
|
+
listTemplates("bkn", templatesDir),
|
|
274
|
+
listTemplates("dataflow", templatesDir),
|
|
275
|
+
]).then(([datasetTemplates, bknTemplates, dataflowTemplates]) => {
|
|
276
|
+
if (argv.json) {
|
|
277
|
+
console.log(JSON.stringify({
|
|
278
|
+
dataset: datasetTemplates,
|
|
279
|
+
bkn: bknTemplates,
|
|
280
|
+
dataflow: dataflowTemplates,
|
|
281
|
+
}, null, 2));
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
console.log("Dataset Templates:");
|
|
285
|
+
for (const t of datasetTemplates) {
|
|
286
|
+
console.log(` - ${t.name.padEnd(18)} ${t.description}`);
|
|
287
|
+
}
|
|
288
|
+
console.log("");
|
|
289
|
+
console.log("BKN Templates:");
|
|
290
|
+
for (const t of bknTemplates) {
|
|
291
|
+
console.log(` - ${t.name.padEnd(18)} ${t.description}`);
|
|
292
|
+
}
|
|
293
|
+
console.log("");
|
|
294
|
+
console.log("Dataflow Templates:");
|
|
295
|
+
for (const t of dataflowTemplates) {
|
|
296
|
+
console.log(` - ${t.name.padEnd(18)} ${t.description}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
})
|
|
301
|
+
.command("create-dataset", "Create a dataset from a template", (command) => command
|
|
302
|
+
.option("template", { type: "string", demandOption: true, describe: "Template name" })
|
|
303
|
+
.option("set", { type: "array", string: true, describe: "Set parameter (key=value), can be used multiple times" })
|
|
304
|
+
.option("json", { type: "boolean", default: false, describe: "Output as JSON" })
|
|
305
|
+
.option("biz-domain", { alias: "bd", type: "string" }), async (argv) => {
|
|
306
|
+
exitCode = await with401RefreshRetry(async () => {
|
|
307
|
+
const base = await requireTokenAndBusinessDomain(argv.bizDomain);
|
|
308
|
+
const templatesDir = getTemplatesDir();
|
|
309
|
+
// Parse --set arguments
|
|
310
|
+
const args = {};
|
|
311
|
+
if (argv.set) {
|
|
312
|
+
for (const item of argv.set) {
|
|
313
|
+
const eqIdx = item.indexOf("=");
|
|
314
|
+
if (eqIdx > 0) {
|
|
315
|
+
const key = item.slice(0, eqIdx);
|
|
316
|
+
const value = item.slice(eqIdx + 1);
|
|
317
|
+
args[key] = value;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// Load template
|
|
322
|
+
const loaded = await loadTemplate(argv.template, "dataset", templatesDir);
|
|
323
|
+
if (!loaded) {
|
|
324
|
+
console.error(`Template not found: ${argv.template}`);
|
|
325
|
+
return 1;
|
|
326
|
+
}
|
|
327
|
+
// Auto-generate source_identifier if not provided
|
|
328
|
+
if (!args["source_identifier"]) {
|
|
329
|
+
const prefixMap = {
|
|
330
|
+
"document": "dataflow_document",
|
|
331
|
+
"document-content": "dataflow_content",
|
|
332
|
+
"document-element": "dataflow_element",
|
|
333
|
+
};
|
|
334
|
+
const prefix = prefixMap[loaded.manifest.name] || "dataflow";
|
|
335
|
+
args["source_identifier"] = generateSourceIdentifier(prefix);
|
|
336
|
+
}
|
|
337
|
+
// Render template
|
|
338
|
+
const rendered = renderTemplate(loaded.template, loaded.manifest, args);
|
|
339
|
+
// Create dataset via API
|
|
340
|
+
const response = await createVegaResource({
|
|
341
|
+
...base,
|
|
342
|
+
body: JSON.stringify(rendered),
|
|
343
|
+
});
|
|
344
|
+
const result = JSON.parse(response);
|
|
345
|
+
if (argv.json) {
|
|
346
|
+
console.log(JSON.stringify({ success: true, id: result.id, name: args.name }, null, 2));
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
console.log(`dataset created: id=${result.id}`);
|
|
350
|
+
}
|
|
351
|
+
return 0;
|
|
352
|
+
});
|
|
353
|
+
})
|
|
354
|
+
.command("create-bkn", "Create a BKN (knowledge network) from a template", (command) => command
|
|
355
|
+
.option("template", { type: "string", demandOption: true, describe: "Template name" })
|
|
356
|
+
.option("set", { type: "array", string: true, describe: "Set parameter (key=value), can be used multiple times" })
|
|
357
|
+
.option("json", { type: "boolean", default: false, describe: "Output as JSON" })
|
|
358
|
+
.option("biz-domain", { alias: "bd", type: "string" }), async (argv) => {
|
|
359
|
+
exitCode = await with401RefreshRetry(async () => {
|
|
360
|
+
const base = await requireTokenAndBusinessDomain(argv.bizDomain);
|
|
361
|
+
const templatesDir = getTemplatesDir();
|
|
362
|
+
// Parse --set arguments
|
|
363
|
+
const args = {};
|
|
364
|
+
if (argv.set) {
|
|
365
|
+
for (const item of argv.set) {
|
|
366
|
+
const eqIdx = item.indexOf("=");
|
|
367
|
+
if (eqIdx > 0) {
|
|
368
|
+
const key = item.slice(0, eqIdx);
|
|
369
|
+
const value = item.slice(eqIdx + 1);
|
|
370
|
+
args[key] = value;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// Load template
|
|
375
|
+
const loaded = await loadTemplate(argv.template, "bkn", templatesDir);
|
|
376
|
+
if (!loaded) {
|
|
377
|
+
console.error(`Template not found: ${argv.template}`);
|
|
378
|
+
return 1;
|
|
379
|
+
}
|
|
380
|
+
// Render template
|
|
381
|
+
const rendered = renderTemplate(loaded.template, loaded.manifest, args);
|
|
382
|
+
rendered.business_domain = base.businessDomain;
|
|
383
|
+
// Create BKN via API
|
|
384
|
+
const response = await createKnowledgeNetwork({
|
|
385
|
+
...base,
|
|
386
|
+
body: JSON.stringify(rendered),
|
|
387
|
+
validate_dependency: false,
|
|
388
|
+
});
|
|
389
|
+
const result = JSON.parse(response);
|
|
390
|
+
if (argv.json) {
|
|
391
|
+
console.log(JSON.stringify({ success: true, id: result.id, name: args.name }, null, 2));
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
console.log(`bkn created: id=${result.id}`);
|
|
395
|
+
}
|
|
396
|
+
return 0;
|
|
397
|
+
});
|
|
398
|
+
})
|
|
399
|
+
.command("create [json]", "Create a new dataflow (DAG) from a JSON definition or template", (command) => command
|
|
400
|
+
.positional("json", {
|
|
401
|
+
type: "string",
|
|
402
|
+
describe: "JSON body string or @file-path to read from file",
|
|
403
|
+
})
|
|
404
|
+
.option("template", { type: "string", describe: "Template name (use instead of json)" })
|
|
405
|
+
.option("set", { type: "array", string: true, describe: "Set parameter (key=value), can be used multiple times" })
|
|
406
|
+
.option("biz-domain", { alias: "bd", type: "string" })
|
|
407
|
+
.check((argv) => {
|
|
408
|
+
const hasJson = typeof argv.json === "string";
|
|
409
|
+
const hasTemplate = typeof argv.template === "string";
|
|
410
|
+
if (hasJson && hasTemplate) {
|
|
411
|
+
throw new Error("Cannot use both json and --template");
|
|
412
|
+
}
|
|
413
|
+
if (!hasJson && !hasTemplate) {
|
|
414
|
+
throw new Error("Either json or --template is required");
|
|
415
|
+
}
|
|
416
|
+
return true;
|
|
417
|
+
}), async (argv) => {
|
|
418
|
+
exitCode = await with401RefreshRetry(async () => {
|
|
419
|
+
const base = await requireTokenAndBusinessDomain(argv.bizDomain);
|
|
420
|
+
let body;
|
|
421
|
+
if (argv.template) {
|
|
422
|
+
// Use template
|
|
423
|
+
const templatesDir = getTemplatesDir();
|
|
424
|
+
// Parse --set arguments
|
|
425
|
+
const args = {};
|
|
426
|
+
if (argv.set) {
|
|
427
|
+
for (const item of argv.set) {
|
|
428
|
+
const eqIdx = item.indexOf("=");
|
|
429
|
+
if (eqIdx > 0) {
|
|
430
|
+
const key = item.slice(0, eqIdx);
|
|
431
|
+
const value = item.slice(eqIdx + 1);
|
|
432
|
+
args[key] = value;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
const loaded = await loadTemplate(argv.template, "dataflow", templatesDir);
|
|
437
|
+
if (!loaded) {
|
|
438
|
+
console.error(`Template not found: ${argv.template}`);
|
|
439
|
+
return 1;
|
|
440
|
+
}
|
|
441
|
+
body = renderTemplate(loaded.template, loaded.manifest, args);
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
// Use JSON
|
|
445
|
+
let raw = argv.json;
|
|
446
|
+
if (raw.startsWith("@")) {
|
|
447
|
+
const filePath = raw.slice(1);
|
|
448
|
+
await access(filePath, constants.R_OK);
|
|
449
|
+
raw = (await readFile(filePath, "utf8")).toString();
|
|
450
|
+
}
|
|
451
|
+
body = JSON.parse(raw);
|
|
452
|
+
}
|
|
453
|
+
const dagId = await createDataflow({ ...base, body });
|
|
454
|
+
console.log(JSON.stringify({ id: dagId }, null, 2));
|
|
455
|
+
return 0;
|
|
456
|
+
});
|
|
283
457
|
})
|
|
284
458
|
.demandCommand(1);
|
|
285
459
|
try {
|
package/dist/commands/ds.d.ts
CHANGED
|
@@ -5,13 +5,35 @@ export declare function parseDsListArgs(args: string[]): {
|
|
|
5
5
|
businessDomain: string;
|
|
6
6
|
pretty: boolean;
|
|
7
7
|
};
|
|
8
|
+
/**
|
|
9
|
+
* Match candidate signature against a list response (the kind returned by
|
|
10
|
+
* `listDatasources`). Connection metadata lives under `bin_data` — host,
|
|
11
|
+
* port, account, plus type-specific fields (`database_name` for MySQL etc.).
|
|
12
|
+
*
|
|
13
|
+
* Exported for unit testing.
|
|
14
|
+
*/
|
|
15
|
+
export interface DsMatchSignature {
|
|
16
|
+
type: string;
|
|
17
|
+
host: string;
|
|
18
|
+
port: number;
|
|
19
|
+
database: string;
|
|
20
|
+
account: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface DsMatchHit {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
matchedByName: boolean;
|
|
27
|
+
matchedByTuple: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function findExistingDatasource(listBody: string, sig: DsMatchSignature): DsMatchHit | undefined;
|
|
30
|
+
export declare function findDatasourceIdByName(listBody: string, name: string): string | undefined;
|
|
8
31
|
export declare function parseImportCsvArgs(args: string[]): {
|
|
9
32
|
datasourceId: string;
|
|
10
33
|
files: string;
|
|
11
34
|
tablePrefix: string;
|
|
12
35
|
batchSize: number;
|
|
13
36
|
businessDomain: string;
|
|
14
|
-
recreate: boolean;
|
|
15
37
|
};
|
|
16
38
|
export declare function resolveFiles(pattern: string): Promise<string[]>;
|
|
17
39
|
export interface ImportCsvResult {
|