@openbkn/bkn-sdk 0.1.0 → 0.1.1-alpha.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.
- package/README.md +18 -3
- package/dist/{chunk-4NXAIG4G.js → chunk-ADZ23DPF.js} +288 -58
- package/dist/chunk-ADZ23DPF.js.map +1 -0
- package/dist/cli.js +123 -25
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +74 -26
- package/dist/index.js +1 -1
- package/package.json +1 -2
- package/dist/chunk-4NXAIG4G.js.map +0 -1
package/README.md
CHANGED
|
@@ -92,13 +92,28 @@ Golden `--help` baselines and a full-depth parity test live in
|
|
|
92
92
|
|
|
93
93
|
## Agent skill
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
`skills/openbkn/` is an agent skill (for Claude Code / the [skills.sh](https://skills.sh)
|
|
96
|
+
ecosystem) that lets an AI drive the `openbkn` CLI from natural language. It
|
|
97
|
+
ships a `SKILL.md` (trigger intents, `allowed-tools: Bash(openbkn *)`, a
|
|
98
|
+
command-group map, examples, and cautions) plus per-domain cheat sheets under
|
|
99
|
+
`references/` (auth, bkn, agent, model, vega, resource, dataflow, context,
|
|
100
|
+
skill, toolbox, trace, admin, call) and two how-tos (build-a-KN, troubleshooting).
|
|
101
|
+
|
|
102
|
+
The skill is **not** part of the npm package — it's registered separately:
|
|
97
103
|
|
|
98
104
|
```bash
|
|
99
|
-
|
|
105
|
+
# Install the skill (globally), then ask in natural language:
|
|
106
|
+
npx skills add openbkn-ai/bkn-sdk@openbkn -g -y
|
|
107
|
+
|
|
108
|
+
# "列出所有知识网络" / "list all knowledge networks"
|
|
109
|
+
# "从 Vega catalog vcat-1 建一个名为 customers 的知识网络并构建索引"
|
|
110
|
+
# "诊断会话 conv-123 的 trace,带 LLM 判定"
|
|
100
111
|
```
|
|
101
112
|
|
|
113
|
+
The skill assumes the `openbkn` CLI is installed (`npm i -g @openbkn/bkn-sdk`)
|
|
114
|
+
and you are logged in (`openbkn auth login`). It always defers to live
|
|
115
|
+
`openbkn <group> <sub> --help` for exact flags.
|
|
116
|
+
|
|
102
117
|
## License
|
|
103
118
|
|
|
104
119
|
Apache-2.0
|
|
@@ -44,9 +44,21 @@ function formatError(err) {
|
|
|
44
44
|
const detail = err.body ? `: ${truncate(err.body, 500)}` : "";
|
|
45
45
|
return `Request failed (HTTP ${err.status} ${err.statusText})${detail}`;
|
|
46
46
|
}
|
|
47
|
-
if (err instanceof Error)
|
|
47
|
+
if (err instanceof Error) {
|
|
48
|
+
const cause = err.cause;
|
|
49
|
+
if (cause?.code && isTlsCertError(cause.code)) {
|
|
50
|
+
return `TLS certificate rejected (${cause.code}). The platform is likely self-signed \u2014 retry with \`-k\`/\`--insecure\`.`;
|
|
51
|
+
}
|
|
52
|
+
if (err.message === "fetch failed" && cause?.message) {
|
|
53
|
+
return `Request failed: ${cause.message}${cause.code ? ` (${cause.code})` : ""}`;
|
|
54
|
+
}
|
|
55
|
+
return err.message;
|
|
56
|
+
}
|
|
48
57
|
return String(err);
|
|
49
58
|
}
|
|
59
|
+
function isTlsCertError(code) {
|
|
60
|
+
return code === "DEPTH_ZERO_SELF_SIGNED_CERT" || code === "SELF_SIGNED_CERT_IN_CHAIN" || code === "UNABLE_TO_VERIFY_LEAF_SIGNATURE" || code === "CERT_HAS_EXPIRED" || code.includes("CERT");
|
|
61
|
+
}
|
|
50
62
|
function truncate(s, n) {
|
|
51
63
|
return s.length > n ? `${s.slice(0, n)}\u2026` : s;
|
|
52
64
|
}
|
|
@@ -2696,38 +2708,6 @@ function deleteJobs(ctx, knId, ids) {
|
|
|
2696
2708
|
return request(ctx, knPath(knId, `jobs/${ids}`), { method: "DELETE" });
|
|
2697
2709
|
}
|
|
2698
2710
|
|
|
2699
|
-
// src/utils/tar.ts
|
|
2700
|
-
import { spawnSync } from "child_process";
|
|
2701
|
-
import { resolve } from "path";
|
|
2702
|
-
var TAR_MISSING = "tar executable not found. On Windows, ensure tar.exe is in PATH (ships with Windows 10 1803+) or install GNU tar via Git for Windows / scoop.";
|
|
2703
|
-
function packDirectoryToTar(dirPath) {
|
|
2704
|
-
const abs = resolve(dirPath);
|
|
2705
|
-
const result = spawnSync("tar", ["cf", "-", "-C", abs, "."], {
|
|
2706
|
-
maxBuffer: 1024 * 1024 * 512,
|
|
2707
|
-
env: { ...process.env, COPYFILE_DISABLE: "1" }
|
|
2708
|
-
});
|
|
2709
|
-
if (result.error && result.error.code === "ENOENT") {
|
|
2710
|
-
throw new Error(TAR_MISSING);
|
|
2711
|
-
}
|
|
2712
|
-
if (result.status !== 0) {
|
|
2713
|
-
throw new Error(`tar pack failed: ${result.stderr?.toString() ?? result.status}`);
|
|
2714
|
-
}
|
|
2715
|
-
return result.stdout;
|
|
2716
|
-
}
|
|
2717
|
-
function extractTarToDirectory(tarBuffer, dirPath) {
|
|
2718
|
-
const abs = resolve(dirPath);
|
|
2719
|
-
const result = spawnSync("tar", ["xf", "-", "-C", abs], {
|
|
2720
|
-
input: tarBuffer,
|
|
2721
|
-
maxBuffer: 1024 * 1024 * 512
|
|
2722
|
-
});
|
|
2723
|
-
if (result.error && result.error.code === "ENOENT") {
|
|
2724
|
-
throw new Error(TAR_MISSING);
|
|
2725
|
-
}
|
|
2726
|
-
if (result.status !== 0) {
|
|
2727
|
-
throw new Error(`tar extract failed: ${result.stderr?.toString() ?? result.status}`);
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
|
|
2731
2711
|
// src/api/vega.ts
|
|
2732
2712
|
import { z } from "zod";
|
|
2733
2713
|
var VEGA_BASE = "/api/vega-backend/v1";
|
|
@@ -2742,14 +2722,28 @@ var CreateBuildTaskRequest = z.object({
|
|
|
2742
2722
|
});
|
|
2743
2723
|
var BuildTask = z.object({
|
|
2744
2724
|
id: z.string(),
|
|
2745
|
-
resource_id: z.string(),
|
|
2746
|
-
mode: BuildMode,
|
|
2725
|
+
resource_id: z.string().optional(),
|
|
2726
|
+
mode: BuildMode.optional(),
|
|
2727
|
+
status: z.string().optional(),
|
|
2747
2728
|
state: z.string().optional(),
|
|
2729
|
+
total_count: z.number().optional(),
|
|
2748
2730
|
synced_count: z.number().optional(),
|
|
2749
|
-
vectorized_count: z.number().optional()
|
|
2750
|
-
|
|
2731
|
+
vectorized_count: z.number().optional(),
|
|
2732
|
+
embedding_fields: z.string().optional(),
|
|
2733
|
+
build_key_fields: z.string().optional(),
|
|
2734
|
+
embedding_model: z.string().optional(),
|
|
2735
|
+
model_dimensions: z.number().optional()
|
|
2736
|
+
}).passthrough();
|
|
2751
2737
|
async function createBuildTask(ctx, req) {
|
|
2752
|
-
const
|
|
2738
|
+
const p = CreateBuildTaskRequest.parse(req);
|
|
2739
|
+
const body = {
|
|
2740
|
+
resource_id: p.resource_id,
|
|
2741
|
+
mode: p.mode,
|
|
2742
|
+
...p.embedding_fields?.length ? { embedding_fields: p.embedding_fields.join(",") } : {},
|
|
2743
|
+
...p.build_key_fields?.length ? { build_key_fields: p.build_key_fields.join(",") } : {},
|
|
2744
|
+
...p.embedding_model ? { embedding_model: p.embedding_model } : {},
|
|
2745
|
+
...p.model_dimensions ? { model_dimensions: p.model_dimensions } : {}
|
|
2746
|
+
};
|
|
2753
2747
|
const res = await request(ctx, `${VEGA_BASE}/build-tasks`, { method: "POST", body });
|
|
2754
2748
|
return BuildTask.parse(res);
|
|
2755
2749
|
}
|
|
@@ -2765,6 +2759,22 @@ async function listCatalogs(ctx, opts = {}) {
|
|
|
2765
2759
|
function getCatalog(ctx, id) {
|
|
2766
2760
|
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}`);
|
|
2767
2761
|
}
|
|
2762
|
+
function createCatalog(ctx, req) {
|
|
2763
|
+
return request(ctx, `${VEGA_BASE}/catalogs`, {
|
|
2764
|
+
method: "POST",
|
|
2765
|
+
body: {
|
|
2766
|
+
name: req.name,
|
|
2767
|
+
connector_type: req.connectorType,
|
|
2768
|
+
connector_config: req.connectorConfig,
|
|
2769
|
+
...req.tags ? { tags: req.tags } : {},
|
|
2770
|
+
...req.description ? { description: req.description } : {},
|
|
2771
|
+
...req.enabled !== void 0 ? { enabled: req.enabled } : {}
|
|
2772
|
+
}
|
|
2773
|
+
});
|
|
2774
|
+
}
|
|
2775
|
+
function enableCatalog(ctx, id) {
|
|
2776
|
+
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/enable`, { method: "POST" });
|
|
2777
|
+
}
|
|
2768
2778
|
function discoverCatalog(ctx, id, wait = true) {
|
|
2769
2779
|
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/discover`, {
|
|
2770
2780
|
method: "POST",
|
|
@@ -2773,8 +2783,8 @@ function discoverCatalog(ctx, id, wait = true) {
|
|
|
2773
2783
|
});
|
|
2774
2784
|
}
|
|
2775
2785
|
function listCatalogResources(ctx, id, category) {
|
|
2776
|
-
return request(ctx, `${VEGA_BASE}/
|
|
2777
|
-
query: { category: category || void 0 }
|
|
2786
|
+
return request(ctx, `${VEGA_BASE}/resources`, {
|
|
2787
|
+
query: { catalog_id: id, category: category || void 0 }
|
|
2778
2788
|
});
|
|
2779
2789
|
}
|
|
2780
2790
|
function catalogHealthStatus(ctx, ids) {
|
|
@@ -2790,8 +2800,180 @@ function getConnectorType(ctx, type) {
|
|
|
2790
2800
|
return request(ctx, `${VEGA_BASE}/connector-types/${encodeURIComponent(type)}`);
|
|
2791
2801
|
}
|
|
2792
2802
|
|
|
2803
|
+
// src/utils/bkn-index.ts
|
|
2804
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync } from "fs";
|
|
2805
|
+
import { join as join2 } from "path";
|
|
2806
|
+
function rowCells(line) {
|
|
2807
|
+
const t = line.trim();
|
|
2808
|
+
if (!t.startsWith("|")) return null;
|
|
2809
|
+
return t.replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
|
|
2810
|
+
}
|
|
2811
|
+
function isDivider(cells) {
|
|
2812
|
+
return cells.length > 0 && cells.every((c) => /^:?-{2,}:?$/.test(c) || c === "");
|
|
2813
|
+
}
|
|
2814
|
+
function section(text, headingRe) {
|
|
2815
|
+
const lines = text.split("\n");
|
|
2816
|
+
let start = -1;
|
|
2817
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
2818
|
+
if (headingRe.test(lines[i] ?? "")) {
|
|
2819
|
+
start = i + 1;
|
|
2820
|
+
break;
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
if (start === -1) return null;
|
|
2824
|
+
const out = [];
|
|
2825
|
+
for (let i = start; i < lines.length; i += 1) {
|
|
2826
|
+
if (/^#{1,6}\s/.test(lines[i] ?? "")) break;
|
|
2827
|
+
out.push(lines[i] ?? "");
|
|
2828
|
+
}
|
|
2829
|
+
return out.join("\n");
|
|
2830
|
+
}
|
|
2831
|
+
function colIndex(header, aliases) {
|
|
2832
|
+
return header.findIndex((h) => aliases.test(h));
|
|
2833
|
+
}
|
|
2834
|
+
function resourceBinding(text) {
|
|
2835
|
+
const sec = section(text, /^#{2,3}\s*(data\s*source|数据来源)/i);
|
|
2836
|
+
if (!sec) return void 0;
|
|
2837
|
+
let header = null;
|
|
2838
|
+
for (const line of sec.split("\n")) {
|
|
2839
|
+
const cells = rowCells(line);
|
|
2840
|
+
if (!cells || isDivider(cells)) continue;
|
|
2841
|
+
if (!header) {
|
|
2842
|
+
header = cells;
|
|
2843
|
+
continue;
|
|
2844
|
+
}
|
|
2845
|
+
const typeIdx = Math.max(0, colIndex(header, /type|类型/i));
|
|
2846
|
+
const idIdx = colIndex(header, /\bid\b/i);
|
|
2847
|
+
const type = (cells[typeIdx] ?? "").toLowerCase();
|
|
2848
|
+
const id = (cells[idIdx >= 0 ? idIdx : 1] ?? "").trim();
|
|
2849
|
+
if (type === "resource" && id) return id;
|
|
2850
|
+
}
|
|
2851
|
+
return void 0;
|
|
2852
|
+
}
|
|
2853
|
+
function mappedFields(text) {
|
|
2854
|
+
const map = /* @__PURE__ */ new Map();
|
|
2855
|
+
const sec = section(text, /^#{2,3}\s*(data\s*propert|数据属性)/i);
|
|
2856
|
+
if (!sec) return map;
|
|
2857
|
+
let header = null;
|
|
2858
|
+
for (const line of sec.split("\n")) {
|
|
2859
|
+
const cells = rowCells(line);
|
|
2860
|
+
if (!cells || isDivider(cells)) continue;
|
|
2861
|
+
if (!header) {
|
|
2862
|
+
header = cells;
|
|
2863
|
+
continue;
|
|
2864
|
+
}
|
|
2865
|
+
const nameIdx = Math.max(0, colIndex(header, /^\s*(name|属性名|属性)\s*$/i));
|
|
2866
|
+
const mapIdx = colIndex(header, /mapped\s*field|映射字段|映射/i);
|
|
2867
|
+
const name = cells[nameIdx] ?? "";
|
|
2868
|
+
if (!name) continue;
|
|
2869
|
+
map.set(name, (mapIdx >= 0 ? cells[mapIdx] : void 0) || name);
|
|
2870
|
+
}
|
|
2871
|
+
return map;
|
|
2872
|
+
}
|
|
2873
|
+
function vectorProps(text) {
|
|
2874
|
+
const names = /* @__PURE__ */ new Set();
|
|
2875
|
+
let model;
|
|
2876
|
+
const scan = (sec) => {
|
|
2877
|
+
if (!sec) return;
|
|
2878
|
+
let header = null;
|
|
2879
|
+
for (const line of sec.split("\n")) {
|
|
2880
|
+
const cells = rowCells(line);
|
|
2881
|
+
if (!cells || isDivider(cells)) continue;
|
|
2882
|
+
if (!header) {
|
|
2883
|
+
header = cells;
|
|
2884
|
+
continue;
|
|
2885
|
+
}
|
|
2886
|
+
const nameIdx = Math.max(0, colIndex(header, /^\s*(name|属性名|属性)\s*$/i));
|
|
2887
|
+
const idxCol = colIndex(header, /索引配置|索引|index\s*config|index/i);
|
|
2888
|
+
const cfg = idxCol >= 0 ? cells[idxCol] ?? "" : "";
|
|
2889
|
+
if (/vector/i.test(cfg)) {
|
|
2890
|
+
const name = cells[nameIdx] ?? "";
|
|
2891
|
+
if (name) names.add(name);
|
|
2892
|
+
const m = cfg.match(/vector\s*\(\s*([^)]+?)\s*\)/i);
|
|
2893
|
+
if (m?.[1]) model = m[1];
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
};
|
|
2897
|
+
scan(section(text, /^#{2,3}\s*(property\s*overrides|属性覆盖)/i));
|
|
2898
|
+
scan(section(text, /^#{2,3}\s*(data\s*propert|数据属性)/i));
|
|
2899
|
+
return { names: [...names], ...model ? { model } : {} };
|
|
2900
|
+
}
|
|
2901
|
+
function buildKey(text) {
|
|
2902
|
+
const clean = (v) => v.replace(/`/g, "").split(/[,,]/)[0]?.trim() || void 0;
|
|
2903
|
+
const incr = text.match(/Incremental[ \t]*Key[ \t]*[::][ \t]*([^\n]+)/i);
|
|
2904
|
+
if (incr?.[1]?.trim()) return clean(incr[1]);
|
|
2905
|
+
const pk = text.match(/Primary[ \t]*Keys?[ \t]*[::][ \t]*([^\n]+)/i) || text.match(/\*\*[ \t]*主键[ \t]*\*\*[ \t]*[::][ \t]*([^|\n]+)/);
|
|
2906
|
+
if (pk?.[1]?.trim()) return clean(pk[1]);
|
|
2907
|
+
return void 0;
|
|
2908
|
+
}
|
|
2909
|
+
function frontmatterId(text) {
|
|
2910
|
+
if (!text.startsWith("---")) return void 0;
|
|
2911
|
+
const end = text.indexOf("\n---", 3);
|
|
2912
|
+
if (end === -1) return void 0;
|
|
2913
|
+
const m = text.slice(3, end).match(/^\s*id\s*:\s*(.+?)\s*$/m);
|
|
2914
|
+
return m?.[1]?.replace(/^["']|["']$/g, "");
|
|
2915
|
+
}
|
|
2916
|
+
function parseObjectTypeIndex(text, fallbackName = "") {
|
|
2917
|
+
const resourceId = resourceBinding(text);
|
|
2918
|
+
if (!resourceId || resourceId.includes("{{")) return null;
|
|
2919
|
+
const { names, model } = vectorProps(text);
|
|
2920
|
+
if (names.length === 0) return null;
|
|
2921
|
+
const mapped = mappedFields(text);
|
|
2922
|
+
const embeddingFields = names.map((n) => mapped.get(n) ?? n);
|
|
2923
|
+
return {
|
|
2924
|
+
objectType: frontmatterId(text) ?? fallbackName,
|
|
2925
|
+
resourceId,
|
|
2926
|
+
embeddingFields,
|
|
2927
|
+
...buildKey(text) ? { buildKey: buildKey(text) } : {},
|
|
2928
|
+
...model ? { embeddingModel: model } : {}
|
|
2929
|
+
};
|
|
2930
|
+
}
|
|
2931
|
+
function collectIndexTargets(dir) {
|
|
2932
|
+
const otDir = join2(dir, "object_types");
|
|
2933
|
+
if (!existsSync2(otDir) || !statSync(otDir).isDirectory()) return [];
|
|
2934
|
+
const targets = [];
|
|
2935
|
+
for (const f of readdirSync2(otDir).filter((x) => x.endsWith(".bkn"))) {
|
|
2936
|
+
const stem = f.replace(/\.bkn$/, "");
|
|
2937
|
+
const target = parseObjectTypeIndex(readFileSync2(join2(otDir, f), "utf8"), stem);
|
|
2938
|
+
if (target) targets.push(target);
|
|
2939
|
+
}
|
|
2940
|
+
return targets;
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
// src/utils/tar.ts
|
|
2944
|
+
import { spawnSync } from "child_process";
|
|
2945
|
+
import { resolve } from "path";
|
|
2946
|
+
var TAR_MISSING = "tar executable not found. On Windows, ensure tar.exe is in PATH (ships with Windows 10 1803+) or install GNU tar via Git for Windows / scoop.";
|
|
2947
|
+
function packDirectoryToTar(dirPath) {
|
|
2948
|
+
const abs = resolve(dirPath);
|
|
2949
|
+
const result = spawnSync("tar", ["cf", "-", "-C", abs, "."], {
|
|
2950
|
+
maxBuffer: 1024 * 1024 * 512,
|
|
2951
|
+
env: { ...process.env, COPYFILE_DISABLE: "1" }
|
|
2952
|
+
});
|
|
2953
|
+
if (result.error && result.error.code === "ENOENT") {
|
|
2954
|
+
throw new Error(TAR_MISSING);
|
|
2955
|
+
}
|
|
2956
|
+
if (result.status !== 0) {
|
|
2957
|
+
throw new Error(`tar pack failed: ${result.stderr?.toString() ?? result.status}`);
|
|
2958
|
+
}
|
|
2959
|
+
return result.stdout;
|
|
2960
|
+
}
|
|
2961
|
+
function extractTarToDirectory(tarBuffer, dirPath) {
|
|
2962
|
+
const abs = resolve(dirPath);
|
|
2963
|
+
const result = spawnSync("tar", ["xf", "-", "-C", abs], {
|
|
2964
|
+
input: tarBuffer,
|
|
2965
|
+
maxBuffer: 1024 * 1024 * 512
|
|
2966
|
+
});
|
|
2967
|
+
if (result.error && result.error.code === "ENOENT") {
|
|
2968
|
+
throw new Error(TAR_MISSING);
|
|
2969
|
+
}
|
|
2970
|
+
if (result.status !== 0) {
|
|
2971
|
+
throw new Error(`tar extract failed: ${result.stderr?.toString() ?? result.status}`);
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
|
|
2793
2975
|
// src/utils/csv-import.ts
|
|
2794
|
-
import { statSync } from "fs";
|
|
2976
|
+
import { statSync as statSync2 } from "fs";
|
|
2795
2977
|
import { glob, readFile } from "fs/promises";
|
|
2796
2978
|
import { basename, resolve as resolve2 } from "path";
|
|
2797
2979
|
import { parse } from "csv-parse/sync";
|
|
@@ -2866,7 +3048,7 @@ async function resolveFiles(pattern) {
|
|
|
2866
3048
|
if (/\.csv$/i.test(p)) out.push(resolve2(p));
|
|
2867
3049
|
}
|
|
2868
3050
|
} else {
|
|
2869
|
-
|
|
3051
|
+
statSync2(resolve2(part));
|
|
2870
3052
|
out.push(resolve2(part));
|
|
2871
3053
|
}
|
|
2872
3054
|
}
|
|
@@ -2925,6 +3107,20 @@ function parsePkMap(input) {
|
|
|
2925
3107
|
}
|
|
2926
3108
|
return out;
|
|
2927
3109
|
}
|
|
3110
|
+
function parseEmbeddingFields(input) {
|
|
3111
|
+
const out = {};
|
|
3112
|
+
for (const pair of input.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
3113
|
+
const idx = pair.indexOf(":");
|
|
3114
|
+
if (idx <= 0 || idx >= pair.length - 1) {
|
|
3115
|
+
throw new Error(
|
|
3116
|
+
`Invalid --embedding-fields entry '${pair}'. Expected '<table>:<col>[+<col>...][,...]'`
|
|
3117
|
+
);
|
|
3118
|
+
}
|
|
3119
|
+
const cols = pair.slice(idx + 1).split("+").map((c) => c.trim()).filter(Boolean);
|
|
3120
|
+
if (cols.length > 0) out[pair.slice(0, idx).trim()] = cols;
|
|
3121
|
+
}
|
|
3122
|
+
return out;
|
|
3123
|
+
}
|
|
2928
3124
|
function formatPkDetectionError(tableName, result) {
|
|
2929
3125
|
const lines = [`Cannot auto-detect a primary key for table '${tableName}'.`];
|
|
2930
3126
|
if (result.sampleSize === 0) {
|
|
@@ -3083,10 +3279,13 @@ async function createFromCatalog(ctx, opts) {
|
|
|
3083
3279
|
if (opts.build) {
|
|
3084
3280
|
log("Submitting build tasks...");
|
|
3085
3281
|
for (const t of targets) {
|
|
3282
|
+
const embedding = opts.embeddingFields?.[t.name];
|
|
3086
3283
|
const task = await createBuildTask(ctx, {
|
|
3087
3284
|
resource_id: viewMap[t.name],
|
|
3088
3285
|
mode: "batch",
|
|
3089
|
-
build_key_fields: [tablePk[t.name]]
|
|
3286
|
+
build_key_fields: [tablePk[t.name]],
|
|
3287
|
+
...embedding && embedding.length > 0 ? { embedding_fields: embedding } : {},
|
|
3288
|
+
...opts.embeddingModel ? { embedding_model: opts.embeddingModel } : {}
|
|
3090
3289
|
});
|
|
3091
3290
|
builds.push({ table: t.name, taskId: String(task.id ?? "") });
|
|
3092
3291
|
}
|
|
@@ -3179,6 +3378,8 @@ async function createFromCsv(ctx, opts) {
|
|
|
3179
3378
|
tables: opts.tables && opts.tables.length > 0 ? opts.tables : imported.tables,
|
|
3180
3379
|
pkMap: opts.pkMap,
|
|
3181
3380
|
build: opts.build,
|
|
3381
|
+
embeddingFields: opts.embeddingFields,
|
|
3382
|
+
embeddingModel: opts.embeddingModel,
|
|
3182
3383
|
noRollback: opts.noRollback,
|
|
3183
3384
|
sampleRows: imported.sampleRows,
|
|
3184
3385
|
onProgress: log
|
|
@@ -3251,8 +3452,32 @@ function kn(ctx) {
|
|
|
3251
3452
|
bknResources: () => listBknResources(ctx),
|
|
3252
3453
|
createFromCatalog: (opts) => createFromCatalog(ctx, opts),
|
|
3253
3454
|
createFromCsv: (opts) => createFromCsv(ctx, opts),
|
|
3254
|
-
/**
|
|
3255
|
-
|
|
3455
|
+
/**
|
|
3456
|
+
* Pack a local BKN directory and upload it as a knowledge network. With
|
|
3457
|
+
* `build`, also submit one Vega BuildTask per object type that declares a
|
|
3458
|
+
* `vector` index — the platform does not auto-build these on import.
|
|
3459
|
+
*/
|
|
3460
|
+
push: async (dir, opts) => {
|
|
3461
|
+
const upload = await uploadBkn(ctx, packDirectoryToTar(dir), { branch: opts?.branch });
|
|
3462
|
+
if (!opts?.build) return upload;
|
|
3463
|
+
const targets = collectIndexTargets(dir);
|
|
3464
|
+
const buildTasks = [];
|
|
3465
|
+
for (const t of targets) {
|
|
3466
|
+
const task = await createBuildTask(ctx, {
|
|
3467
|
+
resource_id: t.resourceId,
|
|
3468
|
+
mode: "batch",
|
|
3469
|
+
embedding_fields: t.embeddingFields,
|
|
3470
|
+
...t.buildKey ? { build_key_fields: [t.buildKey] } : {},
|
|
3471
|
+
...t.embeddingModel ?? opts.embeddingModel ? { embedding_model: t.embeddingModel ?? opts.embeddingModel } : {}
|
|
3472
|
+
});
|
|
3473
|
+
buildTasks.push({
|
|
3474
|
+
objectType: t.objectType,
|
|
3475
|
+
resourceId: t.resourceId,
|
|
3476
|
+
taskId: String(task.id ?? "")
|
|
3477
|
+
});
|
|
3478
|
+
}
|
|
3479
|
+
return { ...upload, build_tasks: buildTasks };
|
|
3480
|
+
},
|
|
3256
3481
|
/** Download a knowledge network and extract it into a local directory. */
|
|
3257
3482
|
pull: async (knId, dir, opts) => {
|
|
3258
3483
|
const tar = await downloadBkn(ctx, knId, opts);
|
|
@@ -3505,26 +3730,26 @@ function setSkillStatus(ctx, skillId, status2) {
|
|
|
3505
3730
|
}
|
|
3506
3731
|
|
|
3507
3732
|
// src/utils/skill-archive.ts
|
|
3508
|
-
import { existsSync as
|
|
3509
|
-
import { dirname, join as
|
|
3733
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
3734
|
+
import { dirname, join as join3, relative, resolve as resolve4, sep } from "path";
|
|
3510
3735
|
import JSZip from "jszip";
|
|
3511
3736
|
function walk(dir, base, files) {
|
|
3512
|
-
for (const entry of
|
|
3513
|
-
const full =
|
|
3514
|
-
const st =
|
|
3737
|
+
for (const entry of readdirSync3(dir)) {
|
|
3738
|
+
const full = join3(dir, entry);
|
|
3739
|
+
const st = statSync3(full);
|
|
3515
3740
|
if (st.isDirectory()) walk(full, base, files);
|
|
3516
3741
|
else files.push(full);
|
|
3517
3742
|
}
|
|
3518
3743
|
}
|
|
3519
3744
|
async function zipDirectory(dir) {
|
|
3520
3745
|
const abs = resolve4(dir);
|
|
3521
|
-
if (!
|
|
3746
|
+
if (!existsSync3(abs)) throw new Error(`directory not found: ${abs}`);
|
|
3522
3747
|
const zip = new JSZip();
|
|
3523
3748
|
const files = [];
|
|
3524
3749
|
walk(abs, abs, files);
|
|
3525
3750
|
for (const file of files) {
|
|
3526
3751
|
const rel = relative(abs, file).split(sep).join("/");
|
|
3527
|
-
zip.file(rel,
|
|
3752
|
+
zip.file(rel, readFileSync3(file));
|
|
3528
3753
|
}
|
|
3529
3754
|
return new Uint8Array(await zip.generateAsync({ type: "uint8array", compression: "DEFLATE" }));
|
|
3530
3755
|
}
|
|
@@ -3536,7 +3761,7 @@ async function unzipToDirectory(bytes, dir) {
|
|
|
3536
3761
|
const entries = Object.values(zip.files);
|
|
3537
3762
|
for (const entry of entries) {
|
|
3538
3763
|
if (entry.dir) continue;
|
|
3539
|
-
const out =
|
|
3764
|
+
const out = join3(abs, entry.name);
|
|
3540
3765
|
mkdirSync3(dirname(out), { recursive: true });
|
|
3541
3766
|
writeFileSync2(out, await entry.async("nodebuffer"));
|
|
3542
3767
|
written.push(out);
|
|
@@ -4525,11 +4750,14 @@ function trace(ctx) {
|
|
|
4525
4750
|
}
|
|
4526
4751
|
|
|
4527
4752
|
// src/resources/vega.ts
|
|
4528
|
-
var TERMINAL_STATES = /* @__PURE__ */ new Set(["completed", "success", "failed"]);
|
|
4753
|
+
var TERMINAL_STATES = /* @__PURE__ */ new Set(["completed", "success", "failed", "stopped", "error"]);
|
|
4529
4754
|
function vega(ctx) {
|
|
4530
4755
|
return {
|
|
4531
4756
|
catalogs: (opts) => listCatalogs(ctx, opts),
|
|
4532
4757
|
getCatalog: (id) => getCatalog(ctx, id),
|
|
4758
|
+
createCatalog: (req) => createCatalog(ctx, req),
|
|
4759
|
+
enableCatalog: (id) => enableCatalog(ctx, id),
|
|
4760
|
+
discoverCatalog: (id, wait = false) => discoverCatalog(ctx, id, wait),
|
|
4533
4761
|
catalogResources: (id, category) => listCatalogResources(ctx, id, category),
|
|
4534
4762
|
catalogHealth: (ids) => catalogHealthStatus(ctx, ids),
|
|
4535
4763
|
connectorTypes: () => listConnectorTypes(ctx),
|
|
@@ -4545,8 +4773,9 @@ function vega(ctx) {
|
|
|
4545
4773
|
}
|
|
4546
4774
|
async function pollBuildTask(ctx, taskId, timeoutMs, intervalMs) {
|
|
4547
4775
|
const deadline = Date.now() + timeoutMs;
|
|
4776
|
+
const terminal = (t) => TERMINAL_STATES.has((t.status ?? t.state ?? "").toLowerCase());
|
|
4548
4777
|
let last = await getBuildTask(ctx, taskId);
|
|
4549
|
-
while (!
|
|
4778
|
+
while (!terminal(last) && Date.now() < deadline) {
|
|
4550
4779
|
await sleep(intervalMs);
|
|
4551
4780
|
last = await getBuildTask(ctx, taskId);
|
|
4552
4781
|
}
|
|
@@ -4557,7 +4786,7 @@ function sleep(ms) {
|
|
|
4557
4786
|
}
|
|
4558
4787
|
|
|
4559
4788
|
// src/api/call.ts
|
|
4560
|
-
import { readFileSync as
|
|
4789
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
4561
4790
|
function parseHeader(raw) {
|
|
4562
4791
|
const idx = raw.indexOf(":");
|
|
4563
4792
|
if (idx <= 0) return null;
|
|
@@ -4587,7 +4816,7 @@ async function rawCall(ctx, path, opts = {}) {
|
|
|
4587
4816
|
const fd = new FormData();
|
|
4588
4817
|
for (const field of opts.form) {
|
|
4589
4818
|
const [key, value, isFile] = parseFormField(field);
|
|
4590
|
-
if (isFile) fd.append(key, new Blob([
|
|
4819
|
+
if (isFile) fd.append(key, new Blob([readFileSync4(value)]), value.split("/").pop());
|
|
4591
4820
|
else fd.append(key, value);
|
|
4592
4821
|
}
|
|
4593
4822
|
body = fd;
|
|
@@ -4780,6 +5009,7 @@ export {
|
|
|
4780
5009
|
context,
|
|
4781
5010
|
dataflows,
|
|
4782
5011
|
parsePkMap,
|
|
5012
|
+
parseEmbeddingFields,
|
|
4783
5013
|
kn,
|
|
4784
5014
|
models,
|
|
4785
5015
|
resources,
|
|
@@ -4802,4 +5032,4 @@ export {
|
|
|
4802
5032
|
exportCreds,
|
|
4803
5033
|
auth_exports
|
|
4804
5034
|
};
|
|
4805
|
-
//# sourceMappingURL=chunk-
|
|
5035
|
+
//# sourceMappingURL=chunk-ADZ23DPF.js.map
|