@kweaver-ai/kweaver-sdk 0.8.2 → 0.8.4

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 (107) hide show
  1. package/README.md +26 -52
  2. package/README.zh.md +27 -46
  3. package/dist/api/agent-chat.d.ts +10 -2
  4. package/dist/api/agent-chat.js +19 -5
  5. package/dist/api/datasources.d.ts +14 -0
  6. package/dist/api/datasources.js +14 -0
  7. package/dist/api/resources.d.ts +94 -0
  8. package/dist/api/resources.js +166 -0
  9. package/dist/cli.js +103 -23
  10. package/dist/client.d.ts +10 -4
  11. package/dist/client.js +12 -6
  12. package/dist/commands/agent-members.js +27 -11
  13. package/dist/commands/agent.js +383 -272
  14. package/dist/commands/auth.js +184 -71
  15. package/dist/commands/bkn-metric.js +37 -16
  16. package/dist/commands/bkn-ops.d.ts +1 -1
  17. package/dist/commands/bkn-ops.js +192 -93
  18. package/dist/commands/bkn-query.js +99 -31
  19. package/dist/commands/bkn-schema.d.ts +3 -3
  20. package/dist/commands/bkn-schema.js +127 -86
  21. package/dist/commands/bkn.js +158 -116
  22. package/dist/commands/call.js +23 -13
  23. package/dist/commands/config.js +22 -12
  24. package/dist/commands/context-loader.js +98 -92
  25. package/dist/commands/dataflow.js +14 -6
  26. package/dist/commands/ds.d.ts +0 -31
  27. package/dist/commands/ds.js +18 -426
  28. package/dist/commands/explore-bkn.d.ts +7 -1
  29. package/dist/commands/explore-bkn.js +32 -3
  30. package/dist/commands/explore.js +18 -15
  31. package/dist/commands/model.js +53 -42
  32. package/dist/commands/resource.d.ts +1 -0
  33. package/dist/commands/{dataview.js → resource.js} +62 -84
  34. package/dist/commands/skill.js +201 -65
  35. package/dist/commands/token.js +11 -0
  36. package/dist/commands/tool.js +46 -29
  37. package/dist/commands/toolbox.js +31 -15
  38. package/dist/commands/vega.js +466 -250
  39. package/dist/help/format.d.ts +65 -0
  40. package/dist/help/format.js +141 -0
  41. package/dist/index.d.ts +3 -3
  42. package/dist/index.js +2 -2
  43. package/dist/resources/datasources.d.ts +7 -0
  44. package/dist/resources/datasources.js +7 -0
  45. package/dist/resources/{dataviews.d.ts → resources.d.ts} +10 -11
  46. package/dist/resources/{dataviews.js → resources.js} +12 -13
  47. package/dist/templates/explorer/bkn.js +860 -9
  48. package/dist/templates/explorer/index.html +1 -0
  49. package/dist/templates/explorer/style.css +225 -0
  50. package/dist/templates/explorer/vendor/g6.min.js +68 -0
  51. package/dist/trace-ai/eval-set/schemas.d.ts +1 -0
  52. package/dist/trace-ai/eval-set/schemas.js +4 -0
  53. package/dist/trace-ai/eval-set/types.d.ts +2 -0
  54. package/dist/trace-ai/exp/capture-fingerprint.d.ts +10 -0
  55. package/dist/trace-ai/exp/capture-fingerprint.js +12 -0
  56. package/dist/trace-ai/exp/context/context-assembler.d.ts +18 -0
  57. package/dist/trace-ai/exp/context/context-assembler.js +42 -0
  58. package/dist/trace-ai/exp/context/failure-analyzer.d.ts +22 -0
  59. package/dist/trace-ai/exp/context/failure-analyzer.js +59 -0
  60. package/dist/trace-ai/exp/context/kn-data-prober.d.ts +13 -0
  61. package/dist/trace-ai/exp/context/kn-data-prober.js +38 -0
  62. package/dist/trace-ai/exp/context/kn-schema-client.d.ts +14 -0
  63. package/dist/trace-ai/exp/context/kn-schema-client.js +41 -0
  64. package/dist/trace-ai/exp/context/retrieval-health.d.ts +32 -0
  65. package/dist/trace-ai/exp/context/retrieval-health.js +138 -0
  66. package/dist/trace-ai/exp/context/vega-catalog-client.d.ts +14 -0
  67. package/dist/trace-ai/exp/context/vega-catalog-client.js +15 -0
  68. package/dist/trace-ai/exp/coordinator.d.ts +34 -21
  69. package/dist/trace-ai/exp/coordinator.js +246 -24
  70. package/dist/trace-ai/exp/eval-runner.js +4 -2
  71. package/dist/trace-ai/exp/exp-store/events-jsonl.d.ts +1 -0
  72. package/dist/trace-ai/exp/exp-store/events-jsonl.js +18 -0
  73. package/dist/trace-ai/exp/exp-store/expected-fingerprint.d.ts +3 -0
  74. package/dist/trace-ai/exp/exp-store/expected-fingerprint.js +31 -0
  75. package/dist/trace-ai/exp/exp-store/index.d.ts +63 -2
  76. package/dist/trace-ai/exp/exp-store/index.js +2 -1
  77. package/dist/trace-ai/exp/exp-store/rollback-yaml.d.ts +12 -0
  78. package/dist/trace-ai/exp/exp-store/rollback-yaml.js +29 -0
  79. package/dist/trace-ai/exp/index.d.ts +2 -0
  80. package/dist/trace-ai/exp/index.js +68 -3
  81. package/dist/trace-ai/exp/info.js +1 -1
  82. package/dist/trace-ai/exp/patch/index.d.ts +13 -2
  83. package/dist/trace-ai/exp/patch/index.js +65 -10
  84. package/dist/trace-ai/exp/patch/kn-api-client.d.ts +40 -0
  85. package/dist/trace-ai/exp/patch/kn-api-client.js +14 -0
  86. package/dist/trace-ai/exp/patch/kn.d.ts +8 -0
  87. package/dist/trace-ai/exp/patch/kn.js +36 -0
  88. package/dist/trace-ai/exp/patch/skill-api-client.d.ts +17 -0
  89. package/dist/trace-ai/exp/patch/skill-api-client.js +14 -0
  90. package/dist/trace-ai/exp/patch/skill-content.d.ts +9 -0
  91. package/dist/trace-ai/exp/patch/skill-content.js +12 -0
  92. package/dist/trace-ai/exp/preflight.d.ts +77 -0
  93. package/dist/trace-ai/exp/preflight.js +148 -0
  94. package/dist/trace-ai/exp/providers/synthesizer-client.d.ts +3 -14
  95. package/dist/trace-ai/exp/providers/synthesizer-client.js +53 -35
  96. package/dist/trace-ai/exp/providers/triage-client.d.ts +15 -2
  97. package/dist/trace-ai/exp/providers/triage-client.js +143 -28
  98. package/dist/trace-ai/exp/run-preflight.d.ts +19 -0
  99. package/dist/trace-ai/exp/run-preflight.js +56 -0
  100. package/dist/trace-ai/exp/schemas.d.ts +402 -44
  101. package/dist/trace-ai/exp/schemas.js +131 -18
  102. package/dist/utils/deprecation.d.ts +1 -0
  103. package/dist/utils/deprecation.js +18 -0
  104. package/package.json +2 -1
  105. package/dist/api/dataviews.d.ts +0 -117
  106. package/dist/api/dataviews.js +0 -265
  107. package/dist/commands/dataview.d.ts +0 -8
@@ -98,6 +98,12 @@ export async function runDataflowCommand(args) {
98
98
  let exitCode = 0;
99
99
  const parser = yargs(args)
100
100
  .scriptName("kweaver dataflow")
101
+ .usage("Dataflow document workflows — list, run, runs, logs, templates, create*\n\n" +
102
+ "USAGE\n" +
103
+ " kweaver dataflow <subcommand> [flags]")
104
+ .epilog("LEARN MORE\n" +
105
+ " Use `kweaver dataflow <subcommand> --help` for flag details\n" +
106
+ " See docs/cli_conventions.md §8 for help format spec")
101
107
  .exitProcess(false)
102
108
  .help()
103
109
  .version(false)
@@ -130,12 +136,14 @@ export async function runDataflowCommand(args) {
130
136
  return 0;
131
137
  });
132
138
  })
133
- .command("run <dagId>", "Trigger one dataflow run", (command) => command
134
- .positional("dagId", { type: "string" })
135
- .option("file", { type: "string" })
136
- .option("url", { type: "string" })
137
- .option("name", { type: "string" })
138
- .option("biz-domain", { alias: "bd", type: "string" })
139
+ .command("run <dagId>", "Trigger one dataflow run (provide --file or --url+--name)", (command) => command
140
+ .positional("dagId", { type: "string", describe: "Dataflow DAG id" })
141
+ .option("file", { type: "string", describe: "Path to local file to upload (multipart)" })
142
+ .option("url", { type: "string", describe: "Remote URL to fetch payload from (requires --name)" })
143
+ .option("name", { type: "string", describe: "Filename for --url payload" })
144
+ .option("biz-domain", { alias: "bd", type: "string", describe: "Business domain (default: bd_public)" })
145
+ .example("kweaver dataflow run dag-123 --file ./input.csv", "Upload local file")
146
+ .example("kweaver dataflow run dag-123 --url https://host/x.csv --name x.csv", "Fetch from remote URL")
139
147
  .check((argv) => {
140
148
  const hasFile = typeof argv.file === "string";
141
149
  const hasUrl = typeof argv.url === "string";
@@ -1,33 +1,3 @@
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
- };
8
- /**
9
- * Match candidate signature against a list response (the kind returned by
10
- * `listDatasources`). Connection metadata lives under `bin_data` — host,
11
- * port, account, plus type-specific fields (`database_name` for MySQL etc.).
12
- *
13
- * Exported for unit testing.
14
- */
15
- export interface DsMatchSignature {
16
- type: string;
17
- host: string;
18
- port: number;
19
- database: string;
20
- account: string;
21
- name?: string;
22
- }
23
- export interface DsMatchHit {
24
- id: string;
25
- name: string;
26
- matchedByName: boolean;
27
- matchedByTuple: boolean;
28
- }
29
- export declare function findExistingDatasource(listBody: string, sig: DsMatchSignature): DsMatchHit | undefined;
30
- export declare function findDatasourceIdByName(listBody: string, name: string): string | undefined;
31
1
  export declare function parseImportCsvArgs(args: string[]): {
32
2
  datasourceId: string;
33
3
  files: string;
@@ -44,4 +14,3 @@ export interface ImportCsvResult {
44
14
  sampleRows: Record<string, Array<Record<string, string | null>>>;
45
15
  }
46
16
  export declare function runDsImportCsv(args: string[]): Promise<ImportCsvResult>;
47
- export declare function runDsImportCsvCommand(args: string[]): Promise<number>;
@@ -1,421 +1,19 @@
1
- import { createInterface } from "node:readline";
1
+ // Internal CSV-import helpers formerly the `kweaver ds` command. The user-facing
2
+ // `ds` command group has been removed; these helpers are now consumed by
3
+ // `kweaver bkn create-from-csv` and by the import-csv tests.
4
+ //
5
+ // The flow still talks to the legacy `/datasources` backend endpoints. SDK-level
6
+ // shims for those endpoints remain available for users on older backends; see
7
+ // `api/datasources.ts` and `resources/datasources.ts` (both @deprecated).
2
8
  import { statSync } from "node:fs";
3
9
  import { glob } from "node:fs/promises";
4
10
  import { resolve as resolvePath } from "node:path";
5
- import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
6
- import { testDatasource, createDatasource, listDatasources, getDatasource, deleteDatasource, } from "../api/datasources.js";
7
- import { listTablesWithColumns, scanMetadata } from "../api/vega.js";
8
- import { formatCallOutput } from "./call.js";
11
+ import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
12
+ import { getDatasource } from "../api/datasources.js";
13
+ import { scanMetadata } from "../api/vega.js";
9
14
  import { resolveBusinessDomain } from "../config/store.js";
10
- import { assertVegaCatalogId } from "./bkn-utils.js";
11
15
  import { parseCsvFile, buildTableName, splitBatches, buildFieldMappings, buildDagBody, } from "./import-csv.js";
12
16
  import { executeDataflow } from "../api/dataflow.js";
13
- function confirmYes(prompt) {
14
- return new Promise((resolve) => {
15
- const rl = createInterface({ input: process.stdin, output: process.stdout });
16
- rl.question(`${prompt} [y/N] `, (answer) => {
17
- rl.close();
18
- const trimmed = answer.trim().toLowerCase();
19
- resolve(trimmed === "y" || trimmed === "yes");
20
- });
21
- });
22
- }
23
- function extractDatasourceId(body) {
24
- const parsed = JSON.parse(body);
25
- const item = Array.isArray(parsed) ? parsed[0] : parsed;
26
- if (!item || typeof item !== "object")
27
- return "";
28
- const id = item.id ?? item.ds_id;
29
- return id != null ? String(id) : "";
30
- }
31
- export async function runDsCommand(args) {
32
- const [subcommand, ...rest] = args;
33
- if (!subcommand || subcommand === "--help" || subcommand === "-h") {
34
- console.log(`kweaver ds
35
-
36
- Subcommands:
37
- list [--keyword X] [--type Y] List datasources
38
- get <id> Get datasource details
39
- delete <id> [-y] Delete a datasource
40
- tables <id> [--keyword X] List tables with columns
41
- connect <db_type> <host> <port> <database> --account X --password Y [--schema Z] [--name N]
42
- [--reuse-existing|--force-new]
43
- Test connectivity, register datasource, and discover tables.
44
- By default reuses an existing ds with the same (type, host, port, database, account)
45
- instead of creating a duplicate. --force-new always creates a new entry.
46
- import-csv <ds-id> --files <glob_or_list> [--table-prefix X] [--batch-size N]
47
- Import CSV files into datasource tables via dataflow API.`);
48
- return 0;
49
- }
50
- const dispatch = () => {
51
- if (subcommand === "list")
52
- return runDsListCommand(rest);
53
- if (subcommand === "get")
54
- return runDsGetCommand(rest);
55
- if (subcommand === "delete")
56
- return runDsDeleteCommand(rest);
57
- if (subcommand === "tables")
58
- return runDsTablesCommand(rest);
59
- if (subcommand === "connect")
60
- return runDsConnectCommand(rest);
61
- if (subcommand === "import-csv")
62
- return runDsImportCsvCommand(rest);
63
- return Promise.resolve(-1);
64
- };
65
- try {
66
- return await with401RefreshRetry(async () => {
67
- const code = await dispatch();
68
- if (code === -1) {
69
- console.error(`Unknown ds subcommand: ${subcommand}`);
70
- return 1;
71
- }
72
- return code;
73
- });
74
- }
75
- catch (error) {
76
- console.error(formatHttpError(error));
77
- return 1;
78
- }
79
- }
80
- export function parseDsListArgs(args) {
81
- let keyword;
82
- let type;
83
- let businessDomain = "";
84
- let pretty = true;
85
- for (let i = 0; i < args.length; i += 1) {
86
- const arg = args[i];
87
- if (arg === "--help" || arg === "-h")
88
- throw new Error("help");
89
- if (arg === "--keyword" && args[i + 1]) {
90
- keyword = args[++i];
91
- continue;
92
- }
93
- if (arg === "--type" && args[i + 1]) {
94
- type = args[++i];
95
- continue;
96
- }
97
- if ((arg === "-bd" || arg === "--biz-domain") && args[i + 1]) {
98
- businessDomain = args[++i];
99
- continue;
100
- }
101
- if (arg === "--pretty") {
102
- pretty = true;
103
- continue;
104
- }
105
- }
106
- if (!businessDomain)
107
- businessDomain = resolveBusinessDomain();
108
- return { keyword, type, businessDomain, pretty };
109
- }
110
- async function runDsListCommand(args) {
111
- try {
112
- const opts = parseDsListArgs(args);
113
- const token = await ensureValidToken();
114
- const body = await listDatasources({
115
- baseUrl: token.baseUrl,
116
- accessToken: token.accessToken,
117
- keyword: opts.keyword,
118
- type: opts.type,
119
- businessDomain: opts.businessDomain,
120
- });
121
- console.log(formatCallOutput(body, opts.pretty));
122
- return 0;
123
- }
124
- catch (error) {
125
- if (error instanceof Error && error.message === "help") {
126
- console.log(`kweaver ds list [options]
127
-
128
- Options:
129
- --keyword <s> Filter by keyword
130
- --type <s> Filter by database type
131
- -bd, --biz-domain Business domain (default: bd_public)
132
- --pretty Pretty-print JSON (default)`);
133
- return 0;
134
- }
135
- throw error;
136
- }
137
- }
138
- async function runDsGetCommand(args) {
139
- const id = args.find((a) => !a.startsWith("-"));
140
- if (!id) {
141
- console.error("Usage: kweaver ds get <id>");
142
- return 1;
143
- }
144
- const token = await ensureValidToken();
145
- const body = await getDatasource({
146
- baseUrl: token.baseUrl,
147
- accessToken: token.accessToken,
148
- id,
149
- });
150
- console.log(formatCallOutput(body, true));
151
- return 0;
152
- }
153
- async function runDsDeleteCommand(args) {
154
- let id = "";
155
- let yes = false;
156
- for (let i = 0; i < args.length; i += 1) {
157
- const arg = args[i];
158
- if (arg === "--yes" || arg === "-y")
159
- yes = true;
160
- else if (!arg.startsWith("-"))
161
- id = arg;
162
- }
163
- if (!id) {
164
- console.error("Usage: kweaver ds delete <id> [-y]");
165
- return 1;
166
- }
167
- if (!yes) {
168
- const confirmed = await confirmYes("Are you sure you want to delete this datasource?");
169
- if (!confirmed) {
170
- console.error("Aborted.");
171
- return 1;
172
- }
173
- }
174
- const token = await ensureValidToken();
175
- await deleteDatasource({
176
- baseUrl: token.baseUrl,
177
- accessToken: token.accessToken,
178
- id,
179
- });
180
- console.error(`Deleted ${id}`);
181
- return 0;
182
- }
183
- async function runDsTablesCommand(args) {
184
- let id = "";
185
- let keyword;
186
- let pretty = true;
187
- for (let i = 0; i < args.length; i += 1) {
188
- const arg = args[i];
189
- if (arg === "--keyword" && args[i + 1]) {
190
- keyword = args[++i];
191
- continue;
192
- }
193
- if (arg === "--pretty") {
194
- pretty = true;
195
- continue;
196
- }
197
- if (!arg.startsWith("-"))
198
- id = arg;
199
- }
200
- if (!id) {
201
- console.error("Usage: kweaver ds tables <vega-catalog-id> [--keyword X]\n" +
202
- " <vega-catalog-id> is a vega catalog id (use `kweaver vega catalog list` to find one;\n" +
203
- " legacy data-connection datasource UUIDs are no longer accepted).");
204
- return 1;
205
- }
206
- assertVegaCatalogId(id);
207
- const token = await ensureValidToken();
208
- const body = await listTablesWithColumns({
209
- baseUrl: token.baseUrl,
210
- accessToken: token.accessToken,
211
- id,
212
- keyword,
213
- });
214
- console.log(formatCallOutput(body, pretty));
215
- return 0;
216
- }
217
- export function findExistingDatasource(listBody, sig) {
218
- const parsed = JSON.parse(listBody);
219
- const entries = Array.isArray(parsed) ? parsed : (parsed.entries ?? []);
220
- const tupleMatch = entries.find((e) => e.id &&
221
- e.type === sig.type &&
222
- e.bin_data?.host === sig.host &&
223
- Number(e.bin_data?.port) === Number(sig.port) &&
224
- e.bin_data?.database_name === sig.database &&
225
- e.bin_data?.account === sig.account);
226
- if (tupleMatch) {
227
- return {
228
- id: String(tupleMatch.id),
229
- name: String(tupleMatch.name ?? ""),
230
- matchedByName: tupleMatch.name === sig.name,
231
- matchedByTuple: true,
232
- };
233
- }
234
- if (sig.name) {
235
- const nameMatch = entries.find((e) => e.id && e.name === sig.name);
236
- if (nameMatch) {
237
- return {
238
- id: String(nameMatch.id),
239
- name: String(nameMatch.name),
240
- matchedByName: true,
241
- matchedByTuple: false,
242
- };
243
- }
244
- }
245
- return undefined;
246
- }
247
- export function findDatasourceIdByName(listBody, name) {
248
- const parsed = JSON.parse(listBody);
249
- const entries = Array.isArray(parsed) ? parsed : (parsed.entries ?? []);
250
- const hit = entries.find((e) => e.id && e.name === name);
251
- return hit?.id ? String(hit.id) : undefined;
252
- }
253
- function isDuplicateNameError(err) {
254
- if (!err || typeof err !== "object")
255
- return false;
256
- // HttpError.message is just "HTTP 400 ..."; the description lives in body.
257
- const status = "status" in err ? Number(err.status) : NaN;
258
- const body = "body" in err ? String(err.body) : "";
259
- if (status !== 400)
260
- return false;
261
- return /数据源名称已存在|datasource name.*exist|already exists/i.test(body);
262
- }
263
- async function runDsConnectCommand(args) {
264
- let dbType = "";
265
- let host = "";
266
- let port = 0;
267
- let database = "";
268
- let account = "";
269
- let password = "";
270
- let schema;
271
- let name;
272
- let forceNew = false;
273
- for (let i = 0; i < args.length; i += 1) {
274
- const arg = args[i];
275
- if (arg === "--account" && args[i + 1]) {
276
- account = args[++i];
277
- continue;
278
- }
279
- if (arg === "--password" && args[i + 1]) {
280
- password = args[++i];
281
- continue;
282
- }
283
- if (arg === "--schema" && args[i + 1]) {
284
- schema = args[++i];
285
- continue;
286
- }
287
- if (arg === "--name" && args[i + 1]) {
288
- name = args[++i];
289
- continue;
290
- }
291
- if (arg === "--force-new") {
292
- forceNew = true;
293
- continue;
294
- }
295
- if (arg === "--reuse-existing") {
296
- forceNew = false;
297
- continue;
298
- }
299
- if (!arg.startsWith("-")) {
300
- if (!dbType)
301
- dbType = arg;
302
- else if (!host)
303
- host = arg;
304
- else if (port === 0)
305
- port = parseInt(arg, 10);
306
- else if (!database)
307
- database = arg;
308
- }
309
- }
310
- if (!dbType || !host || !database || !account || !password) {
311
- console.error("Usage: kweaver ds connect <db_type> <host> <port> <database> --account X --password Y [--schema Z] [--name N] [--reuse-existing|--force-new]");
312
- return 1;
313
- }
314
- if (Number.isNaN(port) || port < 1) {
315
- console.error("Invalid port");
316
- return 1;
317
- }
318
- const token = await ensureValidToken();
319
- const base = { baseUrl: token.baseUrl, accessToken: token.accessToken };
320
- const dsName = name ?? database;
321
- // Pre-flight dedup: connection-tuple match is the silent-orphan vector.
322
- // Backend already rejects duplicate names with 400, but won't notice
323
- // tuple collisions, so we own that check.
324
- if (!forceNew) {
325
- const listBody = await listDatasources({ ...base });
326
- const hit = findExistingDatasource(listBody, {
327
- type: dbType,
328
- host,
329
- port,
330
- database,
331
- account,
332
- name: dsName,
333
- });
334
- if (hit) {
335
- const why = hit.matchedByTuple
336
- ? "matched by (type,host,port,database,account)"
337
- : "matched by --name";
338
- console.error(`Reusing existing datasource ${hit.id} (${hit.name}); ${why}. Use --force-new to override.`);
339
- return printDsConnectOutput(base, hit.id);
340
- }
341
- }
342
- console.error("Testing connectivity ...");
343
- await testDatasource({
344
- ...base,
345
- type: dbType,
346
- host,
347
- port,
348
- database,
349
- account,
350
- password,
351
- schema,
352
- });
353
- let dsId = "";
354
- try {
355
- const createBody = await createDatasource({
356
- ...base,
357
- name: dsName,
358
- type: dbType,
359
- host,
360
- port,
361
- database,
362
- account,
363
- password,
364
- schema,
365
- });
366
- dsId = extractDatasourceId(createBody);
367
- }
368
- catch (err) {
369
- // Backend checks name uniqueness but not tuple. If we raced another caller
370
- // (or tuple match got disabled by --force-new and the name still collides),
371
- // turn the raw 400 into a useful pointer to the existing id.
372
- if (isDuplicateNameError(err)) {
373
- // Backend rejected the name; look it up specifically (not by tuple —
374
- // sibling ds sharing the same connection would mislead the pointer).
375
- const listBody = await listDatasources({ ...base });
376
- const existingId = findDatasourceIdByName(listBody, dsName);
377
- if (existingId) {
378
- console.error(`Datasource name '${dsName}' already exists as ${existingId}. Re-run without --force-new to reuse it, or pick a different --name.`);
379
- return 1;
380
- }
381
- }
382
- throw err;
383
- }
384
- if (!dsId) {
385
- console.error("Failed to get datasource ID from create response");
386
- return 1;
387
- }
388
- return printDsConnectOutput(base, dsId);
389
- }
390
- async function printDsConnectOutput(base, dsId) {
391
- const tablesBody = await listTablesWithColumns({ ...base, id: dsId });
392
- const tables = JSON.parse(tablesBody);
393
- const output = {
394
- datasource_id: dsId,
395
- tables: tables.map((t) => ({
396
- name: t.name,
397
- ...(t.primaryKeys && t.primaryKeys.length > 0 ? { primary_keys: t.primaryKeys } : {}),
398
- columns: t.columns.map((c) => ({
399
- name: c.name,
400
- type: c.type,
401
- comment: c.comment,
402
- ...(c.isPrimaryKey ? { is_primary_key: true } : {}),
403
- })),
404
- })),
405
- };
406
- console.log(JSON.stringify(output, null, 2));
407
- return 0;
408
- }
409
- // ── import-csv ────────────────────────────────────────────────────────────────
410
- const IMPORT_CSV_HELP = `kweaver ds import-csv <ds-id> --files <glob_or_list> [options]
411
-
412
- Import CSV files into datasource tables via dataflow API.
413
-
414
- Options:
415
- --files <s> CSV file paths (comma-separated or glob pattern, required)
416
- --table-prefix <s> Table name prefix (default: none)
417
- --batch-size <n> Rows per batch (default: 500, range: 1-10000)
418
- -bd, --biz-domain Business domain (default: bd_public)`;
419
17
  export function parseImportCsvArgs(args) {
420
18
  let datasourceId = "";
421
19
  let files = "";
@@ -486,13 +84,15 @@ export async function runDsImportCsv(args) {
486
84
  }
487
85
  catch (error) {
488
86
  if (error instanceof Error && error.message === "help") {
489
- console.log(IMPORT_CSV_HELP);
87
+ // The user-facing `ds import-csv` CLI is gone; this path is only reachable
88
+ // if a caller explicitly passes --help into the helper. Print a redirect.
89
+ console.error("CSV import is now an internal helper. Use `kweaver bkn create-from-csv` instead.");
490
90
  return { code: 0, tables: [], failed: [], tableColumns: {}, sampleRows: {} };
491
91
  }
492
92
  throw error;
493
93
  }
494
94
  if (!options.datasourceId) {
495
- console.error("Usage: kweaver ds import-csv <ds-id> --files <glob_or_list> [options]");
95
+ console.error("runDsImportCsv: missing datasource/catalog id (positional argument required)");
496
96
  return { code: 1, tables: [], failed: [], tableColumns: {}, sampleRows: {} };
497
97
  }
498
98
  if (!options.files) {
@@ -589,9 +189,10 @@ export async function runDsImportCsv(args) {
589
189
  if (failed.length > 0) {
590
190
  console.error(`Failed tables: ${failed.join(", ")}`);
591
191
  }
592
- // Refresh the platform metadata catalog so the freshly imported tables
593
- // are visible to ds tables / bkn create-from-ds without manual scan.
594
- // Best-effort: scan failures shouldn't mask a successful import.
192
+ // Refresh the platform metadata catalog so the freshly imported tables are
193
+ // visible to downstream commands (e.g. `bkn create-from-catalog`) without
194
+ // requiring a manual scan. Best-effort: scan failures don't mask a
195
+ // successful import.
595
196
  if (succeeded.length > 0) {
596
197
  process.stderr.write("Scanning datasource metadata ...\n");
597
198
  try {
@@ -608,12 +209,3 @@ export async function runDsImportCsv(args) {
608
209
  }
609
210
  return { code: failed.length > 0 ? 1 : 0, tables: succeeded, failed, tableColumns, sampleRows };
610
211
  }
611
- export async function runDsImportCsvCommand(args) {
612
- const result = await runDsImportCsv(args);
613
- console.log(JSON.stringify({
614
- tables: result.tables,
615
- failed: result.failed,
616
- summary: { succeeded: result.tables.length, failed: result.failed.length },
617
- }, null, 2));
618
- return result.code;
619
- }
@@ -30,6 +30,12 @@ export interface ExploreMeta {
30
30
  id: string;
31
31
  name: string;
32
32
  }>;
33
+ conceptGroups: Array<{
34
+ id: string;
35
+ name: string;
36
+ color?: string;
37
+ objectTypeIds: string[];
38
+ }>;
33
39
  }
34
40
  export interface ExploreOt {
35
41
  id: string;
@@ -63,7 +69,7 @@ export interface ExploreStats {
63
69
  }
64
70
  export declare const EXPLORE_BOOTSTRAP_RETRY_DELAY_MS = 300;
65
71
  export declare const EXPLORE_BOOTSTRAP_MAX_ATTEMPTS = 2;
66
- export declare function buildMeta(knRaw: string, otRaw: string, rtRaw: string, atRaw: string): ExploreMeta;
72
+ export declare function buildMeta(knRaw: string, otRaw: string, rtRaw: string, atRaw: string, cgRaw?: string): ExploreMeta;
67
73
  export declare function isRetryableExploreBootstrapError(error: unknown): boolean;
68
74
  export declare function loadExploreMetaWithRetry(token: {
69
75
  baseUrl: string;
@@ -2,11 +2,12 @@ import { HttpError } from "../utils/http.js";
2
2
  import { getKnowledgeNetwork, listObjectTypes, listRelationTypes, listActionTypes, } from "../api/knowledge-networks.js";
3
3
  import { objectTypeQuery, objectTypeProperties, subgraph } from "../api/ontology-query.js";
4
4
  import { semanticSearch } from "../api/semantic-search.js";
5
+ import { listConceptGroups } from "../api/bkn-backend.js";
5
6
  // ── Constants ───────────────────────────────────────────────────────────────
6
7
  export const EXPLORE_BOOTSTRAP_RETRY_DELAY_MS = 300;
7
8
  export const EXPLORE_BOOTSTRAP_MAX_ATTEMPTS = 2;
8
9
  // ── Meta builder ────────────────────────────────────────────────────────────
9
- export function buildMeta(knRaw, otRaw, rtRaw, atRaw) {
10
+ export function buildMeta(knRaw, otRaw, rtRaw, atRaw, cgRaw) {
10
11
  const kn = JSON.parse(knRaw);
11
12
  const otParsed = JSON.parse(otRaw);
12
13
  const otItems = (Array.isArray(otParsed) ? otParsed
@@ -54,8 +55,29 @@ export function buildMeta(knRaw, otRaw, rtRaw, atRaw) {
54
55
  id: a.id,
55
56
  name: a.name,
56
57
  })),
58
+ conceptGroups: parseConceptGroups(cgRaw),
57
59
  };
58
60
  }
61
+ function parseConceptGroups(cgRaw) {
62
+ if (!cgRaw)
63
+ return [];
64
+ try {
65
+ const parsed = JSON.parse(cgRaw);
66
+ const items = (Array.isArray(parsed) ? parsed
67
+ : Array.isArray(parsed.entries) ? parsed.entries
68
+ : Array.isArray(parsed.concept_groups) ? parsed.concept_groups
69
+ : []);
70
+ return items.map((g) => ({
71
+ id: g.id,
72
+ name: g.name,
73
+ ...(g.color ? { color: g.color } : {}),
74
+ objectTypeIds: Array.isArray(g.object_type_ids) ? g.object_type_ids : [],
75
+ }));
76
+ }
77
+ catch {
78
+ return [];
79
+ }
80
+ }
59
81
  // ── Bootstrap helpers ───────────────────────────────────────────────────────
60
82
  function getErrorMessage(error) {
61
83
  const parts = [];
@@ -100,7 +122,7 @@ function sleep(ms) {
100
122
  export async function loadExploreMetaWithRetry(token, knId, businessDomain) {
101
123
  for (let attempt = 1; attempt <= EXPLORE_BOOTSTRAP_MAX_ATTEMPTS; attempt++) {
102
124
  try {
103
- const [knRaw, otRaw, rtRaw, atRaw] = await Promise.all([
125
+ const [knRaw, otRaw, rtRaw, atRaw, cgRaw] = await Promise.all([
104
126
  getKnowledgeNetwork({
105
127
  baseUrl: token.baseUrl,
106
128
  accessToken: token.accessToken,
@@ -126,8 +148,15 @@ export async function loadExploreMetaWithRetry(token, knId, businessDomain) {
126
148
  knId,
127
149
  businessDomain,
128
150
  }),
151
+ // Concept groups are optional — don't fail the whole load if missing
152
+ listConceptGroups({
153
+ baseUrl: token.baseUrl,
154
+ accessToken: token.accessToken,
155
+ knId,
156
+ businessDomain,
157
+ }).catch(() => ""),
129
158
  ]);
130
- return buildMeta(knRaw, otRaw, rtRaw, atRaw);
159
+ return buildMeta(knRaw, otRaw, rtRaw, atRaw, cgRaw);
131
160
  }
132
161
  catch (error) {
133
162
  if (attempt >= EXPLORE_BOOTSTRAP_MAX_ATTEMPTS || !isRetryableExploreBootstrapError(error)) {
@@ -11,6 +11,7 @@ import { registerVegaRoutes } from "./explore-vega.js";
11
11
  import { listKnowledgeNetworks } from "../api/knowledge-networks.js";
12
12
  import { listAgents } from "../api/agent-list.js";
13
13
  import { listVegaCatalogs } from "../api/vega.js";
14
+ import { renderHelp } from "../help/format.js";
14
15
  export function parseExploreArgs(args) {
15
16
  const opts = {
16
17
  knId: "",
@@ -47,21 +48,23 @@ export function parseExploreArgs(args) {
47
48
  return opts;
48
49
  }
49
50
  function printExploreHelp() {
50
- console.log(`kweaver explore
51
-
52
- Launch an interactive web UI for exploring KWeaver resources.
53
-
54
- Usage:
55
- kweaver explore [options]
56
-
57
- Options:
58
- --kn <id> Open directly to BKN tab with specified KN
59
- --agent <id> Open directly to Chat tab with specified Agent
60
- --port <n> HTTP server port (default: 3721)
61
- --no-open Don't auto-open browser
62
- -bd <value> Business domain override
63
- -h, --help Show this help
64
- `);
51
+ console.log(renderHelp({
52
+ tagline: "Launch interactive web UI for exploring KWeaver resources",
53
+ usage: "kweaver explore [flags]",
54
+ flags: [
55
+ { name: "--kn <id>", desc: "Open directly to BKN tab with specified KN" },
56
+ { name: "--agent <id>", desc: "Open directly to Chat tab with specified Agent" },
57
+ { name: "--port <n>", desc: "HTTP server port (default: 3721)" },
58
+ { name: "--no-open", desc: "Don't auto-open browser" },
59
+ { name: "-bd, --biz-domain <s>", desc: "Business domain override" },
60
+ ],
61
+ inheritedFlags: "--base-url, --token, --user, --help",
62
+ examples: [
63
+ "kweaver explore",
64
+ "kweaver explore --kn <kn-id> --port 4000",
65
+ "kweaver explore --agent <agent-id> --no-open",
66
+ ],
67
+ }));
65
68
  }
66
69
  // MIME map for static files
67
70
  const MIME = {