@kweaver-ai/kweaver-sdk 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/README.zh.md +5 -0
- package/dist/api/agent-chat.d.ts +1 -1
- package/dist/api/agent-chat.js +4 -4
- package/dist/api/agent-list.d.ts +35 -0
- package/dist/api/agent-list.js +86 -12
- package/dist/api/bkn-backend.d.ts +60 -0
- package/dist/api/bkn-backend.js +103 -10
- package/dist/api/conversations.d.ts +6 -3
- package/dist/api/conversations.js +26 -27
- package/dist/api/dataflow.js +1 -10
- package/dist/api/datasources.js +1 -10
- package/dist/api/dataviews.js +1 -10
- package/dist/api/headers.d.ts +9 -0
- package/dist/api/headers.js +25 -0
- package/dist/api/knowledge-networks.d.ts +41 -0
- package/dist/api/knowledge-networks.js +69 -22
- package/dist/api/ontology-query.d.ts +14 -1
- package/dist/api/ontology-query.js +63 -49
- package/dist/api/semantic-search.js +2 -12
- package/dist/api/skills.d.ts +141 -0
- package/dist/api/skills.js +216 -0
- package/dist/api/vega.d.ts +63 -0
- package/dist/api/vega.js +130 -10
- package/dist/auth/oauth.d.ts +5 -1
- package/dist/auth/oauth.js +293 -94
- package/dist/cli.js +28 -4
- package/dist/client.d.ts +3 -0
- package/dist/client.js +4 -0
- package/dist/commands/agent.d.ts +33 -1
- package/dist/commands/agent.js +721 -49
- package/dist/commands/auth.js +156 -33
- package/dist/commands/bkn-ops.d.ts +77 -0
- package/dist/commands/bkn-ops.js +1056 -0
- package/dist/commands/bkn-query.d.ts +14 -0
- package/dist/commands/bkn-query.js +370 -0
- package/dist/commands/bkn-schema.d.ts +135 -0
- package/dist/commands/bkn-schema.js +1461 -0
- package/dist/commands/bkn-utils.d.ts +36 -0
- package/dist/commands/bkn-utils.js +102 -0
- package/dist/commands/bkn.d.ts +7 -113
- package/dist/commands/bkn.js +175 -2429
- package/dist/commands/dataview.d.ts +7 -0
- package/dist/commands/dataview.js +38 -2
- package/dist/commands/ds.d.ts +1 -0
- package/dist/commands/ds.js +8 -1
- package/dist/commands/import-csv.d.ts +2 -0
- package/dist/commands/import-csv.js +3 -2
- package/dist/commands/skill.d.ts +26 -0
- package/dist/commands/skill.js +524 -0
- package/dist/commands/vega.js +371 -14
- package/dist/config/jwt.d.ts +6 -0
- package/dist/config/jwt.js +21 -0
- package/dist/config/store.d.ts +37 -5
- package/dist/config/store.js +363 -30
- package/dist/index.d.ts +6 -1
- package/dist/index.js +5 -1
- package/dist/resources/bkn.d.ts +4 -0
- package/dist/resources/bkn.js +4 -0
- package/dist/resources/conversations.d.ts +5 -2
- package/dist/resources/conversations.js +17 -3
- package/dist/resources/skills.d.ts +47 -0
- package/dist/resources/skills.js +47 -0
- package/dist/resources/vega.d.ts +11 -0
- package/dist/resources/vega.js +37 -1
- package/package.json +1 -1
package/dist/config/store.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { listBusinessDomains } from "../api/business-domains.js";
|
|
5
|
+
import { decodeJwtPayload, extractUserIdFromJwt } from "./jwt.js";
|
|
5
6
|
const MCP_PATH = "/api/agent-retrieval/v1/mcp";
|
|
6
7
|
function buildMcpUrl(baseUrl) {
|
|
7
8
|
return baseUrl.replace(/\/+$/, "") + MCP_PATH;
|
|
8
9
|
}
|
|
9
|
-
const CONFIG_DIR = process.env.KWEAVERC_CONFIG_DIR || join(homedir(), ".kweaver");
|
|
10
10
|
function getConfigDirPath() {
|
|
11
11
|
return process.env.KWEAVERC_CONFIG_DIR || join(homedir(), ".kweaver");
|
|
12
12
|
}
|
|
@@ -43,6 +43,8 @@ function readJsonFile(filePath) {
|
|
|
43
43
|
}
|
|
44
44
|
function writeJsonFile(filePath, value) {
|
|
45
45
|
ensureConfigDir();
|
|
46
|
+
const dir = join(filePath, "..");
|
|
47
|
+
ensureDir(dir);
|
|
46
48
|
writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, IS_WIN32 ? {} : { mode: 0o600 });
|
|
47
49
|
if (!IS_WIN32)
|
|
48
50
|
chmodSync(filePath, 0o600);
|
|
@@ -63,6 +65,56 @@ function getPlatformFile(baseUrl, filename) {
|
|
|
63
65
|
function ensurePlatformDir(baseUrl) {
|
|
64
66
|
ensureDir(getPlatformDir(baseUrl));
|
|
65
67
|
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// User-scoped file routing
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
/** Files that live under users/<userId>/ instead of at platform root. */
|
|
72
|
+
const USER_SCOPED_FILES = new Set(["token.json", "config.json", "context-loader.json"]);
|
|
73
|
+
function getUserDir(baseUrl, userId) {
|
|
74
|
+
return join(getPlatformDir(baseUrl), "users", userId);
|
|
75
|
+
}
|
|
76
|
+
function getUsersDirPath(baseUrl) {
|
|
77
|
+
return join(getPlatformDir(baseUrl), "users");
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Resolve a per-platform file path, routing user-scoped files through the
|
|
81
|
+
* active user's subdirectory with auto-migration fallback.
|
|
82
|
+
*/
|
|
83
|
+
function resolveFile(baseUrl, filename) {
|
|
84
|
+
if (!USER_SCOPED_FILES.has(filename)) {
|
|
85
|
+
return getPlatformFile(baseUrl, filename);
|
|
86
|
+
}
|
|
87
|
+
const userId = getActiveUserRaw(baseUrl);
|
|
88
|
+
if (userId) {
|
|
89
|
+
const userPath = join(getUserDir(baseUrl, userId), filename);
|
|
90
|
+
if (existsSync(userPath))
|
|
91
|
+
return userPath;
|
|
92
|
+
}
|
|
93
|
+
// Fallback: check platform root for legacy / partially-migrated files
|
|
94
|
+
const legacyPath = getPlatformFile(baseUrl, filename);
|
|
95
|
+
if (existsSync(legacyPath)) {
|
|
96
|
+
// If legacy token.json exists, trigger full on-demand migration
|
|
97
|
+
const legacyToken = getPlatformFile(baseUrl, "token.json");
|
|
98
|
+
if (existsSync(legacyToken)) {
|
|
99
|
+
migratePlatformToUserScoped(baseUrl);
|
|
100
|
+
const migratedUser = getActiveUserRaw(baseUrl);
|
|
101
|
+
if (migratedUser) {
|
|
102
|
+
const migratedPath = join(getUserDir(baseUrl, migratedUser), filename);
|
|
103
|
+
if (existsSync(migratedPath))
|
|
104
|
+
return migratedPath;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// File exists at legacy root but no migration possible (e.g. token already migrated).
|
|
108
|
+
// Return legacy path so the caller can still read it.
|
|
109
|
+
return legacyPath;
|
|
110
|
+
}
|
|
111
|
+
if (userId)
|
|
112
|
+
return join(getUserDir(baseUrl, userId), filename);
|
|
113
|
+
return legacyPath;
|
|
114
|
+
}
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// State helpers
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
66
118
|
function readState() {
|
|
67
119
|
return readJsonFile(getStateFilePath()) ?? {};
|
|
68
120
|
}
|
|
@@ -72,6 +124,9 @@ function writeState(state) {
|
|
|
72
124
|
function normalizeAlias(value) {
|
|
73
125
|
return value.trim().toLowerCase();
|
|
74
126
|
}
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Migration: legacy flat files → platforms/<encoded>/
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
75
130
|
function migrateLegacyFilesIfNeeded() {
|
|
76
131
|
const legacyClientFile = getLegacyClientFilePath();
|
|
77
132
|
const legacyTokenFile = getLegacyTokenFilePath();
|
|
@@ -105,10 +160,182 @@ function migrateLegacyFilesIfNeeded() {
|
|
|
105
160
|
writeState({ ...state, currentPlatform: baseUrl });
|
|
106
161
|
}
|
|
107
162
|
}
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Migration: flat platform dir → users/<userId>/ scoped layout
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
/** Extract userId from a TokenConfig (try idToken, then accessToken, fallback "default"). */
|
|
167
|
+
export function extractUserId(token) {
|
|
168
|
+
if (token.idToken) {
|
|
169
|
+
const sub = extractUserIdFromJwt(token.idToken);
|
|
170
|
+
if (sub)
|
|
171
|
+
return sub;
|
|
172
|
+
}
|
|
173
|
+
if (token.accessToken) {
|
|
174
|
+
const sub = extractUserIdFromJwt(token.accessToken);
|
|
175
|
+
if (sub)
|
|
176
|
+
return sub;
|
|
177
|
+
}
|
|
178
|
+
return "default";
|
|
179
|
+
}
|
|
180
|
+
function migratePlatformToUserScoped(baseUrl) {
|
|
181
|
+
const platformDir = getPlatformDir(baseUrl);
|
|
182
|
+
const usersDir = getUsersDirPath(baseUrl);
|
|
183
|
+
const rootTokenFile = join(platformDir, "token.json");
|
|
184
|
+
if (!existsSync(rootTokenFile) || existsSync(usersDir)) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const token = readJsonFile(rootTokenFile);
|
|
188
|
+
if (!token)
|
|
189
|
+
return;
|
|
190
|
+
const userId = extractUserId(token);
|
|
191
|
+
const userDir = getUserDir(baseUrl, userId);
|
|
192
|
+
ensureDir(userDir);
|
|
193
|
+
renameSync(rootTokenFile, join(userDir, "token.json"));
|
|
194
|
+
const rootConfigFile = join(platformDir, "config.json");
|
|
195
|
+
if (existsSync(rootConfigFile)) {
|
|
196
|
+
renameSync(rootConfigFile, join(userDir, "config.json"));
|
|
197
|
+
}
|
|
198
|
+
const rootContextLoaderFile = join(platformDir, "context-loader.json");
|
|
199
|
+
if (existsSync(rootContextLoaderFile)) {
|
|
200
|
+
renameSync(rootContextLoaderFile, join(userDir, "context-loader.json"));
|
|
201
|
+
}
|
|
202
|
+
const resolvedUrl = token.baseUrl || baseUrl;
|
|
203
|
+
const state = readState();
|
|
204
|
+
const activeUsers = { ...(state.activeUsers ?? {}) };
|
|
205
|
+
activeUsers[resolvedUrl] = userId;
|
|
206
|
+
writeState({ ...state, activeUsers });
|
|
207
|
+
}
|
|
208
|
+
function migrateAllPlatformsToUserScoped() {
|
|
209
|
+
const platformsDir = getPlatformsDirPath();
|
|
210
|
+
if (!existsSync(platformsDir))
|
|
211
|
+
return;
|
|
212
|
+
for (const entry of readdirSync(platformsDir)) {
|
|
213
|
+
const dirPath = join(platformsDir, entry);
|
|
214
|
+
if (!statSync(dirPath).isDirectory())
|
|
215
|
+
continue;
|
|
216
|
+
const rootToken = join(dirPath, "token.json");
|
|
217
|
+
const usersDir = join(dirPath, "users");
|
|
218
|
+
if (!existsSync(rootToken) || existsSync(usersDir))
|
|
219
|
+
continue;
|
|
220
|
+
const token = readJsonFile(rootToken);
|
|
221
|
+
if (!token?.baseUrl)
|
|
222
|
+
continue;
|
|
223
|
+
migratePlatformToUserScoped(token.baseUrl);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
// Store initialization
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
108
229
|
function ensureStoreReady() {
|
|
109
230
|
ensureConfigDir();
|
|
110
231
|
migrateLegacyFilesIfNeeded();
|
|
232
|
+
migrateAllPlatformsToUserScoped();
|
|
233
|
+
}
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
// Active user management
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
/** Read active user from state without triggering ensureStoreReady (avoids recursion). */
|
|
238
|
+
function getActiveUserRaw(baseUrl) {
|
|
239
|
+
const state = readJsonFile(getStateFilePath()) ?? {};
|
|
240
|
+
const userId = state.activeUsers?.[baseUrl];
|
|
241
|
+
if (userId)
|
|
242
|
+
return userId;
|
|
243
|
+
// Fallback: scan users/ dir and pick the first one
|
|
244
|
+
const usersDir = getUsersDirPath(baseUrl);
|
|
245
|
+
if (!existsSync(usersDir))
|
|
246
|
+
return null;
|
|
247
|
+
for (const entry of readdirSync(usersDir)) {
|
|
248
|
+
const entryPath = join(usersDir, entry);
|
|
249
|
+
if (statSync(entryPath).isDirectory() && existsSync(join(entryPath, "token.json"))) {
|
|
250
|
+
return entry;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
/** Get the active userId for a platform. */
|
|
256
|
+
export function getActiveUser(baseUrl) {
|
|
257
|
+
ensureStoreReady();
|
|
258
|
+
return getActiveUserRaw(baseUrl);
|
|
259
|
+
}
|
|
260
|
+
/** Set the active userId for a platform. */
|
|
261
|
+
export function setActiveUser(baseUrl, userId) {
|
|
262
|
+
ensureStoreReady();
|
|
263
|
+
const state = readState();
|
|
264
|
+
const activeUsers = { ...(state.activeUsers ?? {}) };
|
|
265
|
+
activeUsers[baseUrl] = userId;
|
|
266
|
+
writeState({ ...state, activeUsers });
|
|
111
267
|
}
|
|
268
|
+
/** List all user IDs stored under a platform. */
|
|
269
|
+
export function listUsers(baseUrl) {
|
|
270
|
+
ensureStoreReady();
|
|
271
|
+
const usersDir = getUsersDirPath(baseUrl);
|
|
272
|
+
if (!existsSync(usersDir))
|
|
273
|
+
return [];
|
|
274
|
+
const users = [];
|
|
275
|
+
for (const entry of readdirSync(usersDir)) {
|
|
276
|
+
const entryPath = join(usersDir, entry);
|
|
277
|
+
if (statSync(entryPath).isDirectory()) {
|
|
278
|
+
users.push(entry);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return users.sort();
|
|
282
|
+
}
|
|
283
|
+
/** Load a specific user's token (not necessarily the active user). */
|
|
284
|
+
export function loadUserTokenConfig(baseUrl, userId) {
|
|
285
|
+
ensureStoreReady();
|
|
286
|
+
return readJsonFile(join(getUserDir(baseUrl, userId), "token.json"));
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* List all user profiles for a platform, enriched with display names.
|
|
290
|
+
*
|
|
291
|
+
* Resolution order for username:
|
|
292
|
+
* 1. ``displayName`` field persisted in token.json (set at login via /oauth2/userinfo)
|
|
293
|
+
* 2. ``preferred_username`` or ``name`` decoded from id_token JWT
|
|
294
|
+
*/
|
|
295
|
+
export function listUserProfiles(baseUrl) {
|
|
296
|
+
const userIds = listUsers(baseUrl);
|
|
297
|
+
return userIds.map((userId) => {
|
|
298
|
+
const token = loadUserTokenConfig(baseUrl, userId);
|
|
299
|
+
let username;
|
|
300
|
+
let email;
|
|
301
|
+
if (token?.displayName) {
|
|
302
|
+
username = token.displayName;
|
|
303
|
+
}
|
|
304
|
+
if (token?.idToken) {
|
|
305
|
+
const payload = decodeJwtPayload(token.idToken);
|
|
306
|
+
if (payload) {
|
|
307
|
+
if (!username) {
|
|
308
|
+
if (typeof payload.preferred_username === "string")
|
|
309
|
+
username = payload.preferred_username;
|
|
310
|
+
else if (typeof payload.name === "string")
|
|
311
|
+
username = payload.name;
|
|
312
|
+
}
|
|
313
|
+
if (typeof payload.email === "string")
|
|
314
|
+
email = payload.email;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return { userId, username, email };
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
/** Resolve a user identifier (userId, username, or email) to a userId for the given platform.
|
|
321
|
+
* userId and username are matched case-sensitively; email is case-insensitive. */
|
|
322
|
+
export function resolveUserId(baseUrl, identifier) {
|
|
323
|
+
const users = listUsers(baseUrl);
|
|
324
|
+
if (users.includes(identifier))
|
|
325
|
+
return identifier;
|
|
326
|
+
const profiles = listUserProfiles(baseUrl);
|
|
327
|
+
// Exact match on username (case-sensitive)
|
|
328
|
+
const exact = profiles.find((p) => p.username === identifier);
|
|
329
|
+
if (exact)
|
|
330
|
+
return exact.userId;
|
|
331
|
+
// Email match (case-insensitive per RFC 5321)
|
|
332
|
+
const lower = identifier.toLowerCase();
|
|
333
|
+
const byEmail = profiles.find((p) => p.email?.toLowerCase() === lower);
|
|
334
|
+
return byEmail?.userId ?? null;
|
|
335
|
+
}
|
|
336
|
+
// ---------------------------------------------------------------------------
|
|
337
|
+
// Public API — platform & alias management
|
|
338
|
+
// ---------------------------------------------------------------------------
|
|
112
339
|
export function getConfigDir() {
|
|
113
340
|
return getConfigDirPath();
|
|
114
341
|
}
|
|
@@ -178,19 +405,32 @@ export function resolvePlatformIdentifier(value) {
|
|
|
178
405
|
}
|
|
179
406
|
return normalized;
|
|
180
407
|
}
|
|
408
|
+
// ---------------------------------------------------------------------------
|
|
409
|
+
// Token config (user-scoped)
|
|
410
|
+
// ---------------------------------------------------------------------------
|
|
181
411
|
export function loadTokenConfig(baseUrl) {
|
|
182
412
|
ensureStoreReady();
|
|
183
413
|
const targetBaseUrl = baseUrl ?? getCurrentPlatform();
|
|
184
414
|
if (!targetBaseUrl) {
|
|
185
415
|
return null;
|
|
186
416
|
}
|
|
187
|
-
return readJsonFile(
|
|
417
|
+
return readJsonFile(resolveFile(targetBaseUrl, "token.json"));
|
|
188
418
|
}
|
|
189
|
-
export function saveTokenConfig(config) {
|
|
419
|
+
export function saveTokenConfig(config, userId) {
|
|
190
420
|
ensureStoreReady();
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
421
|
+
const resolvedUser = userId ?? extractUserId(config);
|
|
422
|
+
const dir = getUserDir(config.baseUrl, resolvedUser);
|
|
423
|
+
ensureDir(dir);
|
|
424
|
+
writeJsonFile(join(dir, "token.json"), config);
|
|
425
|
+
// When KWEAVER_USER is set the caller is doing a one-off operation;
|
|
426
|
+
// don't change the persisted active user.
|
|
427
|
+
if (!process.env.KWEAVER_USER) {
|
|
428
|
+
setActiveUser(config.baseUrl, resolvedUser);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
// ---------------------------------------------------------------------------
|
|
432
|
+
// Client config (platform-level — shared across users)
|
|
433
|
+
// ---------------------------------------------------------------------------
|
|
194
434
|
export function loadClientConfig(baseUrl) {
|
|
195
435
|
ensureStoreReady();
|
|
196
436
|
const targetBaseUrl = baseUrl ?? getCurrentPlatform();
|
|
@@ -204,6 +444,11 @@ export function saveClientConfig(baseUrl, config) {
|
|
|
204
444
|
ensurePlatformDir(baseUrl);
|
|
205
445
|
writeJsonFile(getPlatformFile(baseUrl, "client.json"), { ...config, baseUrl });
|
|
206
446
|
}
|
|
447
|
+
export function deleteClientConfig(baseUrl) {
|
|
448
|
+
const filePath = getPlatformFile(baseUrl, "client.json");
|
|
449
|
+
if (existsSync(filePath))
|
|
450
|
+
rmSync(filePath, { force: true });
|
|
451
|
+
}
|
|
207
452
|
function migrateLegacyContextLoader(raw) {
|
|
208
453
|
const leg = raw;
|
|
209
454
|
if (leg?.knId && !Array.isArray(raw.configs)) {
|
|
@@ -220,7 +465,7 @@ export function loadContextLoaderConfig(baseUrl) {
|
|
|
220
465
|
if (!targetBaseUrl) {
|
|
221
466
|
return null;
|
|
222
467
|
}
|
|
223
|
-
const raw = readJsonFile(
|
|
468
|
+
const raw = readJsonFile(resolveFile(targetBaseUrl, "context-loader.json"));
|
|
224
469
|
if (!raw)
|
|
225
470
|
return null;
|
|
226
471
|
const migrated = migrateLegacyContextLoader(raw);
|
|
@@ -240,8 +485,16 @@ export function loadContextLoaderConfig(baseUrl) {
|
|
|
240
485
|
}
|
|
241
486
|
export function saveContextLoaderConfig(baseUrl, config) {
|
|
242
487
|
ensureStoreReady();
|
|
243
|
-
|
|
244
|
-
|
|
488
|
+
const userId = getActiveUser(baseUrl);
|
|
489
|
+
if (userId) {
|
|
490
|
+
const dir = getUserDir(baseUrl, userId);
|
|
491
|
+
ensureDir(dir);
|
|
492
|
+
writeJsonFile(join(dir, "context-loader.json"), config);
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
ensurePlatformDir(baseUrl);
|
|
496
|
+
writeJsonFile(getPlatformFile(baseUrl, "context-loader.json"), config);
|
|
497
|
+
}
|
|
245
498
|
}
|
|
246
499
|
export function getCurrentContextLoaderKn(baseUrl) {
|
|
247
500
|
ensureStoreReady();
|
|
@@ -297,7 +550,7 @@ export function removeContextLoaderEntry(baseUrl, name) {
|
|
|
297
550
|
return;
|
|
298
551
|
const newConfigs = config.configs.filter((c) => c.name !== name);
|
|
299
552
|
if (newConfigs.length === 0) {
|
|
300
|
-
const file =
|
|
553
|
+
const file = resolveFile(baseUrl, "context-loader.json");
|
|
301
554
|
if (existsSync(file))
|
|
302
555
|
rmSync(file, { force: true });
|
|
303
556
|
return;
|
|
@@ -308,18 +561,47 @@ export function removeContextLoaderEntry(baseUrl, name) {
|
|
|
308
561
|
}
|
|
309
562
|
saveContextLoaderConfig(baseUrl, { configs: newConfigs, current: newCurrent });
|
|
310
563
|
}
|
|
564
|
+
// ---------------------------------------------------------------------------
|
|
565
|
+
// Platform existence / session management
|
|
566
|
+
// ---------------------------------------------------------------------------
|
|
311
567
|
export function hasPlatform(baseUrl) {
|
|
312
568
|
ensureStoreReady();
|
|
313
|
-
|
|
569
|
+
const file = resolveFile(baseUrl, "token.json");
|
|
570
|
+
if (existsSync(file))
|
|
571
|
+
return true;
|
|
572
|
+
return listUsers(baseUrl).length > 0;
|
|
314
573
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
574
|
+
export function clearPlatformSession(baseUrl, userId) {
|
|
575
|
+
ensureStoreReady();
|
|
576
|
+
const target = userId ?? getActiveUser(baseUrl);
|
|
577
|
+
if (target) {
|
|
578
|
+
const tokenFile = join(getUserDir(baseUrl, target), "token.json");
|
|
579
|
+
if (existsSync(tokenFile))
|
|
580
|
+
rmSync(tokenFile, { force: true });
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
// Fallback: legacy flat layout
|
|
584
|
+
const legacyToken = getPlatformFile(baseUrl, "token.json");
|
|
585
|
+
if (existsSync(legacyToken))
|
|
586
|
+
rmSync(legacyToken, { force: true });
|
|
587
|
+
}
|
|
588
|
+
/** Delete a single user's profile directory under a platform. */
|
|
589
|
+
export function deleteUser(baseUrl, userId) {
|
|
319
590
|
ensureStoreReady();
|
|
320
|
-
const
|
|
321
|
-
if (existsSync(
|
|
322
|
-
rmSync(
|
|
591
|
+
const dir = getUserDir(baseUrl, userId);
|
|
592
|
+
if (existsSync(dir))
|
|
593
|
+
rmSync(dir, { recursive: true, force: true });
|
|
594
|
+
const state = readState();
|
|
595
|
+
if (state.activeUsers?.[baseUrl] === userId) {
|
|
596
|
+
const remaining = listUsers(baseUrl);
|
|
597
|
+
const au = { ...(state.activeUsers ?? {}) };
|
|
598
|
+
if (remaining.length > 0) {
|
|
599
|
+
au[baseUrl] = remaining[0];
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
delete au[baseUrl];
|
|
603
|
+
}
|
|
604
|
+
writeState({ ...state, activeUsers: Object.keys(au).length > 0 ? au : undefined });
|
|
323
605
|
}
|
|
324
606
|
}
|
|
325
607
|
export function deletePlatform(baseUrl) {
|
|
@@ -331,33 +613,76 @@ export function deletePlatform(baseUrl) {
|
|
|
331
613
|
deletePlatformAlias(baseUrl);
|
|
332
614
|
rmSync(platformDir, { recursive: true, force: true });
|
|
333
615
|
const state = readState();
|
|
616
|
+
const au = { ...(state.activeUsers ?? {}) };
|
|
617
|
+
delete au[baseUrl];
|
|
334
618
|
if (state.currentPlatform !== baseUrl) {
|
|
619
|
+
writeState({ ...state, activeUsers: Object.keys(au).length > 0 ? au : undefined });
|
|
335
620
|
return;
|
|
336
621
|
}
|
|
337
622
|
const remainingPlatforms = listPlatforms();
|
|
338
623
|
writeState({
|
|
339
624
|
...readState(),
|
|
340
625
|
currentPlatform: remainingPlatforms[0]?.baseUrl,
|
|
626
|
+
activeUsers: Object.keys(au).length > 0 ? au : undefined,
|
|
341
627
|
});
|
|
342
628
|
}
|
|
343
629
|
export function listPlatforms() {
|
|
344
630
|
ensureStoreReady();
|
|
345
631
|
const currentPlatform = getCurrentPlatform();
|
|
346
632
|
const items = [];
|
|
347
|
-
|
|
348
|
-
|
|
633
|
+
const platformsDir = getPlatformsDirPath();
|
|
634
|
+
if (!existsSync(platformsDir))
|
|
635
|
+
return items;
|
|
636
|
+
for (const entry of readdirSync(platformsDir)) {
|
|
637
|
+
const dirPath = join(platformsDir, entry);
|
|
349
638
|
if (!statSync(dirPath).isDirectory()) {
|
|
350
639
|
continue;
|
|
351
640
|
}
|
|
352
|
-
|
|
353
|
-
|
|
641
|
+
// Try to find the baseUrl from any available token
|
|
642
|
+
let baseUrl = null;
|
|
643
|
+
// Check users/ subdirectory first (new layout)
|
|
644
|
+
const usersDir = join(dirPath, "users");
|
|
645
|
+
if (existsSync(usersDir)) {
|
|
646
|
+
for (const userEntry of readdirSync(usersDir)) {
|
|
647
|
+
const userTokenPath = join(usersDir, userEntry, "token.json");
|
|
648
|
+
const userToken = readJsonFile(userTokenPath);
|
|
649
|
+
if (userToken?.baseUrl) {
|
|
650
|
+
baseUrl = userToken.baseUrl;
|
|
651
|
+
break;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
// Fallback: legacy flat layout
|
|
656
|
+
if (!baseUrl) {
|
|
657
|
+
const token = readJsonFile(join(dirPath, "token.json"));
|
|
658
|
+
if (token?.baseUrl) {
|
|
659
|
+
baseUrl = token.baseUrl;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
// Fallback: client.json
|
|
663
|
+
if (!baseUrl) {
|
|
664
|
+
const client = readJsonFile(join(dirPath, "client.json"));
|
|
665
|
+
if (client?.baseUrl) {
|
|
666
|
+
baseUrl = client.baseUrl;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (!baseUrl)
|
|
354
670
|
continue;
|
|
671
|
+
const hasToken = existsSync(resolveFile(baseUrl, "token.json"));
|
|
672
|
+
const activeUser = getActiveUserRaw(baseUrl);
|
|
673
|
+
let displayName;
|
|
674
|
+
if (activeUser) {
|
|
675
|
+
const tok = loadUserTokenConfig(baseUrl, activeUser);
|
|
676
|
+
if (tok?.displayName)
|
|
677
|
+
displayName = tok.displayName;
|
|
355
678
|
}
|
|
356
679
|
items.push({
|
|
357
|
-
baseUrl
|
|
358
|
-
hasToken
|
|
359
|
-
isCurrent:
|
|
360
|
-
alias: getPlatformAlias(
|
|
680
|
+
baseUrl,
|
|
681
|
+
hasToken,
|
|
682
|
+
isCurrent: baseUrl === currentPlatform,
|
|
683
|
+
alias: getPlatformAlias(baseUrl) ?? undefined,
|
|
684
|
+
userId: activeUser ?? undefined,
|
|
685
|
+
displayName,
|
|
361
686
|
});
|
|
362
687
|
}
|
|
363
688
|
items.sort((a, b) => a.baseUrl.localeCompare(b.baseUrl));
|
|
@@ -365,12 +690,20 @@ export function listPlatforms() {
|
|
|
365
690
|
}
|
|
366
691
|
function loadPlatformConfig(baseUrl) {
|
|
367
692
|
ensureStoreReady();
|
|
368
|
-
return readJsonFile(
|
|
693
|
+
return readJsonFile(resolveFile(baseUrl, "config.json"));
|
|
369
694
|
}
|
|
370
695
|
function savePlatformConfig(baseUrl, config) {
|
|
371
696
|
ensureStoreReady();
|
|
372
|
-
|
|
373
|
-
|
|
697
|
+
const userId = getActiveUser(baseUrl);
|
|
698
|
+
if (userId) {
|
|
699
|
+
const dir = getUserDir(baseUrl, userId);
|
|
700
|
+
ensureDir(dir);
|
|
701
|
+
writeJsonFile(join(dir, "config.json"), config);
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
ensurePlatformDir(baseUrl);
|
|
705
|
+
writeJsonFile(getPlatformFile(baseUrl, "config.json"), config);
|
|
706
|
+
}
|
|
374
707
|
}
|
|
375
708
|
export function loadPlatformBusinessDomain(baseUrl) {
|
|
376
709
|
return loadPlatformConfig(baseUrl)?.businessDomain ?? null;
|
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,9 @@ export type { AgentConfig, AgentInput, AgentInputField, AgentOutput, AgentLlmCon
|
|
|
49
49
|
export { BknResource } from "./resources/bkn.js";
|
|
50
50
|
export { ConversationsResource } from "./resources/conversations.js";
|
|
51
51
|
export { ContextLoaderResource } from "./resources/context-loader.js";
|
|
52
|
+
export { SkillsResource } from "./resources/skills.js";
|
|
53
|
+
export type { SkillStatus, SkillSummary, SkillInfo, SkillFileSummary, SkillContentIndex, SkillFileReadResult, RegisterSkillResult, DeleteSkillResult, UpdateSkillStatusResult, SkillListResult, ListSkillsOptions, ListSkillMarketOptions, GetSkillOptions, RegisterSkillContentOptions, RegisterSkillZipOptions, UpdateSkillStatusOptions, ReadSkillFileOptions, DownloadSkillOptions, DownloadedSkillArchive, } from "./api/skills.js";
|
|
54
|
+
export { listSkills, listSkillMarket, getSkill, deleteSkill, updateSkillStatus, registerSkillContent, registerSkillZip, getSkillContentIndex, fetchSkillContent, readSkillFile, fetchSkillFile, downloadSkill, installSkillArchive, } from "./api/skills.js";
|
|
52
55
|
export type { ViewField, DataView, CreateDataViewOptions, GetDataViewOptions, ListDataViewsOptions, DeleteDataViewOptions, FindDataViewOptions, QueryDataViewOptions, DataViewQueryResult, } from "./api/dataviews.js";
|
|
53
56
|
export { parseDataView, createDataView, getDataView, listDataViews, deleteDataView, findDataView, queryDataView, } from "./api/dataviews.js";
|
|
54
57
|
export { DataViewsResource } from "./resources/dataviews.js";
|
|
@@ -56,4 +59,6 @@ export type { BusinessDomain, ListBusinessDomainsOptions } from "./api/business-
|
|
|
56
59
|
export { listBusinessDomains } from "./api/business-domains.js";
|
|
57
60
|
export { HttpError, NetworkRequestError, fetchTextOrThrow } from "./utils/http.js";
|
|
58
61
|
export type { TokenConfig, ContextLoaderEntry, ContextLoaderConfig, } from "./config/store.js";
|
|
59
|
-
export {
|
|
62
|
+
export type { UserProfile } from "./config/store.js";
|
|
63
|
+
export { autoSelectBusinessDomain, getConfigDir, getCurrentPlatform, getActiveUser, setActiveUser, listUsers, listUserProfiles, resolveUserId, extractUserId, } from "./config/store.js";
|
|
64
|
+
export { decodeJwtPayload, extractUserIdFromJwt } from "./config/jwt.js";
|
package/dist/index.js
CHANGED
|
@@ -39,9 +39,13 @@ export { AgentsResource } from "./resources/agents.js";
|
|
|
39
39
|
export { BknResource } from "./resources/bkn.js";
|
|
40
40
|
export { ConversationsResource } from "./resources/conversations.js";
|
|
41
41
|
export { ContextLoaderResource } from "./resources/context-loader.js";
|
|
42
|
+
export { SkillsResource } from "./resources/skills.js";
|
|
43
|
+
export { listSkills, listSkillMarket, getSkill, deleteSkill, updateSkillStatus, registerSkillContent, registerSkillZip, getSkillContentIndex, fetchSkillContent, readSkillFile, fetchSkillFile, downloadSkill, installSkillArchive, } from "./api/skills.js";
|
|
42
44
|
export { parseDataView, createDataView, getDataView, listDataViews, deleteDataView, findDataView, queryDataView, } from "./api/dataviews.js";
|
|
43
45
|
export { DataViewsResource } from "./resources/dataviews.js";
|
|
44
46
|
export { listBusinessDomains } from "./api/business-domains.js";
|
|
45
47
|
// ── HTTP utilities ────────────────────────────────────────────────────────────
|
|
46
48
|
export { HttpError, NetworkRequestError, fetchTextOrThrow } from "./utils/http.js";
|
|
47
|
-
export { autoSelectBusinessDomain, getConfigDir, getCurrentPlatform } from "./config/store.js";
|
|
49
|
+
export { autoSelectBusinessDomain, getConfigDir, getCurrentPlatform, getActiveUser, setActiveUser, listUsers, listUserProfiles, resolveUserId, extractUserId, } from "./config/store.js";
|
|
50
|
+
// ── JWT utilities ─────────────────────────────────────────────────────────────
|
|
51
|
+
export { decodeJwtPayload, extractUserIdFromJwt } from "./config/jwt.js";
|
package/dist/resources/bkn.d.ts
CHANGED
|
@@ -32,6 +32,10 @@ export declare class BknResource {
|
|
|
32
32
|
queryProperties(knId: string, otId: string, body: Record<string, unknown>): Promise<unknown>;
|
|
33
33
|
querySubgraph(knId: string, body: Record<string, unknown>): Promise<unknown>;
|
|
34
34
|
queryAction(knId: string, atId: string, body: Record<string, unknown>): Promise<unknown>;
|
|
35
|
+
/**
|
|
36
|
+
* Execute an action type (has side effects).
|
|
37
|
+
* @param body - Must include `_instance_identities`: `[{"<primary_key>": "<value>"}]`
|
|
38
|
+
*/
|
|
35
39
|
executeAction(knId: string, atId: string, body: Record<string, unknown>): Promise<unknown>;
|
|
36
40
|
getExecution(knId: string, executionId: string): Promise<unknown>;
|
|
37
41
|
listActionLogs(knId: string, opts?: {
|
package/dist/resources/bkn.js
CHANGED
|
@@ -57,6 +57,10 @@ export class BknResource {
|
|
|
57
57
|
const raw = await actionTypeQuery({ ...this.ctx.base(), knId, atId, body: JSON.stringify(body) });
|
|
58
58
|
return JSON.parse(raw);
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Execute an action type (has side effects).
|
|
62
|
+
* @param body - Must include `_instance_identities`: `[{"<primary_key>": "<value>"}]`
|
|
63
|
+
*/
|
|
60
64
|
async executeAction(knId, atId, body) {
|
|
61
65
|
const raw = await actionTypeExecute({ ...this.ctx.base(), knId, atId, body: JSON.stringify(body) });
|
|
62
66
|
return JSON.parse(raw);
|
|
@@ -4,8 +4,11 @@ export declare class ConversationsResource {
|
|
|
4
4
|
constructor(ctx: ClientContext);
|
|
5
5
|
list(agentId: string, opts?: {
|
|
6
6
|
limit?: number;
|
|
7
|
+
page?: number;
|
|
8
|
+
size?: number;
|
|
9
|
+
version?: string;
|
|
7
10
|
}): Promise<unknown[]>;
|
|
8
|
-
listMessages(conversationId: string, opts?: {
|
|
9
|
-
|
|
11
|
+
listMessages(agentId: string, conversationId: string, opts?: {
|
|
12
|
+
version?: string;
|
|
10
13
|
}): Promise<unknown[]>;
|
|
11
14
|
}
|
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
import { listConversations, listMessages } from "../api/conversations.js";
|
|
2
|
+
import { fetchAgentInfo } from "../api/agent-chat.js";
|
|
2
3
|
export class ConversationsResource {
|
|
3
4
|
ctx;
|
|
4
5
|
constructor(ctx) {
|
|
5
6
|
this.ctx = ctx;
|
|
6
7
|
}
|
|
7
8
|
async list(agentId, opts = {}) {
|
|
8
|
-
const
|
|
9
|
+
const { version = "v0", limit, page, size } = opts;
|
|
10
|
+
const info = await fetchAgentInfo({ ...this.ctx.base(), agentId, version });
|
|
11
|
+
const raw = await listConversations({
|
|
12
|
+
...this.ctx.base(),
|
|
13
|
+
agentKey: info.key,
|
|
14
|
+
page: page ?? 1,
|
|
15
|
+
size: size ?? (limit ?? 10),
|
|
16
|
+
});
|
|
9
17
|
const parsed = JSON.parse(raw);
|
|
10
18
|
return Array.isArray(parsed) ? parsed : [];
|
|
11
19
|
}
|
|
12
|
-
async listMessages(conversationId, opts = {}) {
|
|
13
|
-
const
|
|
20
|
+
async listMessages(agentId, conversationId, opts = {}) {
|
|
21
|
+
const { version = "v0" } = opts;
|
|
22
|
+
const info = await fetchAgentInfo({ ...this.ctx.base(), agentId, version });
|
|
23
|
+
const raw = await listMessages({
|
|
24
|
+
...this.ctx.base(),
|
|
25
|
+
agentKey: info.key,
|
|
26
|
+
conversationId,
|
|
27
|
+
});
|
|
14
28
|
const parsed = JSON.parse(raw);
|
|
15
29
|
return Array.isArray(parsed) ? parsed : [];
|
|
16
30
|
}
|