@kweaver-ai/kweaver-sdk 0.4.8 → 0.4.10
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 +1 -1
- package/README.zh.md +1 -1
- package/dist/auth/oauth.js +3 -4
- package/dist/cli.js +6 -4
- package/dist/commands/auth.js +20 -10
- package/dist/commands/bkn.d.ts +18 -0
- package/dist/commands/bkn.js +93 -49
- package/dist/config/store.js +5 -3
- package/dist/utils/bkn-encoding.d.ts +32 -0
- package/dist/utils/bkn-encoding.js +152 -0
- package/dist/utils/browser.js +14 -11
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ const results = await cl.search({ query: "hypertension treatment" });
|
|
|
98
98
|
## CLI Reference
|
|
99
99
|
|
|
100
100
|
```
|
|
101
|
-
kweaver auth login
|
|
101
|
+
kweaver auth login <url> [--alias name] [-u user] [-p pass] [--playwright] — also: status, list, use, delete, logout
|
|
102
102
|
kweaver token
|
|
103
103
|
kweaver bkn list/get/stats/export/create/update/delete
|
|
104
104
|
kweaver bkn object-type list/get/create/update/delete/query/properties
|
package/README.zh.md
CHANGED
|
@@ -98,7 +98,7 @@ const results = await cl.search({ query: "高血压 治疗" });
|
|
|
98
98
|
## 命令速查
|
|
99
99
|
|
|
100
100
|
```
|
|
101
|
-
kweaver auth login
|
|
101
|
+
kweaver auth login <url> [--alias name] [-u user] [-p pass] [--playwright] — 另有 status、list、use、delete、logout
|
|
102
102
|
kweaver token
|
|
103
103
|
kweaver bkn list/get/stats/export/create/update/delete
|
|
104
104
|
kweaver bkn object-type list/get/create/update/delete/query/properties
|
package/dist/auth/oauth.js
CHANGED
|
@@ -74,10 +74,9 @@ export async function oauth2Login(baseUrl, options) {
|
|
|
74
74
|
}
|
|
75
75
|
});
|
|
76
76
|
server.listen(port, "127.0.0.1", () => {
|
|
77
|
-
// Step 5: Open browser
|
|
78
|
-
import("
|
|
79
|
-
|
|
80
|
-
exec(`${cmd} "${authUrl}"`);
|
|
77
|
+
// Step 5: Open browser (uses spawn with proper Windows quoting)
|
|
78
|
+
import("../utils/browser.js").then(({ openBrowser }) => {
|
|
79
|
+
openBrowser(authUrl);
|
|
81
80
|
});
|
|
82
81
|
});
|
|
83
82
|
});
|
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ Usage:
|
|
|
33
33
|
kweaver agent get <agent_id> [-bd value] [--pretty]
|
|
34
34
|
kweaver agent get-by-key <key> [-bd value] [--pretty]
|
|
35
35
|
kweaver agent sessions <agent_id> [-bd value] [--limit N] [--pretty]
|
|
36
|
-
kweaver agent history <
|
|
36
|
+
kweaver agent history <conversation_id> [-bd value] [--limit N] [--pretty]
|
|
37
37
|
kweaver agent create [options]
|
|
38
38
|
kweaver agent update <agent_id> [options]
|
|
39
39
|
kweaver agent delete <agent_id> [-bd value]
|
|
@@ -54,10 +54,10 @@ Usage:
|
|
|
54
54
|
kweaver bkn update <kn-id> [options]
|
|
55
55
|
kweaver bkn delete <kn-id> [-y]
|
|
56
56
|
kweaver bkn build <kn-id> [--wait] [--no-wait] [--timeout N]
|
|
57
|
-
kweaver bkn validate <
|
|
57
|
+
kweaver bkn validate <directory> [--detect-encoding|--no-detect-encoding] [--source-encoding name]
|
|
58
58
|
kweaver bkn export <kn-id>
|
|
59
59
|
kweaver bkn stats <kn-id>
|
|
60
|
-
kweaver bkn push <directory> [--branch main] [-bd value]
|
|
60
|
+
kweaver bkn push <directory> [--branch main] [-bd value] [--detect-encoding|--no-detect-encoding] [--source-encoding name]
|
|
61
61
|
kweaver bkn pull <kn-id> [directory] [--branch main] [-bd value]
|
|
62
62
|
kweaver bkn object-type list|get|create|update|delete|query|properties <kn-id> ...
|
|
63
63
|
kweaver bkn relation-type list|get|create|update|delete <kn-id> ...
|
|
@@ -154,7 +154,9 @@ function safeExit(code) {
|
|
|
154
154
|
process.exit(code);
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
-
|
|
157
|
+
import { fileURLToPath } from "node:url";
|
|
158
|
+
import { resolve } from "node:path";
|
|
159
|
+
if (fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
|
|
158
160
|
run(process.argv.slice(2))
|
|
159
161
|
.then((code) => {
|
|
160
162
|
safeExit(code);
|
package/dist/commands/auth.js
CHANGED
|
@@ -4,19 +4,29 @@ export async function runAuthCommand(args) {
|
|
|
4
4
|
const target = args[0];
|
|
5
5
|
const rest = args.slice(1);
|
|
6
6
|
if (!target || target === "--help" || target === "-h") {
|
|
7
|
-
console.log(`kweaver auth login <url>
|
|
8
|
-
kweaver auth <url> Login (shorthand)
|
|
9
|
-
kweaver auth status [url]
|
|
7
|
+
console.log(`kweaver auth login <url> [--alias <name>] [-u user] [-p pass] [--playwright]
|
|
8
|
+
kweaver auth <url> Login (shorthand; same options as login)
|
|
9
|
+
kweaver auth status [url|alias]
|
|
10
10
|
kweaver auth list List saved platforms
|
|
11
|
-
kweaver auth use <url>
|
|
12
|
-
kweaver auth logout [url]
|
|
13
|
-
kweaver auth delete <url>
|
|
11
|
+
kweaver auth use <url|alias> Switch active platform
|
|
12
|
+
kweaver auth logout [url|alias] Logout (clear local token)
|
|
13
|
+
kweaver auth delete <url|alias> Delete saved credentials
|
|
14
|
+
|
|
15
|
+
Login options (browser OAuth2 by default; use -u/-p for headless Playwright):
|
|
16
|
+
--alias <name> Short name for this platform (use with auth use / status / logout)
|
|
17
|
+
-u, --username Username (with -p triggers Playwright login)
|
|
18
|
+
-p, --password Password
|
|
19
|
+
--playwright Force browser (Playwright) login even without -u/-p`);
|
|
14
20
|
return 0;
|
|
15
21
|
}
|
|
16
22
|
if (target === "login") {
|
|
23
|
+
if (rest[0] === "--help" || rest[0] === "-h") {
|
|
24
|
+
console.log(`kweaver auth login <platform-url> [--alias <name>] [-u user] [-p pass] [--playwright]`);
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
17
27
|
const url = rest[0];
|
|
18
|
-
if (!url) {
|
|
19
|
-
console.error("Usage: kweaver auth login <platform-url>");
|
|
28
|
+
if (!url || url.startsWith("-")) {
|
|
29
|
+
console.error("Usage: kweaver auth login <platform-url> [--alias <name>] [-u user] [-p pass] [--playwright]");
|
|
20
30
|
return 1;
|
|
21
31
|
}
|
|
22
32
|
return runAuthCommand([url, ...rest.slice(1)]);
|
|
@@ -182,8 +192,8 @@ kweaver auth delete <url> Delete saved credentials`);
|
|
|
182
192
|
console.log(`Run \`kweaver auth login ${logoutTarget}\` to sign in again.`);
|
|
183
193
|
return 0;
|
|
184
194
|
}
|
|
185
|
-
console.error("Usage: kweaver auth login <platform-url>");
|
|
186
|
-
console.error(" kweaver auth <platform-url> [--alias <name>]");
|
|
195
|
+
console.error("Usage: kweaver auth login <platform-url> [--alias <name>] [-u user] [-p pass] [--playwright]");
|
|
196
|
+
console.error(" kweaver auth <platform-url> [--alias <name>] [-u user] [-p pass] [--playwright]");
|
|
187
197
|
console.error(" kweaver auth status [platform-url|alias]");
|
|
188
198
|
console.error(" kweaver auth list");
|
|
189
199
|
console.error(" kweaver auth use <platform-url|alias>");
|
package/dist/commands/bkn.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type BknEncodingImportOptions } from "../utils/bkn-encoding.js";
|
|
1
2
|
export interface KnListOptions {
|
|
2
3
|
offset: number;
|
|
3
4
|
limit: number;
|
|
@@ -46,6 +47,7 @@ export interface KnPushOptions {
|
|
|
46
47
|
branch: string;
|
|
47
48
|
businessDomain: string;
|
|
48
49
|
pretty: boolean;
|
|
50
|
+
encodingOptions: BknEncodingImportOptions;
|
|
49
51
|
}
|
|
50
52
|
export declare function parseKnPushArgs(args: string[]): KnPushOptions;
|
|
51
53
|
export interface KnPullOptions {
|
|
@@ -64,6 +66,14 @@ export interface KnObjectTypeQueryOptions {
|
|
|
64
66
|
}
|
|
65
67
|
export declare function parseKnObjectTypeQueryArgs(args: string[]): KnObjectTypeQueryOptions;
|
|
66
68
|
export declare function runKnCommand(args: string[]): Promise<number>;
|
|
69
|
+
/** Parse object-type create args: --name --dataview-id --primary-key --display-key [--property '<json>' ...] */
|
|
70
|
+
export declare function parseObjectTypeCreateArgs(args: string[]): {
|
|
71
|
+
knId: string;
|
|
72
|
+
body: string;
|
|
73
|
+
businessDomain: string;
|
|
74
|
+
branch: string;
|
|
75
|
+
pretty: boolean;
|
|
76
|
+
};
|
|
67
77
|
/** Fields merged via GET → modify → PUT (not raw body mode). */
|
|
68
78
|
export interface ObjectTypeMergeFields {
|
|
69
79
|
name?: string;
|
|
@@ -110,6 +120,14 @@ export interface KnActionTypeExecuteOptions {
|
|
|
110
120
|
timeout: number;
|
|
111
121
|
}
|
|
112
122
|
export declare function parseKnActionTypeExecuteArgs(args: string[]): KnActionTypeExecuteOptions;
|
|
123
|
+
/** Parse relation-type create args: --name --source --target [--mapping src:tgt ...] */
|
|
124
|
+
export declare function parseRelationTypeCreateArgs(args: string[]): {
|
|
125
|
+
knId: string;
|
|
126
|
+
body: string;
|
|
127
|
+
businessDomain: string;
|
|
128
|
+
branch: string;
|
|
129
|
+
pretty: boolean;
|
|
130
|
+
};
|
|
113
131
|
export declare function parseKnBuildArgs(args: string[]): {
|
|
114
132
|
knId: string;
|
|
115
133
|
wait: boolean;
|
package/dist/commands/bkn.js
CHANGED
|
@@ -3,6 +3,7 @@ import { spawnSync } from "node:child_process";
|
|
|
3
3
|
import { mkdirSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
import { loadNetwork, allObjects, allRelations, allActions, generateChecksum, validateNetwork } from "@kweaver-ai/bkn";
|
|
6
|
+
import { prepareBknDirectoryForImport, stripBknEncodingCliArgs, } from "../utils/bkn-encoding.js";
|
|
6
7
|
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
7
8
|
import { listKnowledgeNetworks, getKnowledgeNetwork, createKnowledgeNetwork, updateKnowledgeNetwork, deleteKnowledgeNetwork, listObjectTypes, listRelationTypes, listActionTypes, getObjectType, createObjectTypes, updateObjectType, deleteObjectTypes, getRelationType, createRelationTypes, updateRelationType, deleteRelationTypes, buildKnowledgeNetwork, getBuildStatus, } from "../api/knowledge-networks.js";
|
|
8
9
|
import { objectTypeQuery, objectTypeProperties, subgraph, actionTypeQuery, actionTypeExecute, actionExecutionGet, actionLogsList, actionLogGet, actionLogCancel, } from "../api/ontology-query.js";
|
|
@@ -354,12 +355,13 @@ export function parseKnDeleteArgs(args) {
|
|
|
354
355
|
return { knId, businessDomain, yes };
|
|
355
356
|
}
|
|
356
357
|
export function parseKnPushArgs(args) {
|
|
358
|
+
const { rest, options: encodingOptions } = stripBknEncodingCliArgs(args);
|
|
357
359
|
let directory = "";
|
|
358
360
|
let branch = "main";
|
|
359
361
|
let businessDomain = "";
|
|
360
362
|
let pretty = true;
|
|
361
|
-
for (let i = 0; i <
|
|
362
|
-
const arg =
|
|
363
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
364
|
+
const arg = rest[i];
|
|
363
365
|
if (arg === "--help" || arg === "-h") {
|
|
364
366
|
throw new Error("help");
|
|
365
367
|
}
|
|
@@ -394,7 +396,7 @@ export function parseKnPushArgs(args) {
|
|
|
394
396
|
}
|
|
395
397
|
if (!businessDomain)
|
|
396
398
|
businessDomain = resolveBusinessDomain();
|
|
397
|
-
return { directory, branch, businessDomain, pretty };
|
|
399
|
+
return { directory, branch, businessDomain, pretty, encodingOptions };
|
|
398
400
|
}
|
|
399
401
|
export function parseKnPullArgs(args) {
|
|
400
402
|
let knId = "";
|
|
@@ -601,8 +603,8 @@ Subcommands:
|
|
|
601
603
|
update <kn-id> [options] Update a knowledge network
|
|
602
604
|
delete <kn-id> Delete a knowledge network
|
|
603
605
|
build <kn-id> [--wait|--no-wait] [--timeout n] Trigger full build
|
|
604
|
-
validate <directory> Validate
|
|
605
|
-
push <directory> [--branch main] Upload BKN
|
|
606
|
+
validate <directory> [--detect-encoding|--no-detect-encoding] [--source-encoding n] Validate local BKN (no upload)
|
|
607
|
+
push <directory> [--branch main] [--detect-encoding|--no-detect-encoding] [--source-encoding n] Upload BKN as tar
|
|
606
608
|
pull <kn-id> [<directory>] [--branch main] Download BKN tar and extract
|
|
607
609
|
export <kn-id> Export knowledge network (alias for get --export)
|
|
608
610
|
stats <kn-id> Get statistics (alias for get --stats)
|
|
@@ -692,7 +694,7 @@ export async function runKnCommand(args) {
|
|
|
692
694
|
}
|
|
693
695
|
}
|
|
694
696
|
/** Parse object-type create args: --name --dataview-id --primary-key --display-key [--property '<json>' ...] */
|
|
695
|
-
function parseObjectTypeCreateArgs(args) {
|
|
697
|
+
export function parseObjectTypeCreateArgs(args) {
|
|
696
698
|
let name = "";
|
|
697
699
|
let dataviewId = "";
|
|
698
700
|
let primaryKey = "";
|
|
@@ -746,6 +748,7 @@ function parseObjectTypeCreateArgs(args) {
|
|
|
746
748
|
throw new Error("Usage: kweaver bkn object-type create <kn-id> --name X --dataview-id Y --primary-key Z --display-key W");
|
|
747
749
|
}
|
|
748
750
|
const entry = {
|
|
751
|
+
branch,
|
|
749
752
|
name,
|
|
750
753
|
data_source: { type: "data_view", id: dataviewId },
|
|
751
754
|
primary_keys: [primaryKey],
|
|
@@ -762,7 +765,7 @@ function parseObjectTypeCreateArgs(args) {
|
|
|
762
765
|
type: "string",
|
|
763
766
|
}));
|
|
764
767
|
}
|
|
765
|
-
const body = JSON.stringify({ entries: [entry]
|
|
768
|
+
const body = JSON.stringify({ entries: [entry] });
|
|
766
769
|
if (!businessDomain)
|
|
767
770
|
businessDomain = resolveBusinessDomain();
|
|
768
771
|
return { knId, body, businessDomain, branch, pretty };
|
|
@@ -1285,7 +1288,7 @@ kweaver bkn object-type delete <kn-id> <ot-ids> [-y]`);
|
|
|
1285
1288
|
}
|
|
1286
1289
|
}
|
|
1287
1290
|
/** Parse relation-type create args: --name --source --target [--mapping src:tgt ...] */
|
|
1288
|
-
function parseRelationTypeCreateArgs(args) {
|
|
1291
|
+
export function parseRelationTypeCreateArgs(args) {
|
|
1289
1292
|
let name = "";
|
|
1290
1293
|
let source = "";
|
|
1291
1294
|
let target = "";
|
|
@@ -1339,6 +1342,7 @@ function parseRelationTypeCreateArgs(args) {
|
|
|
1339
1342
|
throw new Error("Usage: kweaver bkn relation-type create <kn-id> --name X --source <ot-id> --target <ot-id> [--mapping src:tgt ...]");
|
|
1340
1343
|
}
|
|
1341
1344
|
const entry = {
|
|
1345
|
+
branch,
|
|
1342
1346
|
name,
|
|
1343
1347
|
source_object_type_id: source,
|
|
1344
1348
|
target_object_type_id: target,
|
|
@@ -1348,7 +1352,7 @@ function parseRelationTypeCreateArgs(args) {
|
|
|
1348
1352
|
target_property: { name: t },
|
|
1349
1353
|
})),
|
|
1350
1354
|
};
|
|
1351
|
-
const body = JSON.stringify({ entries: [entry]
|
|
1355
|
+
const body = JSON.stringify({ entries: [entry] });
|
|
1352
1356
|
if (!businessDomain)
|
|
1353
1357
|
businessDomain = resolveBusinessDomain();
|
|
1354
1358
|
return { knId, body, businessDomain, branch, pretty };
|
|
@@ -2194,6 +2198,7 @@ async function runKnCreateFromDsCommand(args) {
|
|
|
2194
2198
|
const pk = detectPrimaryKey(t);
|
|
2195
2199
|
const dk = detectDisplayKey(t, pk);
|
|
2196
2200
|
const entry = {
|
|
2201
|
+
branch: "main",
|
|
2197
2202
|
name: t.name,
|
|
2198
2203
|
data_source: { type: "data_view", id: viewMap[t.name] },
|
|
2199
2204
|
primary_keys: [pk],
|
|
@@ -2204,7 +2209,7 @@ async function runKnCreateFromDsCommand(args) {
|
|
|
2204
2209
|
type: "string",
|
|
2205
2210
|
})),
|
|
2206
2211
|
};
|
|
2207
|
-
const otBody = JSON.stringify({ entries: [entry]
|
|
2212
|
+
const otBody = JSON.stringify({ entries: [entry] });
|
|
2208
2213
|
const otResponse = await createObjectTypes({
|
|
2209
2214
|
...base,
|
|
2210
2215
|
knId,
|
|
@@ -2443,8 +2448,13 @@ export function packDirectoryToTar(dirPath) {
|
|
|
2443
2448
|
encoding: "buffer",
|
|
2444
2449
|
env: { ...process.env, COPYFILE_DISABLE: "1" },
|
|
2445
2450
|
});
|
|
2446
|
-
if (result.error)
|
|
2451
|
+
if (result.error) {
|
|
2452
|
+
if ("code" in result.error && result.error.code === "ENOENT") {
|
|
2453
|
+
throw new Error("tar executable not found. On Windows, ensure tar.exe is in PATH " +
|
|
2454
|
+
"(ships with Windows 10 1803+) or install GNU tar via Git for Windows / scoop.");
|
|
2455
|
+
}
|
|
2447
2456
|
throw result.error;
|
|
2457
|
+
}
|
|
2448
2458
|
if (result.status !== 0) {
|
|
2449
2459
|
throw new Error(`tar pack failed: ${result.stderr?.toString() ?? result.status}`);
|
|
2450
2460
|
}
|
|
@@ -2457,6 +2467,10 @@ export function extractTarToDirectory(tarBuffer, dirPath) {
|
|
|
2457
2467
|
input: tarBuffer,
|
|
2458
2468
|
});
|
|
2459
2469
|
if (result.error) {
|
|
2470
|
+
if ("code" in result.error && result.error.code === "ENOENT") {
|
|
2471
|
+
throw new Error("tar executable not found. On Windows, ensure tar.exe is in PATH " +
|
|
2472
|
+
"(ships with Windows 10 1803+) or install GNU tar via Git for Windows / scoop.");
|
|
2473
|
+
}
|
|
2460
2474
|
throw result.error;
|
|
2461
2475
|
}
|
|
2462
2476
|
if (result.status !== 0) {
|
|
@@ -2470,7 +2484,10 @@ Pack a BKN directory into a tar and upload to import as a knowledge network.
|
|
|
2470
2484
|
Options:
|
|
2471
2485
|
--branch <s> Branch name (default: main)
|
|
2472
2486
|
-bd, --biz-domain Business domain (default: bd_public)
|
|
2473
|
-
--pretty Pretty-print JSON output
|
|
2487
|
+
--pretty Pretty-print JSON output
|
|
2488
|
+
--detect-encoding Detect .bkn encoding and normalize to UTF-8 (default: on)
|
|
2489
|
+
--no-detect-encoding Do not detect; require UTF-8 .bkn files
|
|
2490
|
+
--source-encoding <name> Decode all .bkn files with this encoding (e.g. gb18030); overrides detection`;
|
|
2474
2491
|
const KN_PULL_HELP = `kweaver bkn pull <kn-id> [<directory>] [options]
|
|
2475
2492
|
|
|
2476
2493
|
Download a BKN tar from a knowledge network and extract to a local directory.
|
|
@@ -2481,12 +2498,28 @@ Options:
|
|
|
2481
2498
|
-bd, --biz-domain Business domain (default: bd_public)`;
|
|
2482
2499
|
async function runKnValidateCommand(args) {
|
|
2483
2500
|
if (args.includes("--help") || args.includes("-h")) {
|
|
2484
|
-
console.log("Usage: kweaver bkn validate <directory
|
|
2501
|
+
console.log("Usage: kweaver bkn validate <directory> [options]\n\n" +
|
|
2502
|
+
"Validate a local BKN directory without uploading.\n\n" +
|
|
2503
|
+
"Options:\n" +
|
|
2504
|
+
" --detect-encoding Detect .bkn encoding and normalize to UTF-8 (default: on)\n" +
|
|
2505
|
+
" --no-detect-encoding Require UTF-8 .bkn files\n" +
|
|
2506
|
+
" --source-encoding <n> Decode all .bkn with this encoding (e.g. gb18030)");
|
|
2485
2507
|
return 0;
|
|
2486
2508
|
}
|
|
2487
|
-
|
|
2509
|
+
let encodingOptions;
|
|
2510
|
+
let restArgs;
|
|
2511
|
+
try {
|
|
2512
|
+
const stripped = stripBknEncodingCliArgs(args);
|
|
2513
|
+
encodingOptions = stripped.options;
|
|
2514
|
+
restArgs = stripped.rest;
|
|
2515
|
+
}
|
|
2516
|
+
catch (e) {
|
|
2517
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
2518
|
+
return 1;
|
|
2519
|
+
}
|
|
2520
|
+
const directory = restArgs.find((a) => !a.startsWith("-"));
|
|
2488
2521
|
if (!directory) {
|
|
2489
|
-
console.error("Missing directory. Usage: kweaver bkn validate <directory>");
|
|
2522
|
+
console.error("Missing directory. Usage: kweaver bkn validate <directory> [options]");
|
|
2490
2523
|
return 1;
|
|
2491
2524
|
}
|
|
2492
2525
|
const absDir = resolve(directory);
|
|
@@ -2504,8 +2537,9 @@ async function runKnValidateCommand(args) {
|
|
|
2504
2537
|
}
|
|
2505
2538
|
throw err;
|
|
2506
2539
|
}
|
|
2540
|
+
const prepared = prepareBknDirectoryForImport(absDir, encodingOptions);
|
|
2507
2541
|
try {
|
|
2508
|
-
const network = await loadNetwork(
|
|
2542
|
+
const network = await loadNetwork(prepared.dir);
|
|
2509
2543
|
const result = validateNetwork(network);
|
|
2510
2544
|
if (!result.ok) {
|
|
2511
2545
|
for (const e of result.errors)
|
|
@@ -2523,6 +2557,9 @@ async function runKnValidateCommand(args) {
|
|
|
2523
2557
|
console.error(`BKN validation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2524
2558
|
return 1;
|
|
2525
2559
|
}
|
|
2560
|
+
finally {
|
|
2561
|
+
prepared.cleanup();
|
|
2562
|
+
}
|
|
2526
2563
|
}
|
|
2527
2564
|
async function runKnPushCommand(args) {
|
|
2528
2565
|
let options;
|
|
@@ -2552,41 +2589,48 @@ async function runKnPushCommand(args) {
|
|
|
2552
2589
|
}
|
|
2553
2590
|
throw err;
|
|
2554
2591
|
}
|
|
2592
|
+
const prepared = prepareBknDirectoryForImport(absDir, options.encodingOptions);
|
|
2593
|
+
const workDir = prepared.dir;
|
|
2555
2594
|
try {
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2595
|
+
try {
|
|
2596
|
+
const network = await loadNetwork(workDir);
|
|
2597
|
+
const objs = allObjects(network);
|
|
2598
|
+
const rels = allRelations(network);
|
|
2599
|
+
const acts = allActions(network);
|
|
2600
|
+
console.error(`Validated: ${objs.length} object types, ${rels.length} relation types, ${acts.length} action types`);
|
|
2601
|
+
}
|
|
2602
|
+
catch (error) {
|
|
2603
|
+
console.error(`BKN validation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2604
|
+
return 1;
|
|
2605
|
+
}
|
|
2606
|
+
try {
|
|
2607
|
+
await generateChecksum(workDir);
|
|
2608
|
+
console.error("Checksum generated");
|
|
2609
|
+
}
|
|
2610
|
+
catch (error) {
|
|
2611
|
+
console.error(`Checksum generation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2612
|
+
return 1;
|
|
2613
|
+
}
|
|
2614
|
+
try {
|
|
2615
|
+
const tarBuffer = packDirectoryToTar(workDir);
|
|
2616
|
+
const token = await ensureValidToken();
|
|
2617
|
+
const body = await uploadBkn({
|
|
2618
|
+
baseUrl: token.baseUrl,
|
|
2619
|
+
accessToken: token.accessToken,
|
|
2620
|
+
tarBuffer,
|
|
2621
|
+
businessDomain: options.businessDomain,
|
|
2622
|
+
branch: options.branch,
|
|
2623
|
+
});
|
|
2624
|
+
console.log(formatCallOutput(body, options.pretty));
|
|
2625
|
+
return 0;
|
|
2626
|
+
}
|
|
2627
|
+
catch (error) {
|
|
2628
|
+
console.error(formatHttpError(error));
|
|
2629
|
+
return 1;
|
|
2630
|
+
}
|
|
2586
2631
|
}
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
return 1;
|
|
2632
|
+
finally {
|
|
2633
|
+
prepared.cleanup();
|
|
2590
2634
|
}
|
|
2591
2635
|
}
|
|
2592
2636
|
async function runKnPullCommand(args) {
|
package/dist/config/store.js
CHANGED
|
@@ -24,9 +24,10 @@ function getLegacyTokenFilePath() {
|
|
|
24
24
|
function getLegacyCallbackFilePath() {
|
|
25
25
|
return join(getConfigDirPath(), "callback.json");
|
|
26
26
|
}
|
|
27
|
+
const IS_WIN32 = process.platform === "win32";
|
|
27
28
|
function ensureDir(path) {
|
|
28
29
|
if (!existsSync(path)) {
|
|
29
|
-
mkdirSync(path, { recursive: true, mode: 0o700 });
|
|
30
|
+
mkdirSync(path, { recursive: true, ...(IS_WIN32 ? {} : { mode: 0o700 }) });
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
function ensureConfigDir() {
|
|
@@ -41,8 +42,9 @@ function readJsonFile(filePath) {
|
|
|
41
42
|
}
|
|
42
43
|
function writeJsonFile(filePath, value) {
|
|
43
44
|
ensureConfigDir();
|
|
44
|
-
writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
|
|
45
|
-
|
|
45
|
+
writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, IS_WIN32 ? {} : { mode: 0o600 });
|
|
46
|
+
if (!IS_WIN32)
|
|
47
|
+
chmodSync(filePath, 0o600);
|
|
46
48
|
}
|
|
47
49
|
function encodePlatformKey(baseUrl) {
|
|
48
50
|
return Buffer.from(baseUrl, "utf8")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize .bkn file bytes to UTF-8 for BKN import (validate / push).
|
|
3
|
+
* Used when --detect-encoding (default) or --source-encoding is active.
|
|
4
|
+
*/
|
|
5
|
+
/** Minimum confidence (0–1) for charset detection before failing. */
|
|
6
|
+
export declare const BKN_DETECT_MIN_CONFIDENCE = 0.65;
|
|
7
|
+
export interface BknEncodingImportOptions {
|
|
8
|
+
/** When true (default), detect encoding for non-UTF-8 .bkn files. */
|
|
9
|
+
detectEncoding: boolean;
|
|
10
|
+
/** When set, decode all .bkn files with this encoding (overrides detection). */
|
|
11
|
+
sourceEncoding: string | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse --no-detect-encoding, --detect-encoding, --source-encoding <name> from argv.
|
|
15
|
+
* Remaining args are returned for positional parsing (directory, etc.).
|
|
16
|
+
*/
|
|
17
|
+
export declare function stripBknEncodingCliArgs(args: string[]): {
|
|
18
|
+
rest: string[];
|
|
19
|
+
options: BknEncodingImportOptions;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Decode raw .bkn bytes to a UTF-8 Buffer (no BOM).
|
|
23
|
+
*/
|
|
24
|
+
export declare function normalizeBknFileBytes(raw: Buffer, options: BknEncodingImportOptions, fileLabel: string): Buffer;
|
|
25
|
+
/**
|
|
26
|
+
* When normalization is needed, copy the tree to a temp dir with .bkn files normalized to UTF-8.
|
|
27
|
+
* Returns the directory to pass to loadNetwork and a cleanup function.
|
|
28
|
+
*/
|
|
29
|
+
export declare function prepareBknDirectoryForImport(absDir: string, options: BknEncodingImportOptions): {
|
|
30
|
+
dir: string;
|
|
31
|
+
cleanup: () => void;
|
|
32
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize .bkn file bytes to UTF-8 for BKN import (validate / push).
|
|
3
|
+
* Used when --detect-encoding (default) or --source-encoding is active.
|
|
4
|
+
*/
|
|
5
|
+
import { copyFileSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join, relative, resolve } from "node:path";
|
|
8
|
+
import chardet from "chardet";
|
|
9
|
+
import iconv from "iconv-lite";
|
|
10
|
+
/** Minimum confidence (0–1) for charset detection before failing. */
|
|
11
|
+
export const BKN_DETECT_MIN_CONFIDENCE = 0.65;
|
|
12
|
+
/**
|
|
13
|
+
* Parse --no-detect-encoding, --detect-encoding, --source-encoding <name> from argv.
|
|
14
|
+
* Remaining args are returned for positional parsing (directory, etc.).
|
|
15
|
+
*/
|
|
16
|
+
export function stripBknEncodingCliArgs(args) {
|
|
17
|
+
let detectEncoding = true;
|
|
18
|
+
let sourceEncoding = null;
|
|
19
|
+
const rest = [];
|
|
20
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
21
|
+
const arg = args[i];
|
|
22
|
+
if (arg === "--no-detect-encoding") {
|
|
23
|
+
detectEncoding = false;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (arg === "--detect-encoding") {
|
|
27
|
+
detectEncoding = true;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (arg === "--source-encoding") {
|
|
31
|
+
const v = args[i + 1];
|
|
32
|
+
if (!v || v.startsWith("-")) {
|
|
33
|
+
throw new Error("Missing value for --source-encoding (e.g. gb18030)");
|
|
34
|
+
}
|
|
35
|
+
sourceEncoding = v;
|
|
36
|
+
i += 1;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
rest.push(arg);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
rest,
|
|
43
|
+
options: { detectEncoding, sourceEncoding },
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function isValidUtf8(buf) {
|
|
47
|
+
try {
|
|
48
|
+
new TextDecoder("utf-8", { fatal: true }).decode(buf);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function stripUtf8Bom(buf) {
|
|
56
|
+
if (buf.length >= 3 && buf[0] === 0xef && buf[1] === 0xbb && buf[2] === 0xbf) {
|
|
57
|
+
return buf.subarray(3);
|
|
58
|
+
}
|
|
59
|
+
return buf;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Decode raw .bkn bytes to a UTF-8 Buffer (no BOM).
|
|
63
|
+
*/
|
|
64
|
+
export function normalizeBknFileBytes(raw, options, fileLabel) {
|
|
65
|
+
if (options.sourceEncoding) {
|
|
66
|
+
const enc = options.sourceEncoding.trim().toLowerCase();
|
|
67
|
+
if (enc === "utf-8" || enc === "utf8") {
|
|
68
|
+
const body = stripUtf8Bom(raw);
|
|
69
|
+
if (!isValidUtf8(body)) {
|
|
70
|
+
throw new Error(`Invalid UTF-8 in ${fileLabel} despite --source-encoding utf-8`);
|
|
71
|
+
}
|
|
72
|
+
return Buffer.from(body.toString("utf8"), "utf8");
|
|
73
|
+
}
|
|
74
|
+
if (!iconv.encodingExists(enc)) {
|
|
75
|
+
throw new Error(`Unsupported --source-encoding: ${options.sourceEncoding}`);
|
|
76
|
+
}
|
|
77
|
+
const text = iconv.decode(raw, enc);
|
|
78
|
+
return Buffer.from(text, "utf8");
|
|
79
|
+
}
|
|
80
|
+
if (!options.detectEncoding) {
|
|
81
|
+
const body = stripUtf8Bom(raw);
|
|
82
|
+
if (!isValidUtf8(body)) {
|
|
83
|
+
throw new Error(`Invalid UTF-8 in ${fileLabel}. Use --detect-encoding (default) or --source-encoding (e.g. gb18030).`);
|
|
84
|
+
}
|
|
85
|
+
return Buffer.from(body.toString("utf8"), "utf8");
|
|
86
|
+
}
|
|
87
|
+
let work = stripUtf8Bom(raw);
|
|
88
|
+
if (isValidUtf8(work)) {
|
|
89
|
+
return Buffer.from(work.toString("utf8"), "utf8");
|
|
90
|
+
}
|
|
91
|
+
const matches = chardet.analyse(work);
|
|
92
|
+
const best = matches[0];
|
|
93
|
+
if (!best || best.confidence < BKN_DETECT_MIN_CONFIDENCE) {
|
|
94
|
+
throw new Error(`Could not detect encoding confidently for ${fileLabel} (best confidence ${best?.confidence ?? 0}). ` +
|
|
95
|
+
`Try --source-encoding gb18030 or save files as UTF-8.`);
|
|
96
|
+
}
|
|
97
|
+
const name = best.name ?? "utf-8";
|
|
98
|
+
if (!iconv.encodingExists(name)) {
|
|
99
|
+
throw new Error(`Detected encoding "${name}" is not supported for ${fileLabel}. Try --source-encoding.`);
|
|
100
|
+
}
|
|
101
|
+
const text = iconv.decode(work, name);
|
|
102
|
+
return Buffer.from(text, "utf8");
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* When normalization is needed, copy the tree to a temp dir with .bkn files normalized to UTF-8.
|
|
106
|
+
* Returns the directory to pass to loadNetwork and a cleanup function.
|
|
107
|
+
*/
|
|
108
|
+
export function prepareBknDirectoryForImport(absDir, options) {
|
|
109
|
+
const needWork = options.sourceEncoding != null || options.detectEncoding;
|
|
110
|
+
if (!needWork) {
|
|
111
|
+
return { dir: absDir, cleanup: () => { } };
|
|
112
|
+
}
|
|
113
|
+
const root = resolve(absDir);
|
|
114
|
+
const tmpRoot = mkdtempSync(join(tmpdir(), "kweaver-bkn-"));
|
|
115
|
+
function walk(srcDir, destDir) {
|
|
116
|
+
mkdirSync(destDir, { recursive: true });
|
|
117
|
+
const entries = readdirSync(srcDir, { withFileTypes: true });
|
|
118
|
+
for (const entry of entries) {
|
|
119
|
+
if (entry.name === "." || entry.name === "..")
|
|
120
|
+
continue;
|
|
121
|
+
const srcPath = join(srcDir, entry.name);
|
|
122
|
+
const destPath = join(destDir, entry.name);
|
|
123
|
+
if (entry.isDirectory()) {
|
|
124
|
+
walk(srcPath, destPath);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (!entry.isFile())
|
|
128
|
+
continue;
|
|
129
|
+
if (entry.name.endsWith(".bkn")) {
|
|
130
|
+
const raw = readFileSync(srcPath);
|
|
131
|
+
const rel = relative(root, srcPath) || entry.name;
|
|
132
|
+
const out = normalizeBknFileBytes(raw, options, rel);
|
|
133
|
+
writeFileSync(destPath, out);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
copyFileSync(srcPath, destPath);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
walk(root, tmpRoot);
|
|
141
|
+
return {
|
|
142
|
+
dir: tmpRoot,
|
|
143
|
+
cleanup: () => {
|
|
144
|
+
try {
|
|
145
|
+
rmSync(tmpRoot, { recursive: true, force: true });
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
/* ignore */
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
package/dist/utils/browser.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
export function openBrowser(url) {
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
const isWindows = process.platform === "win32";
|
|
4
|
+
const command = process.platform === "darwin" ? "open" : isWindows ? "rundll32.exe" : "xdg-open";
|
|
5
|
+
const args = isWindows
|
|
6
|
+
? [
|
|
7
|
+
"url.dll,FileProtocolHandler",
|
|
8
|
+
url,
|
|
9
|
+
]
|
|
10
10
|
: [url];
|
|
11
11
|
return new Promise((resolve) => {
|
|
12
12
|
const child = spawn(command, args, {
|
|
13
|
-
detached: true,
|
|
14
13
|
stdio: "ignore",
|
|
14
|
+
detached: !isWindows,
|
|
15
|
+
windowsHide: true,
|
|
15
16
|
});
|
|
16
|
-
child.
|
|
17
|
-
child.
|
|
18
|
-
|
|
17
|
+
child.once("error", () => resolve(false));
|
|
18
|
+
child.once("spawn", () => resolve(true));
|
|
19
|
+
if (!isWindows) {
|
|
20
|
+
child.unref();
|
|
21
|
+
}
|
|
19
22
|
});
|
|
20
23
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kweaver-ai/kweaver-sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"description": "KWeaver TypeScript SDK — CLI tool and programmatic API for knowledge networks and Decision Agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"lint": "tsc --noEmit -p tsconfig.json",
|
|
30
30
|
"test": "node --import tsx --test test/*.test.ts",
|
|
31
31
|
"test:e2e": "node --import tsx test/e2e/ensure-token.ts && node --import tsx --test --test-concurrency=1 test/e2e/**/*.test.ts",
|
|
32
|
+
"test:e2e:strict": "node test/e2e/run-e2e-strict.mjs",
|
|
32
33
|
"prepublishOnly": "npm run build"
|
|
33
34
|
},
|
|
34
35
|
"keywords": [
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@types/node": "^24.6.0",
|
|
52
53
|
"@types/react": "^19.2.14",
|
|
54
|
+
"playwright": "^1.58.2",
|
|
53
55
|
"tsx": "^4.20.5",
|
|
54
56
|
"typescript": "^5.9.3"
|
|
55
57
|
},
|
|
@@ -63,6 +65,9 @@
|
|
|
63
65
|
},
|
|
64
66
|
"dependencies": {
|
|
65
67
|
"@kweaver-ai/bkn": "^0.1.0",
|
|
68
|
+
"@playwright/test": "^1.58.2",
|
|
69
|
+
"chardet": "^2.1.1",
|
|
70
|
+
"iconv-lite": "^0.7.2",
|
|
66
71
|
"ink": "^6.8.0",
|
|
67
72
|
"ink-spinner": "^5.0.0",
|
|
68
73
|
"ink-text-input": "^6.0.0",
|