@kweaver-ai/kweaver-sdk 0.5.2 → 0.6.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 +19 -1
- package/README.zh.md +19 -1
- package/dist/api/agent-chat.d.ts +7 -1
- package/dist/api/agent-chat.js +146 -40
- package/dist/api/agent-list.js +13 -13
- package/dist/api/business-domains.js +9 -5
- package/dist/api/context-loader.js +4 -1
- package/dist/api/conversations.js +4 -9
- package/dist/api/dataflow2.d.ts +95 -0
- package/dist/api/dataflow2.js +80 -0
- package/dist/api/headers.d.ts +2 -0
- package/dist/api/headers.js +7 -2
- package/dist/api/skills.js +2 -10
- package/dist/api/vega.d.ts +0 -16
- package/dist/api/vega.js +0 -33
- package/dist/auth/oauth.d.ts +1 -1
- package/dist/auth/oauth.js +64 -7
- package/dist/cli.js +21 -1
- package/dist/client.d.ts +9 -0
- package/dist/client.js +48 -8
- package/dist/commands/auth.js +80 -32
- package/dist/commands/bkn-schema.js +22 -0
- package/dist/commands/call.js +8 -5
- package/dist/commands/dataflow.d.ts +1 -0
- package/dist/commands/dataflow.js +251 -0
- package/dist/commands/explore-bkn.d.ts +79 -0
- package/dist/commands/explore-bkn.js +273 -0
- package/dist/commands/explore-chat.d.ts +3 -0
- package/dist/commands/explore-chat.js +193 -0
- package/dist/commands/explore-vega.d.ts +3 -0
- package/dist/commands/explore-vega.js +71 -0
- package/dist/commands/explore.d.ts +9 -0
- package/dist/commands/explore.js +258 -0
- package/dist/commands/vega.js +2 -104
- package/dist/config/no-auth.d.ts +3 -0
- package/dist/config/no-auth.js +5 -0
- package/dist/config/store.d.ts +8 -0
- package/dist/config/store.js +22 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/kweaver.d.ts +5 -0
- package/dist/kweaver.js +32 -2
- package/dist/resources/bkn.js +2 -3
- package/dist/resources/knowledge-networks.js +3 -8
- package/dist/resources/vega.d.ts +0 -6
- package/dist/resources/vega.js +1 -10
- package/dist/templates/explorer/app.js +136 -0
- package/dist/templates/explorer/bkn.js +747 -0
- package/dist/templates/explorer/chat.js +980 -0
- package/dist/templates/explorer/dashboard.js +82 -0
- package/dist/templates/explorer/index.html +35 -0
- package/dist/templates/explorer/style.css +2440 -0
- package/dist/templates/explorer/vega.js +291 -0
- package/dist/utils/http.d.ts +3 -0
- package/dist/utils/http.js +37 -1
- package/package.json +9 -5
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// ── Vega Tab ─────────────────────────────────────────────────────────────────
|
|
2
|
+
|
|
3
|
+
// Caches
|
|
4
|
+
const vegaCatalogCache = {};
|
|
5
|
+
const vegaResourcesCache = {};
|
|
6
|
+
const vegaDataCache = {};
|
|
7
|
+
|
|
8
|
+
// ── API wrappers ──────────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
async function vegaLoadCatalogs() {
|
|
11
|
+
return cachedFetch(vegaCatalogCache, "all", () => api("GET", "/api/vega/catalogs"));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function vegaLoadResources(catalogId) {
|
|
15
|
+
return cachedFetch(vegaResourcesCache, catalogId, () =>
|
|
16
|
+
api("GET", `/api/vega/catalog-resources?catalogId=${enc(catalogId)}`),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function vegaQueryData(resourceId, query) {
|
|
21
|
+
const key = `${resourceId}::${JSON.stringify(query ?? {})}`;
|
|
22
|
+
return cachedFetch(vegaDataCache, key, () =>
|
|
23
|
+
api("POST", "/api/vega/query", { resourceId, query: query ?? {} }),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ── Health indicator ──────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
function vegaHealthDot(status) {
|
|
30
|
+
if (!status) return '<span class="health-dot unknown" title="Unknown"></span>';
|
|
31
|
+
const s = String(status).toLowerCase();
|
|
32
|
+
if (s === "healthy" || s === "ok" || s === "active") return '<span class="health-dot healthy" title="Healthy"></span>';
|
|
33
|
+
if (s === "unhealthy" || s === "error" || s === "failed") return '<span class="health-dot unhealthy" title="Unhealthy"></span>';
|
|
34
|
+
return `<span class="health-dot unknown" title="${esc(status)}"></span>`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function vegaGetHealth(health, catalogId) {
|
|
38
|
+
if (!health || health.error) return null;
|
|
39
|
+
// health may be an object keyed by catalog id, or an array of { id, status } items
|
|
40
|
+
if (Array.isArray(health)) {
|
|
41
|
+
const entry = health.find(h => h.id === catalogId || h.catalog_id === catalogId);
|
|
42
|
+
return entry ? (entry.status ?? entry.health_status ?? null) : null;
|
|
43
|
+
}
|
|
44
|
+
if (typeof health === "object") {
|
|
45
|
+
const entry = health[catalogId];
|
|
46
|
+
if (entry && typeof entry === "object") return entry.status ?? entry.health_status ?? null;
|
|
47
|
+
if (typeof entry === "string") return entry;
|
|
48
|
+
// Try nested data / entries
|
|
49
|
+
const items = health.data ?? health.entries ?? health.items;
|
|
50
|
+
if (Array.isArray(items)) {
|
|
51
|
+
const found = items.find(h => h.id === catalogId || h.catalog_id === catalogId);
|
|
52
|
+
return found ? (found.status ?? found.health_status ?? null) : null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── Catalog list view ─────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
function vegaRenderCatalogList($el, data) {
|
|
61
|
+
const { catalogs, health } = data;
|
|
62
|
+
const items = extractList(catalogs);
|
|
63
|
+
|
|
64
|
+
if (items.length === 0) {
|
|
65
|
+
$el.innerHTML = `
|
|
66
|
+
<div class="section-header"><h2>Vega Catalogs</h2></div>
|
|
67
|
+
<div class="empty-state">No catalogs found.</div>`;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const cards = items.map(cat => {
|
|
72
|
+
const healthStatus = vegaGetHealth(health, cat.id);
|
|
73
|
+
const dot = vegaHealthDot(healthStatus);
|
|
74
|
+
const name = esc(cat.name ?? cat.id);
|
|
75
|
+
const connType = esc(cat.connector_type ?? cat.type ?? "—");
|
|
76
|
+
return `
|
|
77
|
+
<a class="catalog-card" href="#/vega/${enc(cat.id)}">
|
|
78
|
+
<div class="catalog-card-header">
|
|
79
|
+
<span class="health-indicator">${dot}</span>
|
|
80
|
+
<span class="catalog-name">${name}</span>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="catalog-meta">${connType}</div>
|
|
83
|
+
</a>`;
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
$el.innerHTML = `
|
|
87
|
+
<div class="vega-view">
|
|
88
|
+
<h2>Vega Catalogs <span style="color:var(--text-secondary);font-weight:400">(${items.length})</span></h2>
|
|
89
|
+
<div class="catalog-grid">${cards.join("")}</div>
|
|
90
|
+
</div>`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── Resource list view ────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
function vegaRenderResourceList($el, catalogId, data) {
|
|
96
|
+
const items = extractList(data);
|
|
97
|
+
|
|
98
|
+
const breadcrumb = `
|
|
99
|
+
<div class="breadcrumb">
|
|
100
|
+
<a href="#/vega">Catalogs</a> / <strong>${esc(catalogId)}</strong>
|
|
101
|
+
</div>`;
|
|
102
|
+
|
|
103
|
+
if (items.length === 0) {
|
|
104
|
+
$el.innerHTML = `${breadcrumb}
|
|
105
|
+
<div class="section-header"><h2>Resources</h2></div>
|
|
106
|
+
<div class="empty-state">No resources found in this catalog.</div>`;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const rows = items.map(r => {
|
|
111
|
+
const name = esc(r.name ?? r.id);
|
|
112
|
+
const rtype = esc(r.category ?? r.type ?? r.resource_type ?? "—");
|
|
113
|
+
const fields = r.schema?.fields?.length ?? r.fields?.length ?? r.field_count ?? "—";
|
|
114
|
+
return `
|
|
115
|
+
<tr style="cursor:pointer" onclick="location.hash='/vega/${enc(catalogId)}/${enc(r.id)}'">
|
|
116
|
+
<td>${name}</td>
|
|
117
|
+
<td>${esc(r.id)}</td>
|
|
118
|
+
<td>${rtype}</td>
|
|
119
|
+
<td>${esc(String(fields))}</td>
|
|
120
|
+
</tr>`;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
$el.innerHTML = `
|
|
124
|
+
${breadcrumb}
|
|
125
|
+
<div class="section-header"><h2>Resources <span class="count">(${items.length})</span></h2></div>
|
|
126
|
+
<table>
|
|
127
|
+
<thead><tr><th>Name</th><th>ID</th><th>Type</th><th>Fields</th></tr></thead>
|
|
128
|
+
<tbody>${rows.join("")}</tbody>
|
|
129
|
+
</table>`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ── Resource detail / data preview ───────────────────────────────────────────
|
|
133
|
+
|
|
134
|
+
function vegaRenderSchema(fields) {
|
|
135
|
+
if (!Array.isArray(fields) || fields.length === 0) return "";
|
|
136
|
+
const rows = fields.map(f => `
|
|
137
|
+
<tr>
|
|
138
|
+
<td>${esc(f.name ?? f.field_name ?? "—")}</td>
|
|
139
|
+
<td>${esc(f.type ?? f.data_type ?? "—")}</td>
|
|
140
|
+
<td>${esc(f.description ?? "")}</td>
|
|
141
|
+
</tr>`).join("");
|
|
142
|
+
return `
|
|
143
|
+
<div class="section-header" style="margin-top:1.5rem"><h3>Schema Fields <span class="count">(${fields.length})</span></h3></div>
|
|
144
|
+
<table>
|
|
145
|
+
<thead><tr><th>Name</th><th>Type</th><th>Description</th></tr></thead>
|
|
146
|
+
<tbody>${rows}</tbody>
|
|
147
|
+
</table>`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function vegaRenderDataPreview(rawData, fields) {
|
|
151
|
+
let rows = [];
|
|
152
|
+
if (Array.isArray(rawData)) {
|
|
153
|
+
rows = rawData;
|
|
154
|
+
} else if (rawData && typeof rawData === "object") {
|
|
155
|
+
rows = rawData.data ?? rawData.entries ?? rawData.rows ?? rawData.items ?? [];
|
|
156
|
+
}
|
|
157
|
+
if (!Array.isArray(rows) || rows.length === 0) {
|
|
158
|
+
return '<div class="empty-state">No data rows available.</div>';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const preview = rows.slice(0, 20);
|
|
162
|
+
|
|
163
|
+
// Determine columns: from schema fields or from first row keys
|
|
164
|
+
let cols;
|
|
165
|
+
if (Array.isArray(fields) && fields.length > 0) {
|
|
166
|
+
cols = fields.map(f => f.name ?? f.field_name).filter(Boolean);
|
|
167
|
+
} else if (typeof preview[0] === "object" && preview[0] !== null) {
|
|
168
|
+
cols = Object.keys(preview[0]);
|
|
169
|
+
} else {
|
|
170
|
+
cols = ["value"];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const headers = cols.map(c => `<th>${esc(c)}</th>`).join("");
|
|
174
|
+
const dataRows = preview.map(row => {
|
|
175
|
+
const cells = cols.map(c => {
|
|
176
|
+
const v = typeof row === "object" && row !== null ? row[c] : row;
|
|
177
|
+
return `<td>${formatValue(v)}</td>`;
|
|
178
|
+
});
|
|
179
|
+
return `<tr>${cells.join("")}</tr>`;
|
|
180
|
+
}).join("");
|
|
181
|
+
|
|
182
|
+
return `
|
|
183
|
+
<div class="section-header" style="margin-top:1.5rem">
|
|
184
|
+
<h3>Data Preview <span class="count">(first ${preview.length} rows)</span></h3>
|
|
185
|
+
</div>
|
|
186
|
+
<div style="overflow-x:auto">
|
|
187
|
+
<table>
|
|
188
|
+
<thead><tr>${headers}</tr></thead>
|
|
189
|
+
<tbody>${dataRows}</tbody>
|
|
190
|
+
</table>
|
|
191
|
+
</div>`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function vegaRenderResourceDetail($el, catalogId, resourceId) {
|
|
195
|
+
const breadcrumb = `
|
|
196
|
+
<div class="breadcrumb">
|
|
197
|
+
<a href="#/vega">Catalogs</a> /
|
|
198
|
+
<a href="#/vega/${enc(catalogId)}">${esc(catalogId)}</a> /
|
|
199
|
+
<strong>${esc(resourceId)}</strong>
|
|
200
|
+
</div>`;
|
|
201
|
+
|
|
202
|
+
$el.innerHTML = `${breadcrumb}<div class="loading-skeleton"><div class="skeleton skeleton-title"></div><div class="skeleton skeleton-list-item"></div><div class="skeleton skeleton-list-item"></div></div>`;
|
|
203
|
+
|
|
204
|
+
// Load resources list to get schema for this resource
|
|
205
|
+
let schemaFields = [];
|
|
206
|
+
try {
|
|
207
|
+
const resourcesData = await vegaLoadResources(catalogId);
|
|
208
|
+
const items = extractList(resourcesData);
|
|
209
|
+
const res = items.find(r => r.id === resourceId);
|
|
210
|
+
if (res) {
|
|
211
|
+
schemaFields = res.schema?.fields ?? res.fields ?? [];
|
|
212
|
+
}
|
|
213
|
+
} catch { /* schema is best-effort */ }
|
|
214
|
+
|
|
215
|
+
// Query first 20 rows
|
|
216
|
+
let dataPreviewHtml = "";
|
|
217
|
+
try {
|
|
218
|
+
const rawData = await vegaQueryData(resourceId, { limit: 20 });
|
|
219
|
+
dataPreviewHtml = vegaRenderDataPreview(rawData, schemaFields);
|
|
220
|
+
} catch (e) {
|
|
221
|
+
dataPreviewHtml = `
|
|
222
|
+
<div class="error-boundary">
|
|
223
|
+
<div class="error-icon">⚠️</div>
|
|
224
|
+
<h3>Failed to load data</h3>
|
|
225
|
+
<p>${esc(String(e))}</p>
|
|
226
|
+
<button class="retry-btn" onclick="location.reload()">Retry</button>
|
|
227
|
+
</div>`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
$el.innerHTML = `
|
|
231
|
+
${breadcrumb}
|
|
232
|
+
<div class="section-header"><h2>${esc(resourceId)}</h2></div>
|
|
233
|
+
${vegaRenderSchema(schemaFields)}
|
|
234
|
+
${dataPreviewHtml}`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ── Main dispatcher ───────────────────────────────────────────────────────────
|
|
238
|
+
|
|
239
|
+
async function renderVega($el, parts, _params) {
|
|
240
|
+
const myGen = navGeneration;
|
|
241
|
+
|
|
242
|
+
// parts = [] → catalog list + discover tasks
|
|
243
|
+
// parts = [catalogId] → resources in that catalog
|
|
244
|
+
// parts = [catalogId, resourceId] → resource detail + data preview
|
|
245
|
+
|
|
246
|
+
if (parts.length === 0) {
|
|
247
|
+
$el.innerHTML = '<div class="loading-skeleton"><div class="skeleton skeleton-title"></div><div class="loading-skeleton grid"><div class="skeleton skeleton-card"></div><div class="skeleton skeleton-card"></div></div></div>';
|
|
248
|
+
try {
|
|
249
|
+
const data = await vegaLoadCatalogs();
|
|
250
|
+
if (navGeneration !== myGen) return;
|
|
251
|
+
vegaRenderCatalogList($el, data);
|
|
252
|
+
} catch (e) {
|
|
253
|
+
if (navGeneration !== myGen) return;
|
|
254
|
+
$el.innerHTML = `
|
|
255
|
+
<div class="error-boundary">
|
|
256
|
+
<div class="error-icon">⚠️</div>
|
|
257
|
+
<h3>Failed to load catalogs</h3>
|
|
258
|
+
<p>${esc(String(e))}</p>
|
|
259
|
+
<button class="retry-btn" onclick="location.reload()">Retry</button>
|
|
260
|
+
</div>`;
|
|
261
|
+
}
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const [catalogId, resourceId] = parts;
|
|
266
|
+
|
|
267
|
+
if (!resourceId) {
|
|
268
|
+
$el.innerHTML = `
|
|
269
|
+
<div class="breadcrumb"><a href="#/vega">Catalogs</a> / <strong>${esc(catalogId)}</strong></div>
|
|
270
|
+
<div class="loading-skeleton"><div class="skeleton skeleton-title"></div><div class="skeleton skeleton-list-item"></div><div class="skeleton skeleton-list-item"></div></div>`;
|
|
271
|
+
try {
|
|
272
|
+
const data = await vegaLoadResources(catalogId);
|
|
273
|
+
if (navGeneration !== myGen) return;
|
|
274
|
+
vegaRenderResourceList($el, catalogId, data);
|
|
275
|
+
} catch (e) {
|
|
276
|
+
if (navGeneration !== myGen) return;
|
|
277
|
+
$el.innerHTML = `
|
|
278
|
+
<div class="breadcrumb"><a href="#/vega">Catalogs</a> / <strong>${esc(catalogId)}</strong></div>
|
|
279
|
+
<div class="error-boundary">
|
|
280
|
+
<div class="error-icon">🔒</div>
|
|
281
|
+
<h3>Permission Denied or Failed to Load Resources</h3>
|
|
282
|
+
<p>${esc(String(e))}</p>
|
|
283
|
+
<button class="retry-btn" onclick="location.reload()">Retry</button>
|
|
284
|
+
</div>`;
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Resource detail
|
|
290
|
+
await vegaRenderResourceDetail($el, catalogId, resourceId);
|
|
291
|
+
}
|
package/dist/utils/http.d.ts
CHANGED
|
@@ -11,6 +11,9 @@ export declare class NetworkRequestError extends Error {
|
|
|
11
11
|
readonly hint: string;
|
|
12
12
|
constructor(method: string, url: string, causeMessage: string, hint: string);
|
|
13
13
|
}
|
|
14
|
+
/** fetch() with automatic retry on transient network errors (TLS, socket, DNS).
|
|
15
|
+
* Only retries safe (idempotent) HTTP methods by default. */
|
|
16
|
+
export declare function fetchWithRetry(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
14
17
|
export declare function fetchTextOrThrow(input: RequestInfo | URL, init?: RequestInit): Promise<{
|
|
15
18
|
response: Response;
|
|
16
19
|
body: string;
|
package/dist/utils/http.js
CHANGED
|
@@ -45,10 +45,46 @@ function buildNetworkHint(causeMessage) {
|
|
|
45
45
|
}
|
|
46
46
|
return "Check whether the platform URL is correct and whether it exposes /oauth2/clients over HTTPS.";
|
|
47
47
|
}
|
|
48
|
+
function isTransientNetworkError(error) {
|
|
49
|
+
if (!(error instanceof Error))
|
|
50
|
+
return false;
|
|
51
|
+
const msg = ("cause" in error && error.cause instanceof Error
|
|
52
|
+
? error.cause.message
|
|
53
|
+
: error.message).toLowerCase();
|
|
54
|
+
return (msg.includes("tls") ||
|
|
55
|
+
msg.includes("socket") ||
|
|
56
|
+
msg.includes("econnreset") ||
|
|
57
|
+
msg.includes("econnrefused") ||
|
|
58
|
+
msg.includes("certificate") ||
|
|
59
|
+
msg.includes("disconnect") ||
|
|
60
|
+
msg.includes("etimedout") ||
|
|
61
|
+
msg.includes("eai_again"));
|
|
62
|
+
}
|
|
63
|
+
const RETRY_DELAYS = [300, 800];
|
|
64
|
+
const SAFE_RETRY_METHODS = new Set(["GET", "HEAD", "OPTIONS"]);
|
|
65
|
+
/** fetch() with automatic retry on transient network errors (TLS, socket, DNS).
|
|
66
|
+
* Only retries safe (idempotent) HTTP methods by default. */
|
|
67
|
+
export async function fetchWithRetry(input, init) {
|
|
68
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
69
|
+
const canRetry = SAFE_RETRY_METHODS.has(method);
|
|
70
|
+
let lastError;
|
|
71
|
+
for (let attempt = 0; attempt <= RETRY_DELAYS.length; attempt++) {
|
|
72
|
+
try {
|
|
73
|
+
return await fetch(input, init);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
lastError = error;
|
|
77
|
+
if (!canRetry || !isTransientNetworkError(error) || attempt === RETRY_DELAYS.length)
|
|
78
|
+
break;
|
|
79
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt]));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
throw lastError;
|
|
83
|
+
}
|
|
48
84
|
export async function fetchTextOrThrow(input, init) {
|
|
49
85
|
let response;
|
|
50
86
|
try {
|
|
51
|
-
response = await
|
|
87
|
+
response = await fetchWithRetry(input, init);
|
|
52
88
|
}
|
|
53
89
|
catch (error) {
|
|
54
90
|
const url = typeof input === "string"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kweaver-ai/kweaver-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "KWeaver TypeScript SDK — CLI tool and programmatic API for knowledge networks and Decision Agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
26
|
"dev": "tsx watch src/cli.ts",
|
|
27
|
-
"build": "tsc -p tsconfig.json",
|
|
27
|
+
"build": "tsc -p tsconfig.json && (cp -r src/templates dist/ 2>/dev/null || true)",
|
|
28
28
|
"start": "node ./dist/cli.js",
|
|
29
29
|
"lint": "tsc --noEmit -p tsconfig.json",
|
|
30
30
|
"test": "node --import tsx --test test/*.test.ts",
|
|
31
|
-
"test:e2e": "node --import tsx
|
|
32
|
-
"test:e2e:
|
|
31
|
+
"test:e2e": "node --import tsx --test test/e2e/*.test.ts",
|
|
32
|
+
"test:e2e:live": "KWEAVER_BASE_URL=${KWEAVER_BASE_URL:-https://43.129.210.161} KWEAVER_NO_AUTH=1 KWEAVER_TLS_INSECURE=1 node --import tsx --test test/e2e/*.test.ts",
|
|
33
33
|
"prepublishOnly": "npm run build"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "^24.6.0",
|
|
53
53
|
"@types/react": "^19.2.14",
|
|
54
|
+
"@types/yargs": "^17.0.35",
|
|
54
55
|
"playwright": "^1.58.2",
|
|
55
56
|
"tsx": "^4.20.5",
|
|
56
57
|
"typescript": "^5.9.3"
|
|
@@ -67,12 +68,15 @@
|
|
|
67
68
|
"@kweaver-ai/bkn": "^0.1.0",
|
|
68
69
|
"@playwright/test": "^1.58.2",
|
|
69
70
|
"chardet": "^2.1.1",
|
|
71
|
+
"columnify": "^1.6.0",
|
|
70
72
|
"csv-parse": "^6.2.1",
|
|
71
73
|
"iconv-lite": "^0.7.2",
|
|
72
74
|
"ink": "^6.8.0",
|
|
73
75
|
"ink-spinner": "^5.0.0",
|
|
74
76
|
"ink-text-input": "^6.0.0",
|
|
75
77
|
"marked": "^11.2.0",
|
|
76
|
-
"react": "^19.2.4"
|
|
78
|
+
"react": "^19.2.4",
|
|
79
|
+
"string-width": "^8.2.0",
|
|
80
|
+
"yargs": "^18.0.0"
|
|
77
81
|
}
|
|
78
82
|
}
|