@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.
- package/README.md +26 -52
- package/README.zh.md +27 -46
- package/dist/api/agent-chat.d.ts +10 -2
- package/dist/api/agent-chat.js +19 -5
- package/dist/api/datasources.d.ts +14 -0
- package/dist/api/datasources.js +14 -0
- package/dist/api/resources.d.ts +94 -0
- package/dist/api/resources.js +166 -0
- package/dist/cli.js +103 -23
- package/dist/client.d.ts +10 -4
- package/dist/client.js +12 -6
- package/dist/commands/agent-members.js +27 -11
- package/dist/commands/agent.js +383 -272
- package/dist/commands/auth.js +184 -71
- package/dist/commands/bkn-metric.js +37 -16
- package/dist/commands/bkn-ops.d.ts +1 -1
- package/dist/commands/bkn-ops.js +192 -93
- package/dist/commands/bkn-query.js +99 -31
- package/dist/commands/bkn-schema.d.ts +3 -3
- package/dist/commands/bkn-schema.js +127 -86
- package/dist/commands/bkn.js +158 -116
- package/dist/commands/call.js +23 -13
- package/dist/commands/config.js +22 -12
- package/dist/commands/context-loader.js +98 -92
- package/dist/commands/dataflow.js +14 -6
- package/dist/commands/ds.d.ts +0 -31
- package/dist/commands/ds.js +18 -426
- package/dist/commands/explore-bkn.d.ts +7 -1
- package/dist/commands/explore-bkn.js +32 -3
- package/dist/commands/explore.js +18 -15
- package/dist/commands/model.js +53 -42
- package/dist/commands/resource.d.ts +1 -0
- package/dist/commands/{dataview.js → resource.js} +62 -84
- package/dist/commands/skill.js +201 -65
- package/dist/commands/token.js +11 -0
- package/dist/commands/tool.js +46 -29
- package/dist/commands/toolbox.js +31 -15
- package/dist/commands/vega.js +466 -250
- package/dist/help/format.d.ts +65 -0
- package/dist/help/format.js +141 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/resources/datasources.d.ts +7 -0
- package/dist/resources/datasources.js +7 -0
- package/dist/resources/{dataviews.d.ts → resources.d.ts} +10 -11
- package/dist/resources/{dataviews.js → resources.js} +12 -13
- package/dist/templates/explorer/bkn.js +860 -9
- package/dist/templates/explorer/index.html +1 -0
- package/dist/templates/explorer/style.css +225 -0
- package/dist/templates/explorer/vendor/g6.min.js +68 -0
- package/dist/trace-ai/eval-set/schemas.d.ts +1 -0
- package/dist/trace-ai/eval-set/schemas.js +4 -0
- package/dist/trace-ai/eval-set/types.d.ts +2 -0
- package/dist/trace-ai/exp/capture-fingerprint.d.ts +10 -0
- package/dist/trace-ai/exp/capture-fingerprint.js +12 -0
- package/dist/trace-ai/exp/context/context-assembler.d.ts +18 -0
- package/dist/trace-ai/exp/context/context-assembler.js +42 -0
- package/dist/trace-ai/exp/context/failure-analyzer.d.ts +22 -0
- package/dist/trace-ai/exp/context/failure-analyzer.js +59 -0
- package/dist/trace-ai/exp/context/kn-data-prober.d.ts +13 -0
- package/dist/trace-ai/exp/context/kn-data-prober.js +38 -0
- package/dist/trace-ai/exp/context/kn-schema-client.d.ts +14 -0
- package/dist/trace-ai/exp/context/kn-schema-client.js +41 -0
- package/dist/trace-ai/exp/context/retrieval-health.d.ts +32 -0
- package/dist/trace-ai/exp/context/retrieval-health.js +138 -0
- package/dist/trace-ai/exp/context/vega-catalog-client.d.ts +14 -0
- package/dist/trace-ai/exp/context/vega-catalog-client.js +15 -0
- package/dist/trace-ai/exp/coordinator.d.ts +34 -21
- package/dist/trace-ai/exp/coordinator.js +246 -24
- package/dist/trace-ai/exp/eval-runner.js +4 -2
- package/dist/trace-ai/exp/exp-store/events-jsonl.d.ts +1 -0
- package/dist/trace-ai/exp/exp-store/events-jsonl.js +18 -0
- package/dist/trace-ai/exp/exp-store/expected-fingerprint.d.ts +3 -0
- package/dist/trace-ai/exp/exp-store/expected-fingerprint.js +31 -0
- package/dist/trace-ai/exp/exp-store/index.d.ts +63 -2
- package/dist/trace-ai/exp/exp-store/index.js +2 -1
- package/dist/trace-ai/exp/exp-store/rollback-yaml.d.ts +12 -0
- package/dist/trace-ai/exp/exp-store/rollback-yaml.js +29 -0
- package/dist/trace-ai/exp/index.d.ts +2 -0
- package/dist/trace-ai/exp/index.js +68 -3
- package/dist/trace-ai/exp/info.js +1 -1
- package/dist/trace-ai/exp/patch/index.d.ts +13 -2
- package/dist/trace-ai/exp/patch/index.js +65 -10
- package/dist/trace-ai/exp/patch/kn-api-client.d.ts +40 -0
- package/dist/trace-ai/exp/patch/kn-api-client.js +14 -0
- package/dist/trace-ai/exp/patch/kn.d.ts +8 -0
- package/dist/trace-ai/exp/patch/kn.js +36 -0
- package/dist/trace-ai/exp/patch/skill-api-client.d.ts +17 -0
- package/dist/trace-ai/exp/patch/skill-api-client.js +14 -0
- package/dist/trace-ai/exp/patch/skill-content.d.ts +9 -0
- package/dist/trace-ai/exp/patch/skill-content.js +12 -0
- package/dist/trace-ai/exp/preflight.d.ts +77 -0
- package/dist/trace-ai/exp/preflight.js +148 -0
- package/dist/trace-ai/exp/providers/synthesizer-client.d.ts +3 -14
- package/dist/trace-ai/exp/providers/synthesizer-client.js +53 -35
- package/dist/trace-ai/exp/providers/triage-client.d.ts +15 -2
- package/dist/trace-ai/exp/providers/triage-client.js +143 -28
- package/dist/trace-ai/exp/run-preflight.d.ts +19 -0
- package/dist/trace-ai/exp/run-preflight.js +56 -0
- package/dist/trace-ai/exp/schemas.d.ts +402 -44
- package/dist/trace-ai/exp/schemas.js +131 -18
- package/dist/utils/deprecation.d.ts +1 -0
- package/dist/utils/deprecation.js +18 -0
- package/package.json +2 -1
- package/dist/api/dataviews.d.ts +0 -117
- package/dist/api/dataviews.js +0 -265
- 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";
|
package/dist/commands/ds.d.ts
CHANGED
|
@@ -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>;
|
package/dist/commands/ds.js
CHANGED
|
@@ -1,421 +1,19 @@
|
|
|
1
|
-
import
|
|
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
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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
|
-
|
|
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("
|
|
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
|
-
//
|
|
594
|
-
// Best-effort: scan failures
|
|
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)) {
|
package/dist/commands/explore.js
CHANGED
|
@@ -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(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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 = {
|