@kweaver-ai/kweaver-sdk 0.4.0 → 0.4.1

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.
@@ -340,7 +340,7 @@ function parseJsonArg(args) {
340
340
  async function runQueryObjectInstance(options, args, pretty) {
341
341
  const body = parseJsonArg(args);
342
342
  if (!body.ot_id || !body.condition) {
343
- console.error("JSON must include ot_id and condition. See ref/contextloader/examples.md");
343
+ console.error("JSON must include ot_id and condition. See references/json-formats.md#context-loader");
344
344
  return 1;
345
345
  }
346
346
  const result = await queryObjectInstance(options, {
@@ -354,7 +354,7 @@ async function runQueryObjectInstance(options, args, pretty) {
354
354
  async function runQueryInstanceSubgraph(options, args, pretty) {
355
355
  const body = parseJsonArg(args);
356
356
  if (!Array.isArray(body.relation_type_paths)) {
357
- console.error("JSON must include relation_type_paths array. See ref/contextloader/examples.md");
357
+ console.error("JSON must include relation_type_paths array. See references/json-formats.md#context-loader");
358
358
  return 1;
359
359
  }
360
360
  const result = await queryInstanceSubgraph(options, body);
@@ -364,7 +364,7 @@ async function runQueryInstanceSubgraph(options, args, pretty) {
364
364
  async function runGetLogicProperties(options, args, pretty) {
365
365
  const body = parseJsonArg(args);
366
366
  if (!body.ot_id || !body.query || !body._instance_identities || !body.properties) {
367
- console.error("JSON must include ot_id, query, _instance_identities, properties. See ref/contextloader/examples.md");
367
+ console.error("JSON must include ot_id, query, _instance_identities, properties. See references/json-formats.md#context-loader");
368
368
  return 1;
369
369
  }
370
370
  const result = await getLogicPropertiesValues(options, body);
@@ -374,7 +374,7 @@ async function runGetLogicProperties(options, args, pretty) {
374
374
  async function runGetActionInfo(options, args, pretty) {
375
375
  const body = parseJsonArg(args);
376
376
  if (!body.at_id || !body._instance_identity) {
377
- console.error("JSON must include at_id and _instance_identity. See ref/contextloader/examples.md");
377
+ console.error("JSON must include at_id and _instance_identity. See references/json-formats.md#context-loader");
378
378
  return 1;
379
379
  }
380
380
  const result = await getActionInfo(options, body);
@@ -0,0 +1,7 @@
1
+ export declare function runDsCommand(args: string[]): Promise<number>;
2
+ export declare function parseDsListArgs(args: string[]): {
3
+ keyword?: string;
4
+ type?: string;
5
+ businessDomain: string;
6
+ pretty: boolean;
7
+ };
@@ -0,0 +1,283 @@
1
+ import { createInterface } from "node:readline";
2
+ import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
3
+ import { testDatasource, createDatasource, listDatasources, getDatasource, deleteDatasource, listTablesWithColumns, } from "../api/datasources.js";
4
+ import { formatCallOutput } from "./call.js";
5
+ function confirmYes(prompt) {
6
+ return new Promise((resolve) => {
7
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
8
+ rl.question(`${prompt} [y/N] `, (answer) => {
9
+ rl.close();
10
+ const trimmed = answer.trim().toLowerCase();
11
+ resolve(trimmed === "y" || trimmed === "yes");
12
+ });
13
+ });
14
+ }
15
+ function extractDatasourceId(body) {
16
+ const parsed = JSON.parse(body);
17
+ const item = Array.isArray(parsed) ? parsed[0] : parsed;
18
+ if (!item || typeof item !== "object")
19
+ return "";
20
+ const id = item.id ?? item.ds_id;
21
+ return id != null ? String(id) : "";
22
+ }
23
+ export async function runDsCommand(args) {
24
+ const [subcommand, ...rest] = args;
25
+ if (!subcommand || subcommand === "--help" || subcommand === "-h") {
26
+ console.log(`kweaver ds
27
+
28
+ Subcommands:
29
+ list [--keyword X] [--type Y] List datasources
30
+ get <id> Get datasource details
31
+ delete <id> [-y] Delete a datasource
32
+ tables <id> [--keyword X] List tables with columns
33
+ connect <db_type> <host> <port> <database> --account X --password Y [--schema Z] [--name N]
34
+ Test connectivity, register datasource, and discover tables.`);
35
+ return 0;
36
+ }
37
+ try {
38
+ if (subcommand === "list") {
39
+ return runDsListCommand(rest);
40
+ }
41
+ if (subcommand === "get") {
42
+ return runDsGetCommand(rest);
43
+ }
44
+ if (subcommand === "delete") {
45
+ return runDsDeleteCommand(rest);
46
+ }
47
+ if (subcommand === "tables") {
48
+ return runDsTablesCommand(rest);
49
+ }
50
+ if (subcommand === "connect") {
51
+ return runDsConnectCommand(rest);
52
+ }
53
+ console.error(`Unknown ds subcommand: ${subcommand}`);
54
+ return 1;
55
+ }
56
+ catch (error) {
57
+ console.error(formatHttpError(error));
58
+ return 1;
59
+ }
60
+ }
61
+ export function parseDsListArgs(args) {
62
+ let keyword;
63
+ let type;
64
+ let businessDomain = "bd_public";
65
+ let pretty = true;
66
+ for (let i = 0; i < args.length; i += 1) {
67
+ const arg = args[i];
68
+ if (arg === "--help" || arg === "-h")
69
+ throw new Error("help");
70
+ if (arg === "--keyword" && args[i + 1]) {
71
+ keyword = args[++i];
72
+ continue;
73
+ }
74
+ if (arg === "--type" && args[i + 1]) {
75
+ type = args[++i];
76
+ continue;
77
+ }
78
+ if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
79
+ businessDomain = args[++i];
80
+ continue;
81
+ }
82
+ if (arg === "--pretty") {
83
+ pretty = true;
84
+ continue;
85
+ }
86
+ }
87
+ return { keyword, type, businessDomain, pretty };
88
+ }
89
+ async function runDsListCommand(args) {
90
+ try {
91
+ const opts = parseDsListArgs(args);
92
+ const token = await ensureValidToken();
93
+ const body = await listDatasources({
94
+ baseUrl: token.baseUrl,
95
+ accessToken: token.accessToken,
96
+ keyword: opts.keyword,
97
+ type: opts.type,
98
+ businessDomain: opts.businessDomain,
99
+ });
100
+ console.log(formatCallOutput(body, opts.pretty));
101
+ return 0;
102
+ }
103
+ catch (error) {
104
+ if (error instanceof Error && error.message === "help") {
105
+ console.log(`kweaver ds list [options]
106
+
107
+ Options:
108
+ --keyword <s> Filter by keyword
109
+ --type <s> Filter by database type
110
+ -bd, --biz-domain Business domain (default: bd_public)
111
+ --pretty Pretty-print JSON (default)`);
112
+ return 0;
113
+ }
114
+ throw error;
115
+ }
116
+ }
117
+ async function runDsGetCommand(args) {
118
+ const id = args.find((a) => !a.startsWith("-"));
119
+ if (!id) {
120
+ console.error("Usage: kweaver ds get <id>");
121
+ return 1;
122
+ }
123
+ const token = await ensureValidToken();
124
+ const body = await getDatasource({
125
+ baseUrl: token.baseUrl,
126
+ accessToken: token.accessToken,
127
+ id,
128
+ });
129
+ console.log(formatCallOutput(body, true));
130
+ return 0;
131
+ }
132
+ async function runDsDeleteCommand(args) {
133
+ let id = "";
134
+ let yes = false;
135
+ for (let i = 0; i < args.length; i += 1) {
136
+ const arg = args[i];
137
+ if (arg === "--yes" || arg === "-y")
138
+ yes = true;
139
+ else if (!arg.startsWith("-"))
140
+ id = arg;
141
+ }
142
+ if (!id) {
143
+ console.error("Usage: kweaver ds delete <id> [-y]");
144
+ return 1;
145
+ }
146
+ if (!yes) {
147
+ const confirmed = await confirmYes("Are you sure you want to delete this datasource?");
148
+ if (!confirmed) {
149
+ console.error("Aborted.");
150
+ return 1;
151
+ }
152
+ }
153
+ const token = await ensureValidToken();
154
+ await deleteDatasource({
155
+ baseUrl: token.baseUrl,
156
+ accessToken: token.accessToken,
157
+ id,
158
+ });
159
+ console.error(`Deleted ${id}`);
160
+ return 0;
161
+ }
162
+ async function runDsTablesCommand(args) {
163
+ let id = "";
164
+ let keyword;
165
+ let pretty = true;
166
+ for (let i = 0; i < args.length; i += 1) {
167
+ const arg = args[i];
168
+ if (arg === "--keyword" && args[i + 1]) {
169
+ keyword = args[++i];
170
+ continue;
171
+ }
172
+ if (arg === "--pretty") {
173
+ pretty = true;
174
+ continue;
175
+ }
176
+ if (!arg.startsWith("-"))
177
+ id = arg;
178
+ }
179
+ if (!id) {
180
+ console.error("Usage: kweaver ds tables <id> [--keyword X]");
181
+ return 1;
182
+ }
183
+ const token = await ensureValidToken();
184
+ const body = await listTablesWithColumns({
185
+ baseUrl: token.baseUrl,
186
+ accessToken: token.accessToken,
187
+ id,
188
+ keyword,
189
+ });
190
+ console.log(formatCallOutput(body, pretty));
191
+ return 0;
192
+ }
193
+ async function runDsConnectCommand(args) {
194
+ let dbType = "";
195
+ let host = "";
196
+ let port = 0;
197
+ let database = "";
198
+ let account = "";
199
+ let password = "";
200
+ let schema;
201
+ let name;
202
+ for (let i = 0; i < args.length; i += 1) {
203
+ const arg = args[i];
204
+ if (arg === "--account" && args[i + 1]) {
205
+ account = args[++i];
206
+ continue;
207
+ }
208
+ if (arg === "--password" && args[i + 1]) {
209
+ password = args[++i];
210
+ continue;
211
+ }
212
+ if (arg === "--schema" && args[i + 1]) {
213
+ schema = args[++i];
214
+ continue;
215
+ }
216
+ if (arg === "--name" && args[i + 1]) {
217
+ name = args[++i];
218
+ continue;
219
+ }
220
+ if (!arg.startsWith("-")) {
221
+ if (!dbType)
222
+ dbType = arg;
223
+ else if (!host)
224
+ host = arg;
225
+ else if (port === 0)
226
+ port = parseInt(arg, 10);
227
+ else if (!database)
228
+ database = arg;
229
+ }
230
+ }
231
+ if (!dbType || !host || !database || !account || !password) {
232
+ console.error("Usage: kweaver ds connect <db_type> <host> <port> <database> --account X --password Y [--schema Z] [--name N]");
233
+ return 1;
234
+ }
235
+ if (Number.isNaN(port) || port < 1) {
236
+ console.error("Invalid port");
237
+ return 1;
238
+ }
239
+ const token = await ensureValidToken();
240
+ const base = { baseUrl: token.baseUrl, accessToken: token.accessToken };
241
+ console.error("Testing connectivity ...");
242
+ await testDatasource({
243
+ ...base,
244
+ type: dbType,
245
+ host,
246
+ port,
247
+ database,
248
+ account,
249
+ password,
250
+ schema,
251
+ });
252
+ const dsName = name ?? database;
253
+ const createBody = await createDatasource({
254
+ ...base,
255
+ name: dsName,
256
+ type: dbType,
257
+ host,
258
+ port,
259
+ database,
260
+ account,
261
+ password,
262
+ schema,
263
+ });
264
+ const dsId = extractDatasourceId(createBody);
265
+ if (!dsId) {
266
+ console.error("Failed to get datasource ID from create response");
267
+ return 1;
268
+ }
269
+ const tablesBody = await listTablesWithColumns({
270
+ ...base,
271
+ id: dsId,
272
+ });
273
+ const tables = JSON.parse(tablesBody);
274
+ const output = {
275
+ datasource_id: dsId,
276
+ tables: tables.map((t) => ({
277
+ name: t.name,
278
+ columns: t.columns.map((c) => ({ name: c.name, type: c.type, comment: c.comment })),
279
+ })),
280
+ };
281
+ console.log(JSON.stringify(output, null, 2));
282
+ return 0;
283
+ }
@@ -42,4 +42,16 @@ export declare class BknResource {
42
42
  }): Promise<unknown[]>;
43
43
  getActionLog(knId: string, logId: string): Promise<unknown>;
44
44
  cancelActionLog(knId: string, logId: string): Promise<unknown>;
45
+ /**
46
+ * Search KN schema — finds matching object types, relation types, and action types.
47
+ * Uses MCP protocol via the context-loader (public endpoint).
48
+ */
49
+ knSearch(knId: string, query: string, opts?: {
50
+ onlySchema?: boolean;
51
+ }): Promise<{
52
+ object_types?: unknown[];
53
+ relation_types?: unknown[];
54
+ action_types?: unknown[];
55
+ nodes?: unknown[];
56
+ }>;
45
57
  }
@@ -83,4 +83,16 @@ export class BknResource {
83
83
  const raw = await actionLogCancel({ ...this.ctx.base(), knId, logId });
84
84
  return JSON.parse(raw);
85
85
  }
86
+ /**
87
+ * Search KN schema — finds matching object types, relation types, and action types.
88
+ * Uses MCP protocol via the context-loader (public endpoint).
89
+ */
90
+ async knSearch(knId, query, opts = {}) {
91
+ const { ContextLoaderResource } = await import("./context-loader.js");
92
+ const { baseUrl } = this.ctx.base();
93
+ const mcpUrl = `${baseUrl}/api/agent-retrieval/v1/mcp`;
94
+ const cl = new ContextLoaderResource(this.ctx, mcpUrl, knId);
95
+ const result = await cl.search({ query, only_schema: opts.onlySchema ?? false });
96
+ return result;
97
+ }
86
98
  }
@@ -1,8 +1,5 @@
1
1
  import { listKnowledgeNetworks, getKnowledgeNetwork, createKnowledgeNetwork, updateKnowledgeNetwork, deleteKnowledgeNetwork, listObjectTypes, listRelationTypes, listActionTypes, } from "../api/knowledge-networks.js";
2
2
  import { fetchTextOrThrow } from "../utils/http.js";
3
- function is404(err) {
4
- return !!(err && typeof err === "object" && "status" in err && err.status === 404);
5
- }
6
3
  export class KnowledgeNetworksResource {
7
4
  ctx;
8
5
  constructor(ctx) {
@@ -77,29 +74,11 @@ export class KnowledgeNetworksResource {
77
74
  token: accessToken,
78
75
  "x-business-domain": businessDomain,
79
76
  };
80
- try {
81
- await fetchTextOrThrow(`${baseUrl}/api/agent-retrieval/in/v1/kn/full_build_ontology`, { method: "POST", headers, body: JSON.stringify({ kn_id: bknId }) });
82
- }
83
- catch (err) {
84
- if (!is404(err))
85
- throw err;
86
- // Fallback: call ontology-manager jobs endpoint directly
87
- try {
88
- await fetchTextOrThrow(`${baseUrl}/api/ontology-manager/in/v1/knowledge-networks/${encodeURIComponent(bknId)}/jobs`, {
89
- method: "POST",
90
- headers,
91
- body: JSON.stringify({ name: `sdk_build_${bknId.slice(0, 8)}`, job_type: "full" }),
92
- });
93
- }
94
- catch (err2) {
95
- if (is404(err2)) {
96
- throw new Error(`No build endpoint available for BKN ${bknId}. ` +
97
- `Both agent-retrieval and ontology-manager returned 404. ` +
98
- `This deployment may not support index rebuilds.`);
99
- }
100
- throw err2;
101
- }
102
- }
77
+ await fetchTextOrThrow(`${baseUrl}/api/ontology-manager/v1/knowledge-networks/${encodeURIComponent(bknId)}/jobs`, {
78
+ method: "POST",
79
+ headers,
80
+ body: JSON.stringify({ name: `sdk_build_${bknId.slice(0, 8)}`, job_type: "full" }),
81
+ });
103
82
  }
104
83
  /** Poll build status for a BKN. */
105
84
  async buildStatus(bknId) {
@@ -109,36 +88,19 @@ export class KnowledgeNetworksResource {
109
88
  token: accessToken,
110
89
  "x-business-domain": businessDomain,
111
90
  };
112
- try {
113
- const { body } = await fetchTextOrThrow(`${baseUrl}/api/agent-retrieval/in/v1/kn/full_ontology_building_status?kn_id=${encodeURIComponent(bknId)}`, { headers });
114
- const data = JSON.parse(body);
115
- return { state: data.state ?? "running", state_detail: data.state_detail };
116
- }
117
- catch (err) {
118
- if (!is404(err))
119
- throw err;
120
- // Fallback: check ontology-manager jobs for latest status
121
- try {
122
- const { body } = await fetchTextOrThrow(`${baseUrl}/api/ontology-manager/in/v1/knowledge-networks/${encodeURIComponent(bknId)}/jobs?limit=1&direction=desc`, { headers });
123
- const data = JSON.parse(body);
124
- const jobs = Array.isArray(data)
125
- ? data
126
- : data && typeof data === "object" && "entries" in data
127
- ? (data.entries ?? [])
128
- : data && typeof data === "object" && "data" in data
129
- ? (data.data ?? [])
130
- : [];
131
- if (jobs.length > 0) {
132
- return { state: jobs[0].state ?? "running" };
133
- }
134
- return { state: "completed" };
135
- }
136
- catch (err2) {
137
- if (is404(err2))
138
- return { state: "completed" };
139
- throw err2;
140
- }
91
+ const { body } = await fetchTextOrThrow(`${baseUrl}/api/ontology-manager/v1/knowledge-networks/${encodeURIComponent(bknId)}/jobs?limit=1&direction=desc`, { headers });
92
+ const data = JSON.parse(body);
93
+ const jobs = Array.isArray(data)
94
+ ? data
95
+ : data && typeof data === "object" && "entries" in data
96
+ ? (data.entries ?? [])
97
+ : data && typeof data === "object" && "data" in data
98
+ ? (data.data ?? [])
99
+ : [];
100
+ if (jobs.length > 0) {
101
+ return { state: jobs[0].state ?? "running", state_detail: jobs[0].state_detail };
141
102
  }
103
+ return { state: "completed" };
142
104
  }
143
105
  /**
144
106
  * Trigger a full BKN build and wait for it to complete.
@@ -0,0 +1,10 @@
1
+ /**
2
+ * RSA password encryption for the KWeaver data-connection API.
3
+ * The KWeaver backend requires datasource passwords to be RSA-encrypted
4
+ * (PKCS1v15) using a platform-wide public key before transmission.
5
+ */
6
+ /**
7
+ * Encrypt a password with the KWeaver platform RSA public key.
8
+ * Returns a base64-encoded ciphertext string.
9
+ */
10
+ export declare function encryptPassword(plaintext: string): string;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * RSA password encryption for the KWeaver data-connection API.
3
+ * The KWeaver backend requires datasource passwords to be RSA-encrypted
4
+ * (PKCS1v15) using a platform-wide public key before transmission.
5
+ */
6
+ import { publicEncrypt, createPublicKey, constants } from "node:crypto";
7
+ const KWEAVER_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
8
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA22GOSQ1jeDhpdzxhJddS
9
+ f+U10F4Ivut7giYhchFAIJgRonMamDT86MSqQUc8DdTFdPGLm7M3GUKcsG1qbC3S
10
+ qk4XJ9NjmQXbs7IMWyWEWQrN7Iv7S2QjDYJI+ppvIN03I0Km3WKsmnrle2bLzT/V
11
+ G8e72YX69dfXAeiX6uDhht1va/JxZVFMIV3pHa6AQQ9gn5SAUTX2akEhRfe1bPJj
12
+ fVyoM+dfNtvgdfaraqV1rOhVDEqd0NlOWt2RHwETQwU8gIJib2baj2MtyIAY+fQw
13
+ KlKWxUs1GcFbECnhVPiVN6BEhXD7OhRt9QE/cuYl5v4a6ypugGaMBK6VKOqFHDvf
14
+ mwIDAQAB
15
+ -----END PUBLIC KEY-----`;
16
+ let cachedKey = null;
17
+ function getPublicKey() {
18
+ if (!cachedKey) {
19
+ cachedKey = createPublicKey(KWEAVER_PUBLIC_KEY_PEM);
20
+ }
21
+ return cachedKey;
22
+ }
23
+ /**
24
+ * Encrypt a password with the KWeaver platform RSA public key.
25
+ * Returns a base64-encoded ciphertext string.
26
+ */
27
+ export function encryptPassword(plaintext) {
28
+ const key = getPublicKey();
29
+ const ciphertext = publicEncrypt({ key, padding: constants.RSA_PKCS1_PADDING }, Buffer.from(plaintext, "utf8"));
30
+ return ciphertext.toString("base64");
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kweaver-ai/kweaver-sdk",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
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",
@@ -27,7 +27,8 @@
27
27
  "build": "tsc -p tsconfig.json",
28
28
  "start": "node ./dist/cli.js",
29
29
  "lint": "tsc --noEmit -p tsconfig.json",
30
- "test": "node --import tsx --test test/**/*.test.ts",
30
+ "test": "node --import tsx --test test/*.test.ts",
31
+ "test:e2e": "node --import tsx --test test/e2e/**/*.test.ts",
31
32
  "prepublishOnly": "npm run build"
32
33
  },
33
34
  "keywords": [