@openbkn/bkn-sdk 0.1.0 → 0.1.1-alpha.0

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 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
- An agent skill (`skills/openbkn-core/SKILL.md`) lets AI tools drive the CLI in
96
- natural language. Install it with the skills CLI:
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
- npx skills add openbkn-ai/bkn-sdk@openbkn-core
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) return err.message;
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 body = CreateBuildTaskRequest.parse(req);
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",
@@ -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
- statSync(resolve2(part));
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
- /** Pack a local BKN directory and upload it as a knowledge network. */
3255
- push: (dir, opts) => uploadBkn(ctx, packDirectoryToTar(dir), opts),
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 existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
3509
- import { dirname, join as join2, relative, resolve as resolve4, sep } from "path";
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 readdirSync2(dir)) {
3513
- const full = join2(dir, entry);
3514
- const st = statSync2(full);
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 (!existsSync2(abs)) throw new Error(`directory not found: ${abs}`);
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, readFileSync2(file));
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 = join2(abs, entry.name);
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 (!TERMINAL_STATES.has((last.state ?? "").toLowerCase()) && Date.now() < deadline) {
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 readFileSync3 } from "fs";
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([readFileSync3(value)]), value.split("/").pop());
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-4NXAIG4G.js.map
5035
+ //# sourceMappingURL=chunk-DXA44XWY.js.map