@kweaver-ai/kweaver-sdk 0.5.2 → 0.6.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.
Files changed (57) hide show
  1. package/README.md +19 -1
  2. package/README.zh.md +19 -1
  3. package/dist/api/agent-chat.d.ts +7 -1
  4. package/dist/api/agent-chat.js +146 -40
  5. package/dist/api/agent-list.js +13 -13
  6. package/dist/api/business-domains.js +9 -5
  7. package/dist/api/context-loader.js +4 -1
  8. package/dist/api/conversations.js +4 -9
  9. package/dist/api/dataflow2.d.ts +95 -0
  10. package/dist/api/dataflow2.js +80 -0
  11. package/dist/api/headers.d.ts +2 -0
  12. package/dist/api/headers.js +7 -2
  13. package/dist/api/skills.js +2 -10
  14. package/dist/api/vega.d.ts +0 -16
  15. package/dist/api/vega.js +0 -33
  16. package/dist/auth/oauth.d.ts +7 -6
  17. package/dist/auth/oauth.js +170 -80
  18. package/dist/cli.js +21 -1
  19. package/dist/client.d.ts +9 -0
  20. package/dist/client.js +48 -8
  21. package/dist/commands/auth.js +103 -42
  22. package/dist/commands/bkn-schema.js +22 -0
  23. package/dist/commands/call.js +8 -5
  24. package/dist/commands/dataflow.d.ts +1 -0
  25. package/dist/commands/dataflow.js +251 -0
  26. package/dist/commands/explore-bkn.d.ts +79 -0
  27. package/dist/commands/explore-bkn.js +273 -0
  28. package/dist/commands/explore-chat.d.ts +3 -0
  29. package/dist/commands/explore-chat.js +193 -0
  30. package/dist/commands/explore-vega.d.ts +3 -0
  31. package/dist/commands/explore-vega.js +71 -0
  32. package/dist/commands/explore.d.ts +9 -0
  33. package/dist/commands/explore.js +258 -0
  34. package/dist/commands/vega.js +2 -104
  35. package/dist/config/no-auth.d.ts +3 -0
  36. package/dist/config/no-auth.js +5 -0
  37. package/dist/config/store.d.ts +8 -0
  38. package/dist/config/store.js +22 -0
  39. package/dist/index.d.ts +1 -1
  40. package/dist/index.js +1 -1
  41. package/dist/kweaver.d.ts +5 -0
  42. package/dist/kweaver.js +32 -2
  43. package/dist/resources/bkn.js +2 -3
  44. package/dist/resources/knowledge-networks.js +3 -8
  45. package/dist/resources/vega.d.ts +0 -6
  46. package/dist/resources/vega.js +1 -10
  47. package/dist/templates/explorer/app.js +136 -0
  48. package/dist/templates/explorer/bkn.js +747 -0
  49. package/dist/templates/explorer/chat.js +980 -0
  50. package/dist/templates/explorer/dashboard.js +82 -0
  51. package/dist/templates/explorer/index.html +35 -0
  52. package/dist/templates/explorer/style.css +2440 -0
  53. package/dist/templates/explorer/vega.js +291 -0
  54. package/dist/utils/browser.js +33 -10
  55. package/dist/utils/http.d.ts +3 -0
  56. package/dist/utils/http.js +37 -1
  57. package/package.json +9 -5
@@ -0,0 +1,273 @@
1
+ import { HttpError } from "../utils/http.js";
2
+ import { getKnowledgeNetwork, listObjectTypes, listRelationTypes, listActionTypes, } from "../api/knowledge-networks.js";
3
+ import { objectTypeQuery, objectTypeProperties, subgraph } from "../api/ontology-query.js";
4
+ import { semanticSearch } from "../api/semantic-search.js";
5
+ // ── Constants ───────────────────────────────────────────────────────────────
6
+ export const EXPLORE_BOOTSTRAP_RETRY_DELAY_MS = 300;
7
+ export const EXPLORE_BOOTSTRAP_MAX_ATTEMPTS = 2;
8
+ // ── Meta builder ────────────────────────────────────────────────────────────
9
+ export function buildMeta(knRaw, otRaw, rtRaw, atRaw) {
10
+ const kn = JSON.parse(knRaw);
11
+ const otParsed = JSON.parse(otRaw);
12
+ const otItems = (Array.isArray(otParsed) ? otParsed
13
+ : Array.isArray(otParsed.entries) ? otParsed.entries
14
+ : Array.isArray(otParsed.object_types) ? otParsed.object_types
15
+ : []);
16
+ const rtParsed = JSON.parse(rtRaw);
17
+ const rtItems = (Array.isArray(rtParsed) ? rtParsed
18
+ : Array.isArray(rtParsed.entries) ? rtParsed.entries
19
+ : Array.isArray(rtParsed.relation_types) ? rtParsed.relation_types
20
+ : []);
21
+ const atParsed = JSON.parse(atRaw);
22
+ const atItems = (Array.isArray(atParsed) ? atParsed
23
+ : Array.isArray(atParsed.entries) ? atParsed.entries
24
+ : Array.isArray(atParsed.action_types) ? atParsed.action_types
25
+ : []);
26
+ return {
27
+ bkn: { id: kn.id, name: kn.name },
28
+ statistics: {
29
+ object_count: kn.statistics?.object_count ?? 0,
30
+ relation_count: kn.statistics?.relation_count ?? 0,
31
+ },
32
+ objectTypes: otItems.map((o) => {
33
+ const props = o.properties ?? o.data_properties ?? [];
34
+ return {
35
+ id: o.id,
36
+ name: o.name,
37
+ displayKey: o.display_key ?? "",
38
+ propertyCount: props.length,
39
+ properties: props.map((p) => ({
40
+ name: p.name,
41
+ ...(p.type !== undefined ? { type: p.type } : {}),
42
+ })),
43
+ };
44
+ }),
45
+ relationTypes: rtItems.map((r) => ({
46
+ id: r.id,
47
+ name: r.name,
48
+ sourceOtId: r.source_object_type_id,
49
+ targetOtId: r.target_object_type_id,
50
+ sourceOtName: r.source_object_type?.name ?? "",
51
+ targetOtName: r.target_object_type?.name ?? "",
52
+ })),
53
+ actionTypes: atItems.map((a) => ({
54
+ id: a.id,
55
+ name: a.name,
56
+ })),
57
+ };
58
+ }
59
+ // ── Bootstrap helpers ───────────────────────────────────────────────────────
60
+ function getErrorMessage(error) {
61
+ const parts = [];
62
+ if (error instanceof Error) {
63
+ if (error.message) {
64
+ parts.push(error.message);
65
+ }
66
+ const cause = "cause" in error && error.cause instanceof Error ? error.cause.message : "";
67
+ if (cause) {
68
+ parts.push(cause);
69
+ }
70
+ }
71
+ else {
72
+ parts.push(String(error));
73
+ }
74
+ return parts.join(" ").toLowerCase();
75
+ }
76
+ export function isRetryableExploreBootstrapError(error) {
77
+ if (error instanceof HttpError) {
78
+ return false;
79
+ }
80
+ const message = getErrorMessage(error);
81
+ if (!message) {
82
+ return false;
83
+ }
84
+ return [
85
+ "fetch failed",
86
+ "client network socket disconnected",
87
+ "socket hang up",
88
+ "econnreset",
89
+ "econnrefused",
90
+ "etimedout",
91
+ "tls",
92
+ "secure tls connection",
93
+ ].some((token) => message.includes(token));
94
+ }
95
+ function sleep(ms) {
96
+ return new Promise((resolve) => {
97
+ setTimeout(resolve, ms);
98
+ });
99
+ }
100
+ export async function loadExploreMetaWithRetry(token, knId, businessDomain) {
101
+ for (let attempt = 1; attempt <= EXPLORE_BOOTSTRAP_MAX_ATTEMPTS; attempt++) {
102
+ try {
103
+ const [knRaw, otRaw, rtRaw, atRaw] = await Promise.all([
104
+ getKnowledgeNetwork({
105
+ baseUrl: token.baseUrl,
106
+ accessToken: token.accessToken,
107
+ knId,
108
+ businessDomain,
109
+ include_statistics: true,
110
+ }),
111
+ listObjectTypes({
112
+ baseUrl: token.baseUrl,
113
+ accessToken: token.accessToken,
114
+ knId,
115
+ businessDomain,
116
+ }),
117
+ listRelationTypes({
118
+ baseUrl: token.baseUrl,
119
+ accessToken: token.accessToken,
120
+ knId,
121
+ businessDomain,
122
+ }),
123
+ listActionTypes({
124
+ baseUrl: token.baseUrl,
125
+ accessToken: token.accessToken,
126
+ knId,
127
+ businessDomain,
128
+ }),
129
+ ]);
130
+ return buildMeta(knRaw, otRaw, rtRaw, atRaw);
131
+ }
132
+ catch (error) {
133
+ if (attempt >= EXPLORE_BOOTSTRAP_MAX_ATTEMPTS || !isRetryableExploreBootstrapError(error)) {
134
+ throw error;
135
+ }
136
+ await sleep(EXPLORE_BOOTSTRAP_RETRY_DELAY_MS);
137
+ }
138
+ }
139
+ throw new Error("Failed to load explorer metadata.");
140
+ }
141
+ // ── HTTP helpers ────────────────────────────────────────────────────────────
142
+ const MAX_BODY_BYTES = 1024 * 1024; // 1 MB
143
+ export function readBody(req) {
144
+ return new Promise((resolve, reject) => {
145
+ const chunks = [];
146
+ let size = 0;
147
+ req.on("data", (chunk) => {
148
+ size += chunk.length;
149
+ if (size > MAX_BODY_BYTES) {
150
+ req.destroy();
151
+ reject(new Error("Request body too large"));
152
+ return;
153
+ }
154
+ chunks.push(chunk);
155
+ });
156
+ req.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
157
+ req.on("error", reject);
158
+ });
159
+ }
160
+ export function jsonResponse(res, status, data) {
161
+ const body = JSON.stringify(data);
162
+ res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
163
+ res.end(body);
164
+ }
165
+ export function handleApiError(res, error) {
166
+ if (error instanceof HttpError) {
167
+ let detail = "";
168
+ try {
169
+ const parsed = JSON.parse(error.body);
170
+ detail = typeof parsed.description === "string" ? parsed.description : "";
171
+ }
172
+ catch { /* ignore */ }
173
+ jsonResponse(res, error.status, {
174
+ error: detail || error.message,
175
+ upstream_status: error.status,
176
+ });
177
+ }
178
+ else if (error instanceof Error &&
179
+ "causeMessage" in error &&
180
+ typeof error.causeMessage === "string") {
181
+ // NetworkRequestError — include cause and URL for diagnosis
182
+ const net = error;
183
+ const detail = [net.causeMessage, net.url, net.hint].filter(Boolean).join(" | ");
184
+ console.error(`[network-error] ${detail}`);
185
+ jsonResponse(res, 502, { error: `Upstream unreachable: ${net.causeMessage}` });
186
+ }
187
+ else {
188
+ const message = error instanceof Error ? error.message : String(error);
189
+ jsonResponse(res, 500, { error: message });
190
+ }
191
+ }
192
+ export function registerBknRoutes(meta, getToken, businessDomain) {
193
+ const knId = meta.bkn.id;
194
+ const routes = new Map();
195
+ routes.set("GET /api/bkn/meta", (_req, res) => {
196
+ jsonResponse(res, 200, meta);
197
+ });
198
+ routes.set("POST /api/bkn/instances", async (req, res) => {
199
+ try {
200
+ const bodyStr = await readBody(req);
201
+ const body = JSON.parse(bodyStr);
202
+ const queryBody = JSON.stringify({
203
+ limit: body.limit ?? 50,
204
+ ...(body.search_after ? { search_after: body.search_after } : {}),
205
+ ...(body.condition ? { condition: body.condition } : {}),
206
+ ...(body._instance_identities ? { _instance_identities: body._instance_identities } : {}),
207
+ });
208
+ const t = await getToken();
209
+ const result = await objectTypeQuery({
210
+ baseUrl: t.baseUrl, accessToken: t.accessToken,
211
+ knId, otId: body.otId, body: queryBody, businessDomain,
212
+ });
213
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
214
+ res.end(result);
215
+ }
216
+ catch (error) {
217
+ handleApiError(res, error);
218
+ }
219
+ });
220
+ routes.set("POST /api/bkn/subgraph", async (req, res) => {
221
+ try {
222
+ const bodyStr = await readBody(req);
223
+ const parsed = JSON.parse(bodyStr);
224
+ const hasRelationPaths = Array.isArray(parsed.relation_type_paths);
225
+ const t = await getToken();
226
+ const result = await subgraph({
227
+ baseUrl: t.baseUrl, accessToken: t.accessToken,
228
+ knId, body: bodyStr, businessDomain,
229
+ ...(hasRelationPaths ? { queryType: "relation_path" } : {}),
230
+ });
231
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
232
+ res.end(result);
233
+ }
234
+ catch (error) {
235
+ handleApiError(res, error);
236
+ }
237
+ });
238
+ routes.set("POST /api/bkn/search", async (req, res) => {
239
+ try {
240
+ const bodyStr = await readBody(req);
241
+ const body = JSON.parse(bodyStr);
242
+ const t = await getToken();
243
+ const result = await semanticSearch({
244
+ baseUrl: t.baseUrl, accessToken: t.accessToken,
245
+ knId, query: body.query, businessDomain,
246
+ maxConcepts: body.maxConcepts,
247
+ });
248
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
249
+ res.end(result);
250
+ }
251
+ catch (error) {
252
+ handleApiError(res, error);
253
+ }
254
+ });
255
+ routes.set("POST /api/bkn/properties", async (req, res) => {
256
+ try {
257
+ const bodyStr = await readBody(req);
258
+ const body = JSON.parse(bodyStr);
259
+ const { otId, ...rest } = body;
260
+ const t = await getToken();
261
+ const result = await objectTypeProperties({
262
+ baseUrl: t.baseUrl, accessToken: t.accessToken,
263
+ knId, otId, body: JSON.stringify(rest), businessDomain,
264
+ });
265
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
266
+ res.end(result);
267
+ }
268
+ catch (error) {
269
+ handleApiError(res, error);
270
+ }
271
+ });
272
+ return routes;
273
+ }
@@ -0,0 +1,3 @@
1
+ import { IncomingMessage, ServerResponse } from "node:http";
2
+ import { type TokenProvider } from "./explore-bkn.js";
3
+ export declare function registerChatRoutes(getToken: TokenProvider, businessDomain: string): Map<string, (req: IncomingMessage, res: ServerResponse) => void>;
@@ -0,0 +1,193 @@
1
+ import { listAgents } from "../api/agent-list.js";
2
+ import { fetchAgentInfo, sendChatRequestStream } from "../api/agent-chat.js";
3
+ import { getTracesByConversation } from "../api/conversations.js";
4
+ import { readBody, handleApiError, jsonResponse } from "./explore-bkn.js";
5
+ // ── Chat route handlers ──────────────────────────────────────────────────────
6
+ export function registerChatRoutes(getToken, businessDomain) {
7
+ const routes = new Map();
8
+ // GET /api/chat/agents — list published agents
9
+ routes.set("GET /api/chat/agents", async (_req, res) => {
10
+ try {
11
+ const t = await getToken();
12
+ const raw = await listAgents({
13
+ baseUrl: t.baseUrl,
14
+ accessToken: t.accessToken,
15
+ businessDomain,
16
+ limit: 200,
17
+ });
18
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
19
+ res.end(raw);
20
+ }
21
+ catch (error) {
22
+ handleApiError(res, error);
23
+ }
24
+ });
25
+ // POST /api/chat/send — stream a chat response via SSE
26
+ routes.set("POST /api/chat/send", async (req, res) => {
27
+ let bodyStr;
28
+ try {
29
+ bodyStr = await readBody(req);
30
+ }
31
+ catch {
32
+ res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
33
+ res.end(JSON.stringify({ error: "Failed to read request body" }));
34
+ return;
35
+ }
36
+ let agentId;
37
+ let message;
38
+ let conversationId;
39
+ let version;
40
+ try {
41
+ const body = JSON.parse(bodyStr);
42
+ agentId = body.agentId ?? "";
43
+ message = body.message ?? "";
44
+ conversationId = body.conversationId;
45
+ version = body.version;
46
+ }
47
+ catch {
48
+ res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
49
+ res.end(JSON.stringify({ error: "Invalid JSON body" }));
50
+ return;
51
+ }
52
+ if (!agentId || !message) {
53
+ res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
54
+ res.end(JSON.stringify({ error: "agentId and message are required" }));
55
+ return;
56
+ }
57
+ // Fetch agent info to get key + version
58
+ const t = await getToken();
59
+ let agentInfo;
60
+ try {
61
+ agentInfo = await fetchAgentInfo({
62
+ baseUrl: t.baseUrl,
63
+ accessToken: t.accessToken,
64
+ agentId,
65
+ version: version ?? "v0",
66
+ businessDomain,
67
+ });
68
+ }
69
+ catch (error) {
70
+ handleApiError(res, error);
71
+ return;
72
+ }
73
+ // Set SSE response headers
74
+ res.writeHead(200, {
75
+ "Content-Type": "text/event-stream; charset=utf-8",
76
+ "Cache-Control": "no-cache",
77
+ Connection: "keep-alive",
78
+ "X-Accel-Buffering": "no",
79
+ });
80
+ // SSE heartbeat — keeps connection alive and lets client detect stalls
81
+ const heartbeat = setInterval(() => {
82
+ try {
83
+ res.write(": heartbeat\n\n");
84
+ }
85
+ catch { /* connection gone */ }
86
+ }, 15000);
87
+ // Stream chat response
88
+ try {
89
+ const result = await sendChatRequestStream({
90
+ baseUrl: t.baseUrl,
91
+ accessToken: t.accessToken,
92
+ agentId: agentInfo.id,
93
+ agentKey: agentInfo.key,
94
+ agentVersion: agentInfo.version,
95
+ query: message,
96
+ conversationId,
97
+ stream: true,
98
+ businessDomain,
99
+ }, {
100
+ onTextDelta: (fullText, currentSegmentText) => {
101
+ const event = JSON.stringify({ type: "text", fullText, currentText: currentSegmentText });
102
+ res.write(`data: ${event}\n\n`);
103
+ },
104
+ onProgress: (items) => {
105
+ const event = JSON.stringify({ type: "progress", items });
106
+ res.write(`data: ${event}\n\n`);
107
+ },
108
+ onSegmentComplete: (segmentText, segmentIndex) => {
109
+ const event = JSON.stringify({ type: "segment", text: segmentText, index: segmentIndex });
110
+ res.write(`data: ${event}\n\n`);
111
+ },
112
+ onStepMeta: (meta) => {
113
+ const event = JSON.stringify({ type: "step_meta", meta });
114
+ res.write(`data: ${event}\n\n`);
115
+ },
116
+ onConversationId: (convId) => {
117
+ const event = JSON.stringify({ type: "conversation_id", conversationId: convId });
118
+ res.write(`data: ${event}\n\n`);
119
+ },
120
+ });
121
+ clearInterval(heartbeat);
122
+ const doneEvent = JSON.stringify({
123
+ type: "done",
124
+ conversationId: result.conversationId ?? conversationId ?? "",
125
+ });
126
+ res.write(`data: ${doneEvent}\n\n`);
127
+ res.end();
128
+ }
129
+ catch (error) {
130
+ clearInterval(heartbeat);
131
+ // Extract detailed error info — HttpError carries the upstream response body
132
+ let errMsg = error instanceof Error ? error.message : String(error);
133
+ let errDetail;
134
+ if (error && typeof error === "object" && "body" in error) {
135
+ const body = error.body;
136
+ if (body) {
137
+ errDetail = body;
138
+ // Try to extract a human-readable message from JSON body
139
+ try {
140
+ const parsed = JSON.parse(body);
141
+ const desc = parsed.description || parsed.detail || parsed.message || parsed.error;
142
+ if (desc)
143
+ errMsg += `: ${desc}`;
144
+ if (parsed.solution)
145
+ errMsg += ` (${parsed.solution})`;
146
+ }
147
+ catch {
148
+ errMsg += `: ${body.slice(0, 500)}`;
149
+ }
150
+ }
151
+ }
152
+ if (!res.headersSent) {
153
+ res.writeHead(500, { "Content-Type": "application/json; charset=utf-8" });
154
+ res.end(JSON.stringify({ error: errMsg, detail: errDetail }));
155
+ }
156
+ else {
157
+ const errEvent = JSON.stringify({
158
+ type: "error",
159
+ error: errMsg,
160
+ detail: errDetail,
161
+ });
162
+ res.write(`data: ${errEvent}\n\n`);
163
+ res.end();
164
+ }
165
+ }
166
+ });
167
+ // GET /api/chat/trace?agentId=X&conversationId=Y — fetch trace data
168
+ routes.set("GET /api/chat/trace", async (req, res) => {
169
+ try {
170
+ const url = new URL(req.url ?? "/", "http://localhost");
171
+ const agentId = url.searchParams.get("agentId") || "";
172
+ const conversationId = url.searchParams.get("conversationId") || "";
173
+ if (!agentId || !conversationId) {
174
+ jsonResponse(res, 400, { error: "agentId and conversationId are required" });
175
+ return;
176
+ }
177
+ const t = await getToken();
178
+ const raw = await getTracesByConversation({
179
+ baseUrl: t.baseUrl,
180
+ accessToken: t.accessToken,
181
+ agentId,
182
+ conversationId,
183
+ businessDomain,
184
+ });
185
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
186
+ res.end(raw);
187
+ }
188
+ catch (error) {
189
+ handleApiError(res, error);
190
+ }
191
+ });
192
+ return routes;
193
+ }
@@ -0,0 +1,3 @@
1
+ import { IncomingMessage, ServerResponse } from "node:http";
2
+ import { type TokenProvider } from "./explore-bkn.js";
3
+ export declare function registerVegaRoutes(getToken: TokenProvider, businessDomain: string): Map<string, (req: IncomingMessage, res: ServerResponse) => void>;
@@ -0,0 +1,71 @@
1
+ import { listVegaCatalogs, vegaCatalogHealthStatus, listVegaCatalogResources, queryVegaResourceData, } from "../api/vega.js";
2
+ import { readBody, jsonResponse, handleApiError } from "./explore-bkn.js";
3
+ // ── Vega route handlers ──────────────────────────────────────────────────────
4
+ export function registerVegaRoutes(getToken, businessDomain) {
5
+ const routes = new Map();
6
+ // GET /api/vega/catalogs — list catalogs + health status in parallel
7
+ routes.set("GET /api/vega/catalogs", async (_req, res) => {
8
+ try {
9
+ const t = await getToken();
10
+ const [catalogsResult, healthResult] = await Promise.allSettled([
11
+ listVegaCatalogs({
12
+ baseUrl: t.baseUrl, accessToken: t.accessToken, businessDomain,
13
+ }),
14
+ vegaCatalogHealthStatus({
15
+ baseUrl: t.baseUrl, accessToken: t.accessToken, businessDomain, ids: "all",
16
+ }),
17
+ ]);
18
+ const catalogs = catalogsResult.status === "fulfilled"
19
+ ? JSON.parse(catalogsResult.value)
20
+ : { error: String(catalogsResult.reason) };
21
+ const health = healthResult.status === "fulfilled"
22
+ ? JSON.parse(healthResult.value)
23
+ : { error: String(healthResult.reason) };
24
+ jsonResponse(res, 200, { catalogs, health });
25
+ }
26
+ catch (error) {
27
+ handleApiError(res, error);
28
+ }
29
+ });
30
+ // GET /api/vega/catalog-resources?catalogId=<id> — list resources in a catalog
31
+ routes.set("GET /api/vega/catalog-resources", async (req, res) => {
32
+ try {
33
+ const catalogId = new URL(req.url ?? "/", "http://localhost").searchParams.get("catalogId");
34
+ if (!catalogId) {
35
+ jsonResponse(res, 400, { error: "catalogId query parameter is required" });
36
+ return;
37
+ }
38
+ const t = await getToken();
39
+ const raw = await listVegaCatalogResources({
40
+ baseUrl: t.baseUrl, accessToken: t.accessToken, businessDomain, id: catalogId,
41
+ });
42
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
43
+ res.end(raw);
44
+ }
45
+ catch (error) {
46
+ handleApiError(res, error);
47
+ }
48
+ });
49
+ // POST /api/vega/query — query resource data
50
+ routes.set("POST /api/vega/query", async (req, res) => {
51
+ try {
52
+ const bodyStr = await readBody(req);
53
+ const body = JSON.parse(bodyStr);
54
+ if (!body.resourceId) {
55
+ jsonResponse(res, 400, { error: "resourceId is required" });
56
+ return;
57
+ }
58
+ const t = await getToken();
59
+ const raw = await queryVegaResourceData({
60
+ baseUrl: t.baseUrl, accessToken: t.accessToken, businessDomain,
61
+ id: body.resourceId, body: JSON.stringify(body.query ?? {}),
62
+ });
63
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
64
+ res.end(raw);
65
+ }
66
+ catch (error) {
67
+ handleApiError(res, error);
68
+ }
69
+ });
70
+ return routes;
71
+ }
@@ -0,0 +1,9 @@
1
+ export interface ExploreOptions {
2
+ knId: string;
3
+ agentId: string;
4
+ port: number;
5
+ open: boolean;
6
+ businessDomain: string;
7
+ }
8
+ export declare function parseExploreArgs(args: string[]): ExploreOptions;
9
+ export declare function runExploreCommand(args: string[]): Promise<number>;