@kweaver-ai/kweaver-sdk 0.6.10 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -5
- package/README.zh.md +34 -4
- package/dist/api/context-loader.d.ts +45 -10
- package/dist/api/context-loader.js +43 -8
- package/dist/api/semantic-search.d.ts +9 -0
- package/dist/api/semantic-search.js +19 -0
- package/dist/api/skills.js +10 -8
- package/dist/api/toolboxes.d.ts +12 -0
- package/dist/api/toolboxes.js +43 -1
- package/dist/cli.js +67 -28
- package/dist/commands/auth.js +43 -3
- package/dist/commands/bkn-ops.d.ts +4 -0
- package/dist/commands/bkn-ops.js +136 -62
- package/dist/commands/bkn-query.js +7 -2
- package/dist/commands/config.js +8 -0
- package/dist/commands/context-loader.js +340 -36
- package/dist/commands/ds.d.ts +23 -0
- package/dist/commands/ds.js +116 -18
- package/dist/commands/skill.js +26 -6
- package/dist/commands/toolbox.d.ts +15 -0
- package/dist/commands/toolbox.js +131 -1
- package/dist/config/stateless.d.ts +13 -0
- package/dist/config/stateless.js +20 -0
- package/dist/config/store.js +7 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/resources/bkn.d.ts +2 -1
- package/dist/resources/bkn.js +19 -7
- package/dist/resources/context-loader.d.ts +4 -3
- package/dist/resources/context-loader.js +8 -5
- package/dist/resources/toolboxes.d.ts +15 -0
- package/dist/resources/toolboxes.js +15 -1
- package/dist/utils/skill-bundle.d.ts +5 -0
- package/dist/utils/skill-bundle.js +74 -0
- package/package.json +2 -1
package/dist/commands/ds.js
CHANGED
|
@@ -37,7 +37,10 @@ Subcommands:
|
|
|
37
37
|
delete <id> [-y] Delete a datasource
|
|
38
38
|
tables <id> [--keyword X] List tables with columns
|
|
39
39
|
connect <db_type> <host> <port> <database> --account X --password Y [--schema Z] [--name N]
|
|
40
|
+
[--reuse-existing|--force-new]
|
|
40
41
|
Test connectivity, register datasource, and discover tables.
|
|
42
|
+
By default reuses an existing ds with the same (type, host, port, database, account)
|
|
43
|
+
instead of creating a duplicate. --force-new always creates a new entry.
|
|
41
44
|
import-csv <ds-id> --files <glob_or_list> [--table-prefix X] [--batch-size N]
|
|
42
45
|
Import CSV files into datasource tables via dataflow API.`);
|
|
43
46
|
return 0;
|
|
@@ -206,6 +209,52 @@ async function runDsTablesCommand(args) {
|
|
|
206
209
|
console.log(formatCallOutput(body, pretty));
|
|
207
210
|
return 0;
|
|
208
211
|
}
|
|
212
|
+
export function findExistingDatasource(listBody, sig) {
|
|
213
|
+
const parsed = JSON.parse(listBody);
|
|
214
|
+
const entries = Array.isArray(parsed) ? parsed : (parsed.entries ?? []);
|
|
215
|
+
const tupleMatch = entries.find((e) => e.id &&
|
|
216
|
+
e.type === sig.type &&
|
|
217
|
+
e.bin_data?.host === sig.host &&
|
|
218
|
+
Number(e.bin_data?.port) === Number(sig.port) &&
|
|
219
|
+
e.bin_data?.database_name === sig.database &&
|
|
220
|
+
e.bin_data?.account === sig.account);
|
|
221
|
+
if (tupleMatch) {
|
|
222
|
+
return {
|
|
223
|
+
id: String(tupleMatch.id),
|
|
224
|
+
name: String(tupleMatch.name ?? ""),
|
|
225
|
+
matchedByName: tupleMatch.name === sig.name,
|
|
226
|
+
matchedByTuple: true,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
if (sig.name) {
|
|
230
|
+
const nameMatch = entries.find((e) => e.id && e.name === sig.name);
|
|
231
|
+
if (nameMatch) {
|
|
232
|
+
return {
|
|
233
|
+
id: String(nameMatch.id),
|
|
234
|
+
name: String(nameMatch.name),
|
|
235
|
+
matchedByName: true,
|
|
236
|
+
matchedByTuple: false,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
export function findDatasourceIdByName(listBody, name) {
|
|
243
|
+
const parsed = JSON.parse(listBody);
|
|
244
|
+
const entries = Array.isArray(parsed) ? parsed : (parsed.entries ?? []);
|
|
245
|
+
const hit = entries.find((e) => e.id && e.name === name);
|
|
246
|
+
return hit?.id ? String(hit.id) : undefined;
|
|
247
|
+
}
|
|
248
|
+
function isDuplicateNameError(err) {
|
|
249
|
+
if (!err || typeof err !== "object")
|
|
250
|
+
return false;
|
|
251
|
+
// HttpError.message is just "HTTP 400 ..."; the description lives in body.
|
|
252
|
+
const status = "status" in err ? Number(err.status) : NaN;
|
|
253
|
+
const body = "body" in err ? String(err.body) : "";
|
|
254
|
+
if (status !== 400)
|
|
255
|
+
return false;
|
|
256
|
+
return /数据源名称已存在|datasource name.*exist|already exists/i.test(body);
|
|
257
|
+
}
|
|
209
258
|
async function runDsConnectCommand(args) {
|
|
210
259
|
let dbType = "";
|
|
211
260
|
let host = "";
|
|
@@ -215,6 +264,7 @@ async function runDsConnectCommand(args) {
|
|
|
215
264
|
let password = "";
|
|
216
265
|
let schema;
|
|
217
266
|
let name;
|
|
267
|
+
let forceNew = false;
|
|
218
268
|
for (let i = 0; i < args.length; i += 1) {
|
|
219
269
|
const arg = args[i];
|
|
220
270
|
if (arg === "--account" && args[i + 1]) {
|
|
@@ -233,6 +283,14 @@ async function runDsConnectCommand(args) {
|
|
|
233
283
|
name = args[++i];
|
|
234
284
|
continue;
|
|
235
285
|
}
|
|
286
|
+
if (arg === "--force-new") {
|
|
287
|
+
forceNew = true;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (arg === "--reuse-existing") {
|
|
291
|
+
forceNew = false;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
236
294
|
if (!arg.startsWith("-")) {
|
|
237
295
|
if (!dbType)
|
|
238
296
|
dbType = arg;
|
|
@@ -245,7 +303,7 @@ async function runDsConnectCommand(args) {
|
|
|
245
303
|
}
|
|
246
304
|
}
|
|
247
305
|
if (!dbType || !host || !database || !account || !password) {
|
|
248
|
-
console.error("Usage: kweaver ds connect <db_type> <host> <port> <database> --account X --password Y [--schema Z] [--name N]");
|
|
306
|
+
console.error("Usage: kweaver ds connect <db_type> <host> <port> <database> --account X --password Y [--schema Z] [--name N] [--reuse-existing|--force-new]");
|
|
249
307
|
return 1;
|
|
250
308
|
}
|
|
251
309
|
if (Number.isNaN(port) || port < 1) {
|
|
@@ -254,6 +312,28 @@ async function runDsConnectCommand(args) {
|
|
|
254
312
|
}
|
|
255
313
|
const token = await ensureValidToken();
|
|
256
314
|
const base = { baseUrl: token.baseUrl, accessToken: token.accessToken };
|
|
315
|
+
const dsName = name ?? database;
|
|
316
|
+
// Pre-flight dedup: connection-tuple match is the silent-orphan vector.
|
|
317
|
+
// Backend already rejects duplicate names with 400, but won't notice
|
|
318
|
+
// tuple collisions, so we own that check.
|
|
319
|
+
if (!forceNew) {
|
|
320
|
+
const listBody = await listDatasources({ ...base });
|
|
321
|
+
const hit = findExistingDatasource(listBody, {
|
|
322
|
+
type: dbType,
|
|
323
|
+
host,
|
|
324
|
+
port,
|
|
325
|
+
database,
|
|
326
|
+
account,
|
|
327
|
+
name: dsName,
|
|
328
|
+
});
|
|
329
|
+
if (hit) {
|
|
330
|
+
const why = hit.matchedByTuple
|
|
331
|
+
? "matched by (type,host,port,database,account)"
|
|
332
|
+
: "matched by --name";
|
|
333
|
+
console.error(`Reusing existing datasource ${hit.id} (${hit.name}); ${why}. Use --force-new to override.`);
|
|
334
|
+
return printDsConnectOutput(base, hit.id);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
257
337
|
console.error("Testing connectivity ...");
|
|
258
338
|
await testDatasource({
|
|
259
339
|
...base,
|
|
@@ -265,27 +345,45 @@ async function runDsConnectCommand(args) {
|
|
|
265
345
|
password,
|
|
266
346
|
schema,
|
|
267
347
|
});
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
348
|
+
let dsId = "";
|
|
349
|
+
try {
|
|
350
|
+
const createBody = await createDatasource({
|
|
351
|
+
...base,
|
|
352
|
+
name: dsName,
|
|
353
|
+
type: dbType,
|
|
354
|
+
host,
|
|
355
|
+
port,
|
|
356
|
+
database,
|
|
357
|
+
account,
|
|
358
|
+
password,
|
|
359
|
+
schema,
|
|
360
|
+
});
|
|
361
|
+
dsId = extractDatasourceId(createBody);
|
|
362
|
+
}
|
|
363
|
+
catch (err) {
|
|
364
|
+
// Backend checks name uniqueness but not tuple. If we raced another caller
|
|
365
|
+
// (or tuple match got disabled by --force-new and the name still collides),
|
|
366
|
+
// turn the raw 400 into a useful pointer to the existing id.
|
|
367
|
+
if (isDuplicateNameError(err)) {
|
|
368
|
+
// Backend rejected the name; look it up specifically (not by tuple —
|
|
369
|
+
// sibling ds sharing the same connection would mislead the pointer).
|
|
370
|
+
const listBody = await listDatasources({ ...base });
|
|
371
|
+
const existingId = findDatasourceIdByName(listBody, dsName);
|
|
372
|
+
if (existingId) {
|
|
373
|
+
console.error(`Datasource name '${dsName}' already exists as ${existingId}. Re-run without --force-new to reuse it, or pick a different --name.`);
|
|
374
|
+
return 1;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
throw err;
|
|
378
|
+
}
|
|
281
379
|
if (!dsId) {
|
|
282
380
|
console.error("Failed to get datasource ID from create response");
|
|
283
381
|
return 1;
|
|
284
382
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
});
|
|
383
|
+
return printDsConnectOutput(base, dsId);
|
|
384
|
+
}
|
|
385
|
+
async function printDsConnectOutput(base, dsId) {
|
|
386
|
+
const tablesBody = await listTablesWithColumns({ ...base, id: dsId });
|
|
289
387
|
const tables = JSON.parse(tablesBody);
|
|
290
388
|
const output = {
|
|
291
389
|
datasource_id: dsId,
|
package/dist/commands/skill.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { basename, dirname, resolve } from "node:path";
|
|
3
3
|
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
4
4
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
5
|
-
import { deleteSkill, downloadSkill, fetchSkillContent, fetchSkillFile, getSkill, getSkillContentIndex, installSkillArchive, listSkillMarket, listSkills, readSkillFile,
|
|
5
|
+
import { deleteSkill, downloadSkill, fetchSkillContent, fetchSkillFile, getSkill, getSkillContentIndex, installSkillArchive, listSkillMarket, listSkills, readSkillFile, registerSkillZip, updateSkillStatus, } from "../api/skills.js";
|
|
6
|
+
import { bundleSkillDirectoryToZip, bundleSkillFileToZip } from "../utils/skill-bundle.js";
|
|
6
7
|
function printSkillHelp(subcommand) {
|
|
7
8
|
if (subcommand === "list") {
|
|
8
9
|
console.log(`kweaver skill list [--name kw] [--source src] [--status status] [--create-user user]
|
|
@@ -20,7 +21,15 @@ function printSkillHelp(subcommand) {
|
|
|
20
21
|
}
|
|
21
22
|
if (subcommand === "register") {
|
|
22
23
|
console.log(`kweaver skill register (--content-file <path> | --zip-file <path>)
|
|
23
|
-
[--source src] [--extend-info json] [-bd value] [--pretty|--compact]
|
|
24
|
+
[--source src] [--extend-info json] [-bd value] [--pretty|--compact]
|
|
25
|
+
|
|
26
|
+
--content-file accepts either:
|
|
27
|
+
- a single file named SKILL.md (auto-bundled into a 1-file zip)
|
|
28
|
+
- a skill directory containing SKILL.md (bundled into a zip)
|
|
29
|
+
Both paths upload as multipart zip; the backend's file_type=content
|
|
30
|
+
registration is unreliable (publish-then-read returns 404) so the CLI
|
|
31
|
+
always goes through zip.
|
|
32
|
+
--zip-file accepts a pre-built .zip with SKILL.md at the archive root.`);
|
|
24
33
|
return;
|
|
25
34
|
}
|
|
26
35
|
if (subcommand === "set-status" || subcommand === "status") {
|
|
@@ -54,6 +63,7 @@ Subcommands:
|
|
|
54
63
|
market [--name kw] [--source src] [--page N] [--page-size N] [-bd value]
|
|
55
64
|
get <skill-id> [-bd value]
|
|
56
65
|
register --content-file <path> | --zip-file <path> [--source src] [--extend-info json]
|
|
66
|
+
(--content-file accepts a file named SKILL.md or a directory; both auto-zip)
|
|
57
67
|
set-status <skill-id> <unpublish|published|offline> [-bd value]
|
|
58
68
|
delete <skill-id> [-y] [-bd value]
|
|
59
69
|
content <skill-id> [--raw] [--output file] [-bd value]
|
|
@@ -394,13 +404,23 @@ export async function runSkillCommand(args) {
|
|
|
394
404
|
if (subcommand === "register") {
|
|
395
405
|
const opts = parseSkillRegisterArgs(rest);
|
|
396
406
|
if (opts.contentFile) {
|
|
397
|
-
|
|
398
|
-
|
|
407
|
+
// Always bundle into zip — the backend's file_type=content path
|
|
408
|
+
// doesn't write skill_file_index, so SKILL.md is unreachable
|
|
409
|
+
// after publish via /skills/:id/content. Going through zip
|
|
410
|
+
// (single SKILL.md or full directory) is the only path that
|
|
411
|
+
// produces a readable skill end-to-end.
|
|
412
|
+
const abs = resolve(opts.contentFile);
|
|
413
|
+
const stat = statSync(abs);
|
|
414
|
+
const bytes = stat.isDirectory()
|
|
415
|
+
? await bundleSkillDirectoryToZip(abs)
|
|
416
|
+
: await bundleSkillFileToZip(abs);
|
|
417
|
+
const result = await registerSkillZip({
|
|
399
418
|
...token,
|
|
400
419
|
businessDomain: opts.businessDomain,
|
|
401
|
-
content,
|
|
402
420
|
source: opts.source,
|
|
403
421
|
extendInfo: opts.extendInfo,
|
|
422
|
+
filename: `${basename(abs).replace(/\.zip$/i, "")}.zip`,
|
|
423
|
+
bytes,
|
|
404
424
|
});
|
|
405
425
|
console.log(format(result, opts.pretty));
|
|
406
426
|
return 0;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ImpexType } from "../api/toolboxes.js";
|
|
1
2
|
export declare function runToolboxCommand(args: string[]): Promise<number>;
|
|
2
3
|
export interface ToolboxCreateOptions {
|
|
3
4
|
name: string;
|
|
@@ -12,3 +13,17 @@ export interface ToolboxSetStatusOptions {
|
|
|
12
13
|
businessDomain: string;
|
|
13
14
|
}
|
|
14
15
|
export declare function parseToolboxSetStatusArgs(args: string[]): ToolboxSetStatusOptions;
|
|
16
|
+
export interface ToolboxExportOptions {
|
|
17
|
+
boxId: string;
|
|
18
|
+
output: string;
|
|
19
|
+
type: ImpexType;
|
|
20
|
+
businessDomain: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function parseToolboxExportArgs(args: string[]): ToolboxExportOptions;
|
|
23
|
+
export interface ToolboxImportOptions {
|
|
24
|
+
filePath: string;
|
|
25
|
+
type: ImpexType;
|
|
26
|
+
businessDomain: string;
|
|
27
|
+
pretty: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function parseToolboxImportArgs(args: string[]): ToolboxImportOptions;
|
package/dist/commands/toolbox.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
1
2
|
import { createInterface } from "node:readline";
|
|
2
3
|
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
3
|
-
import { createToolbox, deleteToolbox, listToolboxes, setToolboxStatus } from "../api/toolboxes.js";
|
|
4
|
+
import { createToolbox, deleteToolbox, exportConfig, importConfig, listToolboxes, setToolboxStatus, } from "../api/toolboxes.js";
|
|
4
5
|
import { formatCallOutput } from "./call.js";
|
|
5
6
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
7
|
+
const VALID_IMPEX_TYPES = new Set(["toolbox", "mcp", "operator"]);
|
|
6
8
|
const HELP = `kweaver toolbox
|
|
7
9
|
|
|
8
10
|
Subcommands:
|
|
@@ -11,6 +13,8 @@ Subcommands:
|
|
|
11
13
|
publish <box-id> Publish a toolbox (status=published)
|
|
12
14
|
unpublish <box-id> Unpublish (status=draft)
|
|
13
15
|
delete <box-id> [-y|--yes] Delete a toolbox
|
|
16
|
+
export <box-id> [-o <file>|-] [--type toolbox|mcp|operator] Export toolbox config (.adp JSON)
|
|
17
|
+
import <file> [--type toolbox|mcp|operator] Import a previously exported config
|
|
14
18
|
|
|
15
19
|
Options:
|
|
16
20
|
-bd, --biz-domain <s> Business domain (default: bd_public)
|
|
@@ -33,6 +37,10 @@ export async function runToolboxCommand(args) {
|
|
|
33
37
|
return runToolboxSetStatus(rest, "draft");
|
|
34
38
|
if (subcommand === "delete")
|
|
35
39
|
return runToolboxDelete(rest);
|
|
40
|
+
if (subcommand === "export")
|
|
41
|
+
return runToolboxExport(rest);
|
|
42
|
+
if (subcommand === "import")
|
|
43
|
+
return runToolboxImport(rest);
|
|
36
44
|
return Promise.resolve(-1);
|
|
37
45
|
};
|
|
38
46
|
try {
|
|
@@ -254,3 +262,125 @@ async function runToolboxDelete(args) {
|
|
|
254
262
|
console.error(`Deleted toolbox ${boxId}`);
|
|
255
263
|
return 0;
|
|
256
264
|
}
|
|
265
|
+
export function parseToolboxExportArgs(args) {
|
|
266
|
+
let boxId = "";
|
|
267
|
+
let output = "";
|
|
268
|
+
let type = "toolbox";
|
|
269
|
+
let businessDomain = "";
|
|
270
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
271
|
+
const a = args[i];
|
|
272
|
+
if ((a === "-o" || a === "--output") && args[i + 1] !== undefined) {
|
|
273
|
+
output = args[++i];
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (a === "--type" && args[i + 1]) {
|
|
277
|
+
const v = args[++i];
|
|
278
|
+
if (!VALID_IMPEX_TYPES.has(v)) {
|
|
279
|
+
throw new Error(`--type must be one of: ${[...VALID_IMPEX_TYPES].join(", ")}`);
|
|
280
|
+
}
|
|
281
|
+
type = v;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
285
|
+
businessDomain = args[++i];
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (!a.startsWith("-")) {
|
|
289
|
+
boxId = a;
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (!boxId)
|
|
294
|
+
throw new Error("Missing required argument: <box-id>");
|
|
295
|
+
if (!businessDomain)
|
|
296
|
+
businessDomain = resolveBusinessDomain();
|
|
297
|
+
return { boxId, output, type, businessDomain };
|
|
298
|
+
}
|
|
299
|
+
async function runToolboxExport(args) {
|
|
300
|
+
let opts;
|
|
301
|
+
try {
|
|
302
|
+
opts = parseToolboxExportArgs(args);
|
|
303
|
+
}
|
|
304
|
+
catch (e) {
|
|
305
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
306
|
+
console.error("Usage: kweaver toolbox export <box-id> [-o <file>|-] [--type toolbox|mcp|operator]");
|
|
307
|
+
return 1;
|
|
308
|
+
}
|
|
309
|
+
const token = await ensureValidToken();
|
|
310
|
+
const buf = await exportConfig({
|
|
311
|
+
baseUrl: token.baseUrl,
|
|
312
|
+
accessToken: token.accessToken,
|
|
313
|
+
businessDomain: opts.businessDomain,
|
|
314
|
+
id: opts.boxId,
|
|
315
|
+
type: opts.type,
|
|
316
|
+
});
|
|
317
|
+
if (opts.output === "-") {
|
|
318
|
+
process.stdout.write(buf);
|
|
319
|
+
if (buf.length === 0 || buf[buf.length - 1] !== 0x0a)
|
|
320
|
+
process.stdout.write("\n");
|
|
321
|
+
return 0;
|
|
322
|
+
}
|
|
323
|
+
const target = opts.output || `${opts.type}_${opts.boxId}.adp`;
|
|
324
|
+
await writeFile(target, buf);
|
|
325
|
+
console.error(`Exported ${opts.type} ${opts.boxId} → ${target} (${buf.byteLength} bytes)`);
|
|
326
|
+
return 0;
|
|
327
|
+
}
|
|
328
|
+
export function parseToolboxImportArgs(args) {
|
|
329
|
+
let filePath = "";
|
|
330
|
+
let type = "toolbox";
|
|
331
|
+
let businessDomain = "";
|
|
332
|
+
let pretty = true;
|
|
333
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
334
|
+
const a = args[i];
|
|
335
|
+
if (a === "--type" && args[i + 1]) {
|
|
336
|
+
const v = args[++i];
|
|
337
|
+
if (!VALID_IMPEX_TYPES.has(v)) {
|
|
338
|
+
throw new Error(`--type must be one of: ${[...VALID_IMPEX_TYPES].join(", ")}`);
|
|
339
|
+
}
|
|
340
|
+
type = v;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
344
|
+
businessDomain = args[++i];
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
if (a === "--pretty") {
|
|
348
|
+
pretty = true;
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (a === "--compact") {
|
|
352
|
+
pretty = false;
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (!a.startsWith("-")) {
|
|
356
|
+
filePath = a;
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (!filePath)
|
|
361
|
+
throw new Error("Missing required argument: <file>");
|
|
362
|
+
if (!businessDomain)
|
|
363
|
+
businessDomain = resolveBusinessDomain();
|
|
364
|
+
return { filePath, type, businessDomain, pretty };
|
|
365
|
+
}
|
|
366
|
+
async function runToolboxImport(args) {
|
|
367
|
+
let opts;
|
|
368
|
+
try {
|
|
369
|
+
opts = parseToolboxImportArgs(args);
|
|
370
|
+
}
|
|
371
|
+
catch (e) {
|
|
372
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
373
|
+
console.error("Usage: kweaver toolbox import <file> [--type toolbox|mcp|operator]");
|
|
374
|
+
return 1;
|
|
375
|
+
}
|
|
376
|
+
const token = await ensureValidToken();
|
|
377
|
+
const body = await importConfig({
|
|
378
|
+
baseUrl: token.baseUrl,
|
|
379
|
+
accessToken: token.accessToken,
|
|
380
|
+
businessDomain: opts.businessDomain,
|
|
381
|
+
filePath: opts.filePath,
|
|
382
|
+
type: opts.type,
|
|
383
|
+
});
|
|
384
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
385
|
+
return 0;
|
|
386
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stateless token mode: user passed --token on the CLI for this invocation.
|
|
3
|
+
*
|
|
4
|
+
* In stateless mode the CLI must not mutate ~/.kweaver/ — we error out from
|
|
5
|
+
* any command that would write tokens, sessions, or per-platform config.
|
|
6
|
+
*
|
|
7
|
+
* KWEAVER_TOKEN env (without --token flag) is NOT considered stateless: the
|
|
8
|
+
* env-var path predates this feature and keeps its existing semantics for
|
|
9
|
+
* backward compatibility. The cli.ts argv parser sets KWEAVER_TOKEN_SOURCE=flag
|
|
10
|
+
* only when --token was passed explicitly.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isStatelessTokenMode(): boolean;
|
|
13
|
+
export declare function assertNotStatelessForWrite(commandName: string): void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stateless token mode: user passed --token on the CLI for this invocation.
|
|
3
|
+
*
|
|
4
|
+
* In stateless mode the CLI must not mutate ~/.kweaver/ — we error out from
|
|
5
|
+
* any command that would write tokens, sessions, or per-platform config.
|
|
6
|
+
*
|
|
7
|
+
* KWEAVER_TOKEN env (without --token flag) is NOT considered stateless: the
|
|
8
|
+
* env-var path predates this feature and keeps its existing semantics for
|
|
9
|
+
* backward compatibility. The cli.ts argv parser sets KWEAVER_TOKEN_SOURCE=flag
|
|
10
|
+
* only when --token was passed explicitly.
|
|
11
|
+
*/
|
|
12
|
+
export function isStatelessTokenMode() {
|
|
13
|
+
return process.env.KWEAVER_TOKEN_SOURCE === "flag";
|
|
14
|
+
}
|
|
15
|
+
export function assertNotStatelessForWrite(commandName) {
|
|
16
|
+
if (isStatelessTokenMode()) {
|
|
17
|
+
throw new Error(`Cannot run \`${commandName}\` with --token. The --token flag is for stateless invocations and ` +
|
|
18
|
+
`must not mutate ~/.kweaver/. Drop --token, or use \`kweaver auth login\` to obtain a saved session.`);
|
|
19
|
+
}
|
|
20
|
+
}
|
package/dist/config/store.js
CHANGED
|
@@ -783,8 +783,13 @@ export async function autoSelectBusinessDomain(baseUrl, accessToken, options) {
|
|
|
783
783
|
return selected;
|
|
784
784
|
}
|
|
785
785
|
catch (error) {
|
|
786
|
-
|
|
787
|
-
|
|
786
|
+
// Endpoint may be unavailable on this deployment or for this account
|
|
787
|
+
// type — fall back silently. Set KWEAVER_DEBUG=1 to surface the
|
|
788
|
+
// underlying error during diagnostics.
|
|
789
|
+
if (process.env.KWEAVER_DEBUG) {
|
|
790
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
791
|
+
console.warn(`Business domain list unavailable (${message}); defaulting to bd_public.`);
|
|
792
|
+
}
|
|
788
793
|
return "bd_public";
|
|
789
794
|
}
|
|
790
795
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -35,10 +35,10 @@ export type { ListAgentsOptions, GetAgentOptions, GetAgentByKeyOptions, CreateAg
|
|
|
35
35
|
export { listAgents, getAgent, getAgentByKey, createAgent, updateAgent, deleteAgent, publishAgent, unpublishAgent, } from "./api/agent-list.js";
|
|
36
36
|
export type { ListConversationsOptions, ListMessagesOptions } from "./api/conversations.js";
|
|
37
37
|
export { listConversations, listMessages } from "./api/conversations.js";
|
|
38
|
-
export type { SemanticSearchOptions } from "./api/semantic-search.js";
|
|
39
|
-
export { semanticSearch } from "./api/semantic-search.js";
|
|
40
|
-
export type { ContextLoaderCallOptions,
|
|
41
|
-
export {
|
|
38
|
+
export type { SemanticSearchOptions, KnSearchHttpOptions } from "./api/semantic-search.js";
|
|
39
|
+
export { semanticSearch, knSearchHttp } from "./api/semantic-search.js";
|
|
40
|
+
export type { ContextLoaderCallOptions, SearchSchemaArgs, SearchSchemaScope, SearchSchemaResult, ConditionSpec, QueryObjectInstanceArgs, RelationTypePath, QueryInstanceSubgraphArgs, GetLogicPropertiesValuesArgs, GetActionInfoArgs, FindSkillsArgs, FindSkillsResult, MissingInputParamsError, } from "./api/context-loader.js";
|
|
41
|
+
export { callTool, searchSchema, queryObjectInstance, queryInstanceSubgraph, getLogicPropertiesValues, getActionInfo, findSkills, formatMissingInputParamsHint, validateCondition, validateInstanceIdentity, validateInstanceIdentities, } from "./api/context-loader.js";
|
|
42
42
|
export type { ConfigureOptions } from "./kweaver.js";
|
|
43
43
|
export { configure, search, agents, chat, bkns, weaver, getClient } from "./kweaver.js";
|
|
44
44
|
export type { KWeaverClientOptions, ClientContext } from "./client.js";
|
package/dist/index.js
CHANGED
|
@@ -30,8 +30,8 @@ export { objectTypeQuery, objectTypeProperties, subgraph, actionTypeQuery, actio
|
|
|
30
30
|
export { sendChatRequest, sendChatRequestStream, fetchAgentInfo, buildChatUrl, buildAgentInfoUrl, extractText, } from "./api/agent-chat.js";
|
|
31
31
|
export { listAgents, getAgent, getAgentByKey, createAgent, updateAgent, deleteAgent, publishAgent, unpublishAgent, } from "./api/agent-list.js";
|
|
32
32
|
export { listConversations, listMessages } from "./api/conversations.js";
|
|
33
|
-
export { semanticSearch } from "./api/semantic-search.js";
|
|
34
|
-
export {
|
|
33
|
+
export { semanticSearch, knSearchHttp } from "./api/semantic-search.js";
|
|
34
|
+
export { callTool, searchSchema, queryObjectInstance, queryInstanceSubgraph, getLogicPropertiesValues, getActionInfo, findSkills, formatMissingInputParamsHint, validateCondition, validateInstanceIdentity, validateInstanceIdentities, } from "./api/context-loader.js";
|
|
35
35
|
export { configure, search, agents, chat, bkns, weaver, getClient } from "./kweaver.js";
|
|
36
36
|
export { KWeaverClient } from "./client.js";
|
|
37
37
|
export { KnowledgeNetworksResource } from "./resources/knowledge-networks.js";
|
package/dist/resources/bkn.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export declare class BknResource {
|
|
|
48
48
|
cancelActionLog(knId: string, logId: string): Promise<unknown>;
|
|
49
49
|
/**
|
|
50
50
|
* Search KN schema — finds matching object types, relation types, and action types.
|
|
51
|
-
* Uses
|
|
51
|
+
* Uses the public agent-retrieval HTTP compatibility endpoint.
|
|
52
52
|
*/
|
|
53
53
|
knSearch(knId: string, query: string, opts?: {
|
|
54
54
|
onlySchema?: boolean;
|
|
@@ -56,6 +56,7 @@ export declare class BknResource {
|
|
|
56
56
|
object_types?: unknown[];
|
|
57
57
|
relation_types?: unknown[];
|
|
58
58
|
action_types?: unknown[];
|
|
59
|
+
metric_types?: unknown[];
|
|
59
60
|
nodes?: unknown[];
|
|
60
61
|
}>;
|
|
61
62
|
}
|
package/dist/resources/bkn.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { buildHeaders } from "../api/headers.js";
|
|
2
|
+
import { knSearchHttp } from "../api/semantic-search.js";
|
|
2
3
|
import { objectTypeQuery, objectTypeProperties, subgraph, actionTypeQuery, actionTypeExecute, actionExecutionGet, actionLogsList, actionLogGet, actionLogCancel, } from "../api/ontology-query.js";
|
|
3
4
|
import { fetchTextOrThrow } from "../utils/http.js";
|
|
4
5
|
/** BKN engine resource — instance queries, subgraph, action execution and logs. */
|
|
@@ -88,14 +89,25 @@ export class BknResource {
|
|
|
88
89
|
}
|
|
89
90
|
/**
|
|
90
91
|
* Search KN schema — finds matching object types, relation types, and action types.
|
|
91
|
-
* Uses
|
|
92
|
+
* Uses the public agent-retrieval HTTP compatibility endpoint.
|
|
92
93
|
*/
|
|
93
94
|
async knSearch(knId, query, opts = {}) {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
const raw = await knSearchHttp({
|
|
96
|
+
...this.ctx.base(),
|
|
97
|
+
knId,
|
|
98
|
+
query,
|
|
99
|
+
onlySchema: opts.onlySchema ?? false,
|
|
100
|
+
});
|
|
101
|
+
let parsed;
|
|
102
|
+
try {
|
|
103
|
+
parsed = JSON.parse(raw);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
throw new Error(`kn_search returned non-JSON body (first 200 chars): ${raw.slice(0, 200)}`);
|
|
107
|
+
}
|
|
108
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
109
|
+
throw new Error(`kn_search returned unexpected JSON shape (first 200 chars): ${raw.slice(0, 200)}`);
|
|
110
|
+
}
|
|
111
|
+
return parsed;
|
|
100
112
|
}
|
|
101
113
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SearchSchemaArgs, QueryObjectInstanceArgs, QueryInstanceSubgraphArgs, GetLogicPropertiesValuesArgs, GetActionInfoArgs, FindSkillsArgs, FindSkillsResult } from "../api/context-loader.js";
|
|
2
2
|
import type { ClientContext } from "../client.js";
|
|
3
3
|
export declare class ContextLoaderResource {
|
|
4
4
|
private readonly ctx;
|
|
@@ -6,10 +6,11 @@ export declare class ContextLoaderResource {
|
|
|
6
6
|
private readonly knId;
|
|
7
7
|
constructor(ctx: ClientContext, mcpUrl: string, knId: string);
|
|
8
8
|
private opts;
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
callTool(toolName: string, args: Record<string, unknown>): Promise<unknown>;
|
|
10
|
+
searchSchema(args: SearchSchemaArgs): Promise<unknown>;
|
|
11
11
|
queryInstances(args: QueryObjectInstanceArgs): Promise<unknown>;
|
|
12
12
|
querySubgraph(args: QueryInstanceSubgraphArgs): Promise<unknown>;
|
|
13
13
|
getLogicProperties(args: GetLogicPropertiesValuesArgs): Promise<unknown>;
|
|
14
14
|
getActionInfo(args: GetActionInfoArgs): Promise<unknown>;
|
|
15
|
+
findSkills(args: FindSkillsArgs): Promise<FindSkillsResult>;
|
|
15
16
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { callTool, searchSchema, queryObjectInstance, queryInstanceSubgraph, getLogicPropertiesValues, getActionInfo, findSkills, } from "../api/context-loader.js";
|
|
2
2
|
export class ContextLoaderResource {
|
|
3
3
|
ctx;
|
|
4
4
|
mcpUrl;
|
|
@@ -11,11 +11,11 @@ export class ContextLoaderResource {
|
|
|
11
11
|
opts() {
|
|
12
12
|
return { mcpUrl: this.mcpUrl, knId: this.knId, accessToken: this.ctx.base().accessToken };
|
|
13
13
|
}
|
|
14
|
-
async
|
|
15
|
-
return
|
|
14
|
+
async callTool(toolName, args) {
|
|
15
|
+
return callTool(this.opts(), toolName, args);
|
|
16
16
|
}
|
|
17
|
-
async
|
|
18
|
-
return
|
|
17
|
+
async searchSchema(args) {
|
|
18
|
+
return searchSchema(this.opts(), args);
|
|
19
19
|
}
|
|
20
20
|
async queryInstances(args) {
|
|
21
21
|
return queryObjectInstance(this.opts(), args);
|
|
@@ -29,4 +29,7 @@ export class ContextLoaderResource {
|
|
|
29
29
|
async getActionInfo(args) {
|
|
30
30
|
return getActionInfo(this.opts(), args);
|
|
31
31
|
}
|
|
32
|
+
async findSkills(args) {
|
|
33
|
+
return findSkills(this.opts(), args);
|
|
34
|
+
}
|
|
32
35
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ClientContext } from "../client.js";
|
|
2
|
+
import { type ImpexType } from "../api/toolboxes.js";
|
|
2
3
|
export interface InvokeToolArgs {
|
|
3
4
|
/** Optional headers to forward to the downstream tool. Authorization is
|
|
4
5
|
* auto-injected from the client's access token when omitted; pass `{}` to
|
|
@@ -35,5 +36,19 @@ export declare class ToolboxesResource {
|
|
|
35
36
|
execute(boxId: string, toolId: string, args?: InvokeToolArgs): Promise<string>;
|
|
36
37
|
/** Debug a tool through the toolbox proxy (works on draft/disabled tools too). */
|
|
37
38
|
debug(boxId: string, toolId: string, args?: InvokeToolArgs): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Export a toolbox/mcp/operator config (.adp JSON) as raw bytes.
|
|
41
|
+
*
|
|
42
|
+
* Returned bytes are usually UTF-8 JSON; mirrors the Python SDK's
|
|
43
|
+
* `export_config -> bytes`. Use `new TextDecoder().decode(buf)` if you
|
|
44
|
+
* need a string.
|
|
45
|
+
*/
|
|
46
|
+
exportConfig(id: string, opts?: {
|
|
47
|
+
type?: ImpexType;
|
|
48
|
+
}): Promise<Uint8Array>;
|
|
49
|
+
/** Import a previously exported config from disk. */
|
|
50
|
+
importConfig(filePath: string, opts?: {
|
|
51
|
+
type?: ImpexType;
|
|
52
|
+
}): Promise<string>;
|
|
38
53
|
private injectAuth;
|
|
39
54
|
}
|