bluera-knowledge 0.17.2 → 0.18.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/CHANGELOG.md +92 -0
- package/README.md +3 -3
- package/dist/brands-3EYIYV6T.js +13 -0
- package/dist/chunk-CLIMKLTW.js +28 -0
- package/dist/chunk-CLIMKLTW.js.map +1 -0
- package/dist/{chunk-YMDXPECI.js → chunk-EZXJ3W5X.js} +79 -32
- package/dist/chunk-EZXJ3W5X.js.map +1 -0
- package/dist/chunk-HXBIIMYL.js +140 -0
- package/dist/chunk-HXBIIMYL.js.map +1 -0
- package/dist/{chunk-WMALVLFW.js → chunk-RDDGZIDL.js} +1095 -245
- package/dist/chunk-RDDGZIDL.js.map +1 -0
- package/dist/{chunk-PFHK5Q22.js → chunk-VUGQ7HAR.js} +10 -6
- package/dist/chunk-VUGQ7HAR.js.map +1 -0
- package/dist/index.js +231 -84
- package/dist/index.js.map +1 -1
- package/dist/mcp/bootstrap.js +22 -3
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/server.d.ts +169 -18
- package/dist/mcp/server.js +4 -3
- package/dist/watch.service-VDSUQ72Z.js +7 -0
- package/dist/watch.service-VDSUQ72Z.js.map +1 -0
- package/dist/workers/background-worker-cli.js +20 -9
- package/dist/workers/background-worker-cli.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-HRQD3MPH.js +0 -69
- package/dist/chunk-HRQD3MPH.js.map +0 -1
- package/dist/chunk-PFHK5Q22.js.map +0 -1
- package/dist/chunk-WMALVLFW.js.map +0 -1
- package/dist/chunk-YMDXPECI.js.map +0 -1
- package/dist/watch.service-OPLKIDFQ.js +0 -7
- /package/dist/{watch.service-OPLKIDFQ.js.map → brands-3EYIYV6T.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -3,34 +3,33 @@ import {
|
|
|
3
3
|
ZilAdapter,
|
|
4
4
|
runMCPServer,
|
|
5
5
|
spawnBackgroundWorker
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-EZXJ3W5X.js";
|
|
7
7
|
import {
|
|
8
8
|
IntelligentCrawler,
|
|
9
9
|
getCrawlStrategy
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-VUGQ7HAR.js";
|
|
11
11
|
import {
|
|
12
12
|
ASTParser,
|
|
13
13
|
AdapterRegistry,
|
|
14
14
|
ChunkingService,
|
|
15
15
|
JobService,
|
|
16
|
+
ProjectRootService,
|
|
16
17
|
StoreDefinitionService,
|
|
17
18
|
classifyWebContentType,
|
|
18
|
-
createDocumentId,
|
|
19
19
|
createServices,
|
|
20
|
-
createStoreId,
|
|
21
20
|
destroyServices,
|
|
22
21
|
err,
|
|
23
22
|
extractRepoName,
|
|
24
23
|
isFileStoreDefinition,
|
|
24
|
+
isGitUrl,
|
|
25
25
|
isRepoStoreDefinition,
|
|
26
26
|
isWebStoreDefinition,
|
|
27
27
|
ok
|
|
28
|
-
} from "./chunk-
|
|
29
|
-
import
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
import
|
|
33
|
-
import { join as join5 } from "path";
|
|
28
|
+
} from "./chunk-RDDGZIDL.js";
|
|
29
|
+
import {
|
|
30
|
+
createDocumentId
|
|
31
|
+
} from "./chunk-CLIMKLTW.js";
|
|
32
|
+
import "./chunk-HXBIIMYL.js";
|
|
34
33
|
|
|
35
34
|
// src/cli/commands/crawl.ts
|
|
36
35
|
import { createHash } from "crypto";
|
|
@@ -61,7 +60,11 @@ function createCrawlCommand(getOptions) {
|
|
|
61
60
|
);
|
|
62
61
|
}
|
|
63
62
|
}
|
|
64
|
-
const services = await createServices(
|
|
63
|
+
const services = await createServices(
|
|
64
|
+
globalOpts.config,
|
|
65
|
+
globalOpts.dataDir,
|
|
66
|
+
globalOpts.projectRoot
|
|
67
|
+
);
|
|
65
68
|
let store;
|
|
66
69
|
let storeCreated = false;
|
|
67
70
|
const existingStore = await services.store.getByIdOrName(storeIdOrName);
|
|
@@ -92,7 +95,12 @@ function createCrawlCommand(getOptions) {
|
|
|
92
95
|
} else {
|
|
93
96
|
store = existingStore;
|
|
94
97
|
}
|
|
95
|
-
const maxPages =
|
|
98
|
+
const maxPages = parseInt(cmdOptions.maxPages, 10);
|
|
99
|
+
if (Number.isNaN(maxPages)) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Invalid value for --max-pages: "${cmdOptions.maxPages}" is not a valid integer`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
96
104
|
const isInteractive = process.stdout.isTTY && globalOpts.quiet !== true && globalOpts.format !== "json";
|
|
97
105
|
let spinner;
|
|
98
106
|
if (isInteractive) {
|
|
@@ -101,7 +109,8 @@ function createCrawlCommand(getOptions) {
|
|
|
101
109
|
} else if (globalOpts.quiet !== true && globalOpts.format !== "json") {
|
|
102
110
|
console.log(`Crawling ${url}`);
|
|
103
111
|
}
|
|
104
|
-
const
|
|
112
|
+
const appConfig = await services.config.load();
|
|
113
|
+
const crawler = new IntelligentCrawler(appConfig.crawl);
|
|
105
114
|
const webChunker = ChunkingService.forContentType("web");
|
|
106
115
|
let pagesIndexed = 0;
|
|
107
116
|
let chunksCreated = 0;
|
|
@@ -122,6 +131,7 @@ function createCrawlCommand(getOptions) {
|
|
|
122
131
|
}
|
|
123
132
|
});
|
|
124
133
|
try {
|
|
134
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
125
135
|
await services.lance.initialize(store.id);
|
|
126
136
|
const docs = [];
|
|
127
137
|
for await (const result of crawler.crawl(url, {
|
|
@@ -150,7 +160,7 @@ function createCrawlCommand(getOptions) {
|
|
|
150
160
|
title: result.title,
|
|
151
161
|
extracted: result.extracted !== void 0,
|
|
152
162
|
depth: result.depth,
|
|
153
|
-
indexedAt: /* @__PURE__ */ new Date(),
|
|
163
|
+
indexedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
154
164
|
fileType,
|
|
155
165
|
chunkIndex: chunk.chunkIndex,
|
|
156
166
|
totalChunks: chunk.totalChunks,
|
|
@@ -165,6 +175,7 @@ function createCrawlCommand(getOptions) {
|
|
|
165
175
|
if (spinner) {
|
|
166
176
|
spinner.text = "Indexing documents...";
|
|
167
177
|
}
|
|
178
|
+
await services.lance.clearAllDocuments(store.id);
|
|
168
179
|
await services.lance.addDocuments(store.id, docs);
|
|
169
180
|
await services.lance.createFtsIndex(store.id);
|
|
170
181
|
}
|
|
@@ -203,7 +214,7 @@ function createCrawlCommand(getOptions) {
|
|
|
203
214
|
await destroyServices(services);
|
|
204
215
|
}
|
|
205
216
|
if (exitCode !== 0) {
|
|
206
|
-
process.
|
|
217
|
+
process.exitCode = exitCode;
|
|
207
218
|
}
|
|
208
219
|
}
|
|
209
220
|
);
|
|
@@ -213,9 +224,13 @@ function createCrawlCommand(getOptions) {
|
|
|
213
224
|
import { Command as Command2 } from "commander";
|
|
214
225
|
import ora2 from "ora";
|
|
215
226
|
function createIndexCommand(getOptions) {
|
|
216
|
-
const index = new Command2("index").description("Scan store files, chunk text, generate embeddings, save to LanceDB").argument("<store>", "Store ID or name").option("--force", "Re-index all files even if unchanged").action(async (storeIdOrName,
|
|
227
|
+
const index = new Command2("index").description("Scan store files, chunk text, generate embeddings, save to LanceDB").argument("<store>", "Store ID or name").option("--force", "Re-index all files even if unchanged").action(async (storeIdOrName, options) => {
|
|
217
228
|
const globalOpts = getOptions();
|
|
218
|
-
const services = await createServices(
|
|
229
|
+
const services = await createServices(
|
|
230
|
+
globalOpts.config,
|
|
231
|
+
globalOpts.dataDir,
|
|
232
|
+
globalOpts.projectRoot
|
|
233
|
+
);
|
|
219
234
|
let exitCode = 0;
|
|
220
235
|
try {
|
|
221
236
|
indexLogic: {
|
|
@@ -232,19 +247,21 @@ function createIndexCommand(getOptions) {
|
|
|
232
247
|
} else if (globalOpts.quiet !== true && globalOpts.format !== "json") {
|
|
233
248
|
console.log(`Indexing store: ${store.name}`);
|
|
234
249
|
}
|
|
250
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
235
251
|
await services.lance.initialize(store.id);
|
|
236
|
-
const
|
|
252
|
+
const progressCallback = (event) => {
|
|
237
253
|
if (event.type === "progress") {
|
|
238
254
|
if (spinner) {
|
|
239
255
|
spinner.text = `Indexing: ${String(event.current)}/${String(event.total)} files - ${event.message}`;
|
|
240
256
|
}
|
|
241
257
|
}
|
|
242
|
-
}
|
|
258
|
+
};
|
|
259
|
+
const result = options.force === true ? await services.index.indexStore(store, progressCallback) : await services.index.indexStoreIncremental(store, progressCallback);
|
|
243
260
|
if (result.success) {
|
|
244
261
|
if (globalOpts.format === "json") {
|
|
245
262
|
console.log(JSON.stringify(result.data, null, 2));
|
|
246
263
|
} else {
|
|
247
|
-
const message = `Indexed ${String(result.data.
|
|
264
|
+
const message = `Indexed ${String(result.data.filesIndexed)} documents, ${String(result.data.chunksCreated)} chunks in ${String(result.data.timeMs)}ms`;
|
|
248
265
|
if (spinner !== void 0) {
|
|
249
266
|
spinner.succeed(message);
|
|
250
267
|
} else if (globalOpts.quiet !== true) {
|
|
@@ -266,7 +283,7 @@ function createIndexCommand(getOptions) {
|
|
|
266
283
|
await destroyServices(services);
|
|
267
284
|
}
|
|
268
285
|
if (exitCode !== 0) {
|
|
269
|
-
process.
|
|
286
|
+
process.exitCode = exitCode;
|
|
270
287
|
}
|
|
271
288
|
});
|
|
272
289
|
index.command("watch <store>").description("Watch store directory; re-index when files change").option(
|
|
@@ -275,20 +292,35 @@ function createIndexCommand(getOptions) {
|
|
|
275
292
|
"1000"
|
|
276
293
|
).action(async (storeIdOrName, options) => {
|
|
277
294
|
const globalOpts = getOptions();
|
|
278
|
-
const services = await createServices(
|
|
295
|
+
const services = await createServices(
|
|
296
|
+
globalOpts.config,
|
|
297
|
+
globalOpts.dataDir,
|
|
298
|
+
globalOpts.projectRoot
|
|
299
|
+
);
|
|
279
300
|
const store = await services.store.getByIdOrName(storeIdOrName);
|
|
280
301
|
if (store === void 0 || store.type !== "file" && store.type !== "repo") {
|
|
281
302
|
console.error(`Error: File/repo store not found: ${storeIdOrName}`);
|
|
282
|
-
|
|
303
|
+
await destroyServices(services);
|
|
304
|
+
process.exitCode = 3;
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const appConfig = await services.config.load();
|
|
308
|
+
const { WatchService } = await import("./watch.service-VDSUQ72Z.js");
|
|
309
|
+
const watchService = new WatchService(services.index, services.lance, services.embeddings, {
|
|
310
|
+
ignorePatterns: appConfig.indexing.ignorePatterns
|
|
311
|
+
});
|
|
312
|
+
const debounceMs = parseInt(options.debounce, 10);
|
|
313
|
+
if (Number.isNaN(debounceMs)) {
|
|
314
|
+
throw new Error(
|
|
315
|
+
`Invalid value for --debounce: "${options.debounce}" is not a valid integer`
|
|
316
|
+
);
|
|
283
317
|
}
|
|
284
|
-
const { WatchService } = await import("./watch.service-OPLKIDFQ.js");
|
|
285
|
-
const watchService = new WatchService(services.index, services.lance);
|
|
286
318
|
if (globalOpts.quiet !== true) {
|
|
287
319
|
console.log(`Watching ${store.name} for changes...`);
|
|
288
320
|
}
|
|
289
321
|
await watchService.watch(
|
|
290
322
|
store,
|
|
291
|
-
|
|
323
|
+
debounceMs,
|
|
292
324
|
() => {
|
|
293
325
|
if (globalOpts.quiet !== true) {
|
|
294
326
|
console.log(`Re-indexed ${store.name}`);
|
|
@@ -301,8 +333,11 @@ function createIndexCommand(getOptions) {
|
|
|
301
333
|
process.on("SIGINT", () => {
|
|
302
334
|
void (async () => {
|
|
303
335
|
await watchService.unwatchAll();
|
|
336
|
+
await destroyServices(services);
|
|
304
337
|
process.exit(0);
|
|
305
|
-
})().catch(() => {
|
|
338
|
+
})().catch((err2) => {
|
|
339
|
+
console.error("Shutdown error:", err2);
|
|
340
|
+
process.exit(1);
|
|
306
341
|
});
|
|
307
342
|
});
|
|
308
343
|
});
|
|
@@ -316,7 +351,8 @@ function createMCPCommand(getOptions) {
|
|
|
316
351
|
const opts = getOptions();
|
|
317
352
|
await runMCPServer({
|
|
318
353
|
dataDir: opts.dataDir,
|
|
319
|
-
config: opts.config
|
|
354
|
+
config: opts.config,
|
|
355
|
+
projectRoot: opts.projectRoot
|
|
320
356
|
});
|
|
321
357
|
});
|
|
322
358
|
return mcp;
|
|
@@ -509,6 +545,7 @@ var DependencyUsageAnalyzer = class {
|
|
|
509
545
|
if (![
|
|
510
546
|
"node_modules",
|
|
511
547
|
".git",
|
|
548
|
+
".bluera",
|
|
512
549
|
"dist",
|
|
513
550
|
"build",
|
|
514
551
|
"coverage",
|
|
@@ -815,16 +852,19 @@ async function handleAddRepo(args, options = {}) {
|
|
|
815
852
|
});
|
|
816
853
|
if (!result.success) {
|
|
817
854
|
console.error(`Error: ${result.error.message}`);
|
|
818
|
-
process.
|
|
855
|
+
process.exitCode = 1;
|
|
856
|
+
return;
|
|
819
857
|
}
|
|
820
858
|
console.log(`Created store: ${storeName} (${result.data.id})`);
|
|
821
859
|
if ("path" in result.data) {
|
|
822
860
|
console.log(`Location: ${result.data.path}`);
|
|
823
861
|
}
|
|
824
862
|
console.log("\nIndexing...");
|
|
863
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
864
|
+
await services.lance.initialize(result.data.id);
|
|
825
865
|
const indexResult = await services.index.indexStore(result.data);
|
|
826
866
|
if (indexResult.success) {
|
|
827
|
-
console.log(`Indexed ${String(indexResult.data.
|
|
867
|
+
console.log(`Indexed ${String(indexResult.data.filesIndexed)} files`);
|
|
828
868
|
} else {
|
|
829
869
|
console.error(`Indexing failed: ${indexResult.error.message}`);
|
|
830
870
|
}
|
|
@@ -849,16 +889,19 @@ async function handleAddFolder(args, options = {}) {
|
|
|
849
889
|
});
|
|
850
890
|
if (!result.success) {
|
|
851
891
|
console.error(`Error: ${result.error.message}`);
|
|
852
|
-
process.
|
|
892
|
+
process.exitCode = 1;
|
|
893
|
+
return;
|
|
853
894
|
}
|
|
854
895
|
console.log(`Created store: ${storeName} (${result.data.id})`);
|
|
855
896
|
if ("path" in result.data) {
|
|
856
897
|
console.log(`Location: ${result.data.path}`);
|
|
857
898
|
}
|
|
858
899
|
console.log("\nIndexing...");
|
|
900
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
901
|
+
await services.lance.initialize(result.data.id);
|
|
859
902
|
const indexResult = await services.index.indexStore(result.data);
|
|
860
903
|
if (indexResult.success) {
|
|
861
|
-
console.log(`Indexed ${String(indexResult.data.
|
|
904
|
+
console.log(`Indexed ${String(indexResult.data.filesIndexed)} files`);
|
|
862
905
|
} else {
|
|
863
906
|
console.error(`Indexing failed: ${indexResult.error.message}`);
|
|
864
907
|
}
|
|
@@ -913,7 +956,8 @@ async function handleSuggest(options = {}) {
|
|
|
913
956
|
spinner.stop();
|
|
914
957
|
if (!result.success) {
|
|
915
958
|
console.error(`Error: ${result.error.message}`);
|
|
916
|
-
process.
|
|
959
|
+
process.exitCode = 1;
|
|
960
|
+
return;
|
|
917
961
|
}
|
|
918
962
|
const { usages, totalFilesScanned, skippedFiles } = result.data;
|
|
919
963
|
console.log(
|
|
@@ -1031,14 +1075,18 @@ function createSearchCommand(getOptions) {
|
|
|
1031
1075
|
).option("-n, --limit <count>", "Maximum results to return (default: 10)", "10").option("-t, --threshold <score>", "Minimum score 0-1; omit low-relevance results").option(
|
|
1032
1076
|
"--min-relevance <score>",
|
|
1033
1077
|
"Minimum raw cosine similarity 0-1; returns empty if no results meet threshold"
|
|
1034
|
-
).option(
|
|
1078
|
+
).option(
|
|
1035
1079
|
"--detail <level>",
|
|
1036
1080
|
"Context detail: minimal, contextual, full (default: minimal)",
|
|
1037
1081
|
"minimal"
|
|
1038
1082
|
).action(
|
|
1039
1083
|
async (query, options) => {
|
|
1040
1084
|
const globalOpts = getOptions();
|
|
1041
|
-
const services = await createServices(
|
|
1085
|
+
const services = await createServices(
|
|
1086
|
+
globalOpts.config,
|
|
1087
|
+
globalOpts.dataDir,
|
|
1088
|
+
globalOpts.projectRoot
|
|
1089
|
+
);
|
|
1042
1090
|
let exitCode = 0;
|
|
1043
1091
|
try {
|
|
1044
1092
|
let storeIds = (await services.store.list()).map((s) => s.id);
|
|
@@ -1063,18 +1111,48 @@ function createSearchCommand(getOptions) {
|
|
|
1063
1111
|
exitCode = 1;
|
|
1064
1112
|
break searchLogic;
|
|
1065
1113
|
}
|
|
1114
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
1066
1115
|
for (const storeId of storeIds) {
|
|
1067
1116
|
await services.lance.initialize(storeId);
|
|
1068
1117
|
}
|
|
1118
|
+
const limit = parseInt(options.limit, 10);
|
|
1119
|
+
if (Number.isNaN(limit)) {
|
|
1120
|
+
throw new Error(
|
|
1121
|
+
`Invalid value for --limit: "${options.limit}" is not a valid integer`
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
let threshold;
|
|
1125
|
+
if (options.threshold !== void 0) {
|
|
1126
|
+
threshold = parseFloat(options.threshold);
|
|
1127
|
+
if (Number.isNaN(threshold)) {
|
|
1128
|
+
throw new Error(
|
|
1129
|
+
`Invalid value for --threshold: "${options.threshold}" is not a valid number`
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
if (threshold < 0 || threshold > 1) {
|
|
1133
|
+
throw new Error(`Invalid value for --threshold: must be between 0 and 1`);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
let minRelevance;
|
|
1137
|
+
if (options.minRelevance !== void 0) {
|
|
1138
|
+
minRelevance = parseFloat(options.minRelevance);
|
|
1139
|
+
if (Number.isNaN(minRelevance)) {
|
|
1140
|
+
throw new Error(
|
|
1141
|
+
`Invalid value for --min-relevance: "${options.minRelevance}" is not a valid number`
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
if (minRelevance < 0 || minRelevance > 1) {
|
|
1145
|
+
throw new Error(`Invalid value for --min-relevance: must be between 0 and 1`);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1069
1148
|
const results = await services.search.search({
|
|
1070
1149
|
query,
|
|
1071
1150
|
stores: storeIds,
|
|
1072
|
-
mode: options.mode
|
|
1073
|
-
limit
|
|
1074
|
-
threshold
|
|
1075
|
-
minRelevance
|
|
1076
|
-
|
|
1077
|
-
detail: options.detail ?? "minimal"
|
|
1151
|
+
mode: options.mode,
|
|
1152
|
+
limit,
|
|
1153
|
+
threshold,
|
|
1154
|
+
minRelevance,
|
|
1155
|
+
detail: options.detail
|
|
1078
1156
|
});
|
|
1079
1157
|
if (globalOpts.format === "json") {
|
|
1080
1158
|
console.log(JSON.stringify(results, null, 2));
|
|
@@ -1086,7 +1164,7 @@ function createSearchCommand(getOptions) {
|
|
|
1086
1164
|
} else {
|
|
1087
1165
|
console.log(`
|
|
1088
1166
|
Search: "${query}"`);
|
|
1089
|
-
let statusLine = `Mode: ${results.mode} | Detail: ${
|
|
1167
|
+
let statusLine = `Mode: ${results.mode} | Detail: ${options.detail} | Stores: ${String(results.stores.length)} | Results: ${String(results.totalResults)} | Time: ${String(results.timeMs)}ms`;
|
|
1090
1168
|
if (results.confidence !== void 0) {
|
|
1091
1169
|
statusLine += ` | Confidence: ${results.confidence}`;
|
|
1092
1170
|
}
|
|
@@ -1168,6 +1246,8 @@ import { serve } from "@hono/node-server";
|
|
|
1168
1246
|
import { Command as Command6 } from "commander";
|
|
1169
1247
|
|
|
1170
1248
|
// src/server/app.ts
|
|
1249
|
+
import { rm } from "fs/promises";
|
|
1250
|
+
import { join as join2 } from "path";
|
|
1171
1251
|
import { Hono } from "hono";
|
|
1172
1252
|
import { cors } from "hono/cors";
|
|
1173
1253
|
import { z } from "zod";
|
|
@@ -1229,6 +1309,13 @@ function createApp(services) {
|
|
|
1229
1309
|
app.delete("/api/stores/:id", async (c) => {
|
|
1230
1310
|
const store = await services.store.getByIdOrName(c.req.param("id"));
|
|
1231
1311
|
if (!store) return c.json({ error: "Not found" }, 404);
|
|
1312
|
+
await services.lance.deleteStore(store.id);
|
|
1313
|
+
await services.codeGraph.deleteGraph(store.id);
|
|
1314
|
+
await services.manifest.delete(store.id);
|
|
1315
|
+
const resolvedDataDir = services.config.resolveDataDir();
|
|
1316
|
+
if (store.type === "repo" && "url" in store && store.url !== void 0 && store.path.startsWith(join2(resolvedDataDir, "repos"))) {
|
|
1317
|
+
await rm(store.path, { recursive: true, force: true });
|
|
1318
|
+
}
|
|
1232
1319
|
const result = await services.store.delete(store.id);
|
|
1233
1320
|
if (result.success) return c.json({ deleted: true });
|
|
1234
1321
|
return c.json({ error: result.error.message }, 400);
|
|
@@ -1240,10 +1327,22 @@ function createApp(services) {
|
|
|
1240
1327
|
return c.json({ error: parseResult.error.issues[0]?.message ?? "Invalid request body" }, 400);
|
|
1241
1328
|
}
|
|
1242
1329
|
const storeIds = (await services.store.list()).map((s) => s.id);
|
|
1330
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
1243
1331
|
for (const id of storeIds) {
|
|
1244
1332
|
await services.lance.initialize(id);
|
|
1245
1333
|
}
|
|
1246
|
-
|
|
1334
|
+
let requestedStores = storeIds;
|
|
1335
|
+
if (parseResult.data.stores !== void 0) {
|
|
1336
|
+
const resolvedStores = [];
|
|
1337
|
+
for (const requested of parseResult.data.stores) {
|
|
1338
|
+
const store = await services.store.getByIdOrName(requested);
|
|
1339
|
+
if (store === void 0) {
|
|
1340
|
+
return c.json({ error: `Store not found: ${requested}` }, 404);
|
|
1341
|
+
}
|
|
1342
|
+
resolvedStores.push(store.id);
|
|
1343
|
+
}
|
|
1344
|
+
requestedStores = resolvedStores;
|
|
1345
|
+
}
|
|
1247
1346
|
const query = {
|
|
1248
1347
|
query: parseResult.data.query,
|
|
1249
1348
|
detail: parseResult.data.detail ?? "minimal",
|
|
@@ -1256,6 +1355,7 @@ function createApp(services) {
|
|
|
1256
1355
|
app.post("/api/stores/:id/index", async (c) => {
|
|
1257
1356
|
const store = await services.store.getByIdOrName(c.req.param("id"));
|
|
1258
1357
|
if (!store) return c.json({ error: "Not found" }, 404);
|
|
1358
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
1259
1359
|
await services.lance.initialize(store.id);
|
|
1260
1360
|
const result = await services.index.indexStore(store);
|
|
1261
1361
|
if (result.success) return c.json(result.data);
|
|
@@ -1266,16 +1366,28 @@ function createApp(services) {
|
|
|
1266
1366
|
|
|
1267
1367
|
// src/cli/commands/serve.ts
|
|
1268
1368
|
function createServeCommand(getOptions) {
|
|
1269
|
-
return new Command6("serve").description("Start HTTP API server for programmatic search access").option("-p, --port <port>", "Port to listen on (
|
|
1369
|
+
return new Command6("serve").description("Start HTTP API server for programmatic search access").option("-p, --port <port>", "Port to listen on (reads from config if not specified)").option(
|
|
1270
1370
|
"--host <host>",
|
|
1271
|
-
"Bind address (
|
|
1272
|
-
"127.0.0.1"
|
|
1371
|
+
"Bind address (reads from config if not specified, use 0.0.0.0 for all interfaces)"
|
|
1273
1372
|
).action(async (options) => {
|
|
1274
1373
|
const globalOpts = getOptions();
|
|
1275
|
-
const services = await createServices(
|
|
1374
|
+
const services = await createServices(
|
|
1375
|
+
globalOpts.config,
|
|
1376
|
+
globalOpts.dataDir,
|
|
1377
|
+
globalOpts.projectRoot
|
|
1378
|
+
);
|
|
1379
|
+
const appConfig = await services.config.load();
|
|
1276
1380
|
const app = createApp(services);
|
|
1277
|
-
|
|
1278
|
-
|
|
1381
|
+
let port;
|
|
1382
|
+
if (options.port !== void 0) {
|
|
1383
|
+
port = parseInt(options.port, 10);
|
|
1384
|
+
if (Number.isNaN(port)) {
|
|
1385
|
+
throw new Error(`Invalid value for --port: "${options.port}" is not a valid integer`);
|
|
1386
|
+
}
|
|
1387
|
+
} else {
|
|
1388
|
+
port = appConfig.server.port;
|
|
1389
|
+
}
|
|
1390
|
+
const host = options.host ?? appConfig.server.host;
|
|
1279
1391
|
console.log(`Starting server on http://${host}:${String(port)}`);
|
|
1280
1392
|
const server = serve({
|
|
1281
1393
|
fetch: app.fetch,
|
|
@@ -1300,7 +1412,7 @@ import { spawnSync } from "child_process";
|
|
|
1300
1412
|
import { existsSync as existsSync2 } from "fs";
|
|
1301
1413
|
import { mkdir } from "fs/promises";
|
|
1302
1414
|
import { homedir } from "os";
|
|
1303
|
-
import { join as
|
|
1415
|
+
import { join as join3 } from "path";
|
|
1304
1416
|
import { Command as Command7 } from "commander";
|
|
1305
1417
|
import ora4 from "ora";
|
|
1306
1418
|
|
|
@@ -1357,7 +1469,7 @@ var DEFAULT_REPOS = [
|
|
|
1357
1469
|
];
|
|
1358
1470
|
|
|
1359
1471
|
// src/cli/commands/setup.ts
|
|
1360
|
-
var DEFAULT_REPOS_DIR =
|
|
1472
|
+
var DEFAULT_REPOS_DIR = join3(homedir(), ".bluera", "bluera-knowledge", "repos");
|
|
1361
1473
|
function createSetupCommand(getOptions) {
|
|
1362
1474
|
const setup = new Command7("setup").description(
|
|
1363
1475
|
"Quick-start with pre-configured Claude/Anthropic documentation repos"
|
|
@@ -1382,26 +1494,31 @@ function createSetupCommand(getOptions) {
|
|
|
1382
1494
|
}
|
|
1383
1495
|
return;
|
|
1384
1496
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
);
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
process.exit(1);
|
|
1397
|
-
}
|
|
1497
|
+
let repos = DEFAULT_REPOS;
|
|
1498
|
+
if (options.only !== void 0 && options.only !== "") {
|
|
1499
|
+
const onlyNames = options.only.split(",").map((n) => n.trim().toLowerCase());
|
|
1500
|
+
repos = DEFAULT_REPOS.filter(
|
|
1501
|
+
(r) => onlyNames.some((n) => r.name.toLowerCase().includes(n))
|
|
1502
|
+
);
|
|
1503
|
+
if (repos.length === 0) {
|
|
1504
|
+
console.error(`No repos matched: ${options.only}`);
|
|
1505
|
+
console.log("Available repos:", DEFAULT_REPOS.map((r) => r.name).join(", "));
|
|
1506
|
+
process.exitCode = 1;
|
|
1507
|
+
return;
|
|
1398
1508
|
}
|
|
1509
|
+
}
|
|
1510
|
+
const services = await createServices(
|
|
1511
|
+
globalOpts.config,
|
|
1512
|
+
globalOpts.dataDir,
|
|
1513
|
+
globalOpts.projectRoot
|
|
1514
|
+
);
|
|
1515
|
+
try {
|
|
1399
1516
|
console.log(`
|
|
1400
1517
|
Setting up ${String(repos.length)} repositories...
|
|
1401
1518
|
`);
|
|
1402
1519
|
await mkdir(options.reposDir, { recursive: true });
|
|
1403
1520
|
for (const repo of repos) {
|
|
1404
|
-
const repoPath =
|
|
1521
|
+
const repoPath = join3(options.reposDir, repo.name);
|
|
1405
1522
|
const spinner = ora4(`Processing ${repo.name}`).start();
|
|
1406
1523
|
try {
|
|
1407
1524
|
if (options.skipClone !== true) {
|
|
@@ -1450,6 +1567,7 @@ Setting up ${String(repos.length)} repositories...
|
|
|
1450
1567
|
spinner.text = `${repo.name}: Indexing...`;
|
|
1451
1568
|
const store = await services.store.getByIdOrName(storeId);
|
|
1452
1569
|
if (store) {
|
|
1570
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
1453
1571
|
await services.lance.initialize(store.id);
|
|
1454
1572
|
const indexResult = await services.index.indexStore(store, (event) => {
|
|
1455
1573
|
if (event.type === "progress") {
|
|
@@ -1458,7 +1576,7 @@ Setting up ${String(repos.length)} repositories...
|
|
|
1458
1576
|
});
|
|
1459
1577
|
if (indexResult.success) {
|
|
1460
1578
|
spinner.succeed(
|
|
1461
|
-
`${repo.name}: ${String(indexResult.data.
|
|
1579
|
+
`${repo.name}: ${String(indexResult.data.filesIndexed)} docs, ${String(indexResult.data.chunksCreated)} chunks`
|
|
1462
1580
|
);
|
|
1463
1581
|
} else {
|
|
1464
1582
|
throw new Error(
|
|
@@ -1485,8 +1603,8 @@ Setting up ${String(repos.length)} repositories...
|
|
|
1485
1603
|
}
|
|
1486
1604
|
|
|
1487
1605
|
// src/cli/commands/store.ts
|
|
1488
|
-
import { rm } from "fs/promises";
|
|
1489
|
-
import { join as
|
|
1606
|
+
import { rm as rm2 } from "fs/promises";
|
|
1607
|
+
import { join as join4 } from "path";
|
|
1490
1608
|
import { Command as Command8 } from "commander";
|
|
1491
1609
|
function createStoreCommand(getOptions) {
|
|
1492
1610
|
const store = new Command8("store").description(
|
|
@@ -1494,7 +1612,11 @@ function createStoreCommand(getOptions) {
|
|
|
1494
1612
|
);
|
|
1495
1613
|
store.command("list").description("Show all stores with their type (file/repo/web) and ID").option("-t, --type <type>", "Filter by type: file, repo, or web").action(async (options) => {
|
|
1496
1614
|
const globalOpts = getOptions();
|
|
1497
|
-
const services = await createServices(
|
|
1615
|
+
const services = await createServices(
|
|
1616
|
+
globalOpts.config,
|
|
1617
|
+
globalOpts.dataDir,
|
|
1618
|
+
globalOpts.projectRoot
|
|
1619
|
+
);
|
|
1498
1620
|
try {
|
|
1499
1621
|
const stores = await services.store.list(options.type);
|
|
1500
1622
|
if (globalOpts.format === "json") {
|
|
@@ -1524,10 +1646,14 @@ function createStoreCommand(getOptions) {
|
|
|
1524
1646
|
).requiredOption("-s, --source <path>", "Local path for file/repo stores, URL for web stores").option("-b, --branch <branch>", "Git branch to clone (repo stores only)").option("-d, --description <desc>", "Optional description for the store").option("--tags <tags>", "Comma-separated tags for filtering").action(
|
|
1525
1647
|
async (name, options) => {
|
|
1526
1648
|
const globalOpts = getOptions();
|
|
1527
|
-
const services = await createServices(
|
|
1649
|
+
const services = await createServices(
|
|
1650
|
+
globalOpts.config,
|
|
1651
|
+
globalOpts.dataDir,
|
|
1652
|
+
globalOpts.projectRoot
|
|
1653
|
+
);
|
|
1528
1654
|
let exitCode = 0;
|
|
1529
1655
|
try {
|
|
1530
|
-
const isUrl =
|
|
1656
|
+
const isUrl = isGitUrl(options.source);
|
|
1531
1657
|
const result = await services.store.create({
|
|
1532
1658
|
name,
|
|
1533
1659
|
type: options.type,
|
|
@@ -1559,7 +1685,11 @@ Created store: ${result.data.name} (${result.data.id})
|
|
|
1559
1685
|
);
|
|
1560
1686
|
store.command("info <store>").description("Show store details: ID, type, path/URL, timestamps").action(async (storeIdOrName) => {
|
|
1561
1687
|
const globalOpts = getOptions();
|
|
1562
|
-
const services = await createServices(
|
|
1688
|
+
const services = await createServices(
|
|
1689
|
+
globalOpts.config,
|
|
1690
|
+
globalOpts.dataDir,
|
|
1691
|
+
globalOpts.projectRoot
|
|
1692
|
+
);
|
|
1563
1693
|
let exitCode = 0;
|
|
1564
1694
|
storeInfo: try {
|
|
1565
1695
|
const s = await services.store.getByIdOrName(storeIdOrName);
|
|
@@ -1591,7 +1721,11 @@ Store: ${s.name}`);
|
|
|
1591
1721
|
});
|
|
1592
1722
|
store.command("delete <store>").description("Remove store and its indexed documents from LanceDB").option("-f, --force", "Delete without confirmation prompt").option("-y, --yes", "Alias for --force").action(async (storeIdOrName, options) => {
|
|
1593
1723
|
const globalOpts = getOptions();
|
|
1594
|
-
const services = await createServices(
|
|
1724
|
+
const services = await createServices(
|
|
1725
|
+
globalOpts.config,
|
|
1726
|
+
globalOpts.dataDir,
|
|
1727
|
+
globalOpts.projectRoot
|
|
1728
|
+
);
|
|
1595
1729
|
let exitCode = 0;
|
|
1596
1730
|
storeDelete: try {
|
|
1597
1731
|
const s = await services.store.getByIdOrName(storeIdOrName);
|
|
@@ -1625,10 +1759,11 @@ Store: ${s.name}`);
|
|
|
1625
1759
|
}
|
|
1626
1760
|
await services.lance.deleteStore(s.id);
|
|
1627
1761
|
await services.codeGraph.deleteGraph(s.id);
|
|
1762
|
+
await services.manifest.delete(s.id);
|
|
1628
1763
|
if (s.type === "repo" && "url" in s && s.url !== void 0) {
|
|
1629
1764
|
const dataDir = services.config.resolveDataDir();
|
|
1630
|
-
const repoPath =
|
|
1631
|
-
await
|
|
1765
|
+
const repoPath = join4(dataDir, "repos", s.id);
|
|
1766
|
+
await rm2(repoPath, { recursive: true, force: true });
|
|
1632
1767
|
}
|
|
1633
1768
|
const result = await services.store.delete(s.id);
|
|
1634
1769
|
if (result.success) {
|
|
@@ -1648,6 +1783,8 @@ Store: ${s.name}`);
|
|
|
1648
1783
|
}
|
|
1649
1784
|
|
|
1650
1785
|
// src/cli/commands/sync.ts
|
|
1786
|
+
import { rm as rm3 } from "fs/promises";
|
|
1787
|
+
import { join as join5 } from "path";
|
|
1651
1788
|
import { Command as Command9 } from "commander";
|
|
1652
1789
|
async function createStoreFromDefinition(def, defService, storeService) {
|
|
1653
1790
|
try {
|
|
@@ -1693,6 +1830,9 @@ async function createStoreFromDefinition(def, defService, storeService) {
|
|
|
1693
1830
|
type: "web",
|
|
1694
1831
|
url: def.url,
|
|
1695
1832
|
depth: def.depth,
|
|
1833
|
+
maxPages: def.maxPages,
|
|
1834
|
+
crawlInstructions: def.crawlInstructions,
|
|
1835
|
+
extractInstructions: def.extractInstructions,
|
|
1696
1836
|
description: def.description,
|
|
1697
1837
|
tags: def.tags
|
|
1698
1838
|
},
|
|
@@ -1717,7 +1857,7 @@ function createSyncCommand(getOptions) {
|
|
|
1717
1857
|
);
|
|
1718
1858
|
sync.option("--dry-run", "Show what would happen without making changes").option("--prune", "Remove stores not in definitions").option("--reindex", "Re-index existing stores after sync").action(async (options) => {
|
|
1719
1859
|
const globalOpts = getOptions();
|
|
1720
|
-
const projectRoot = globalOpts.projectRoot ??
|
|
1860
|
+
const projectRoot = globalOpts.projectRoot ?? ProjectRootService.resolve();
|
|
1721
1861
|
const defService = new StoreDefinitionService(projectRoot);
|
|
1722
1862
|
const services = await createServices(globalOpts.config, globalOpts.dataDir, projectRoot);
|
|
1723
1863
|
try {
|
|
@@ -1765,6 +1905,14 @@ function createSyncCommand(getOptions) {
|
|
|
1765
1905
|
for (const orphanName of result.orphans) {
|
|
1766
1906
|
const store = await services.store.getByName(orphanName);
|
|
1767
1907
|
if (store !== void 0) {
|
|
1908
|
+
await services.lance.deleteStore(store.id);
|
|
1909
|
+
await services.codeGraph.deleteGraph(store.id);
|
|
1910
|
+
await services.manifest.delete(store.id);
|
|
1911
|
+
if (store.type === "repo" && "url" in store && store.url !== void 0) {
|
|
1912
|
+
const dataDir = services.config.resolveDataDir();
|
|
1913
|
+
const repoPath = join5(dataDir, "repos", store.id);
|
|
1914
|
+
await rm3(repoPath, { recursive: true, force: true });
|
|
1915
|
+
}
|
|
1768
1916
|
const deleteResult = await services.store.delete(store.id, {
|
|
1769
1917
|
skipDefinitionSync: true
|
|
1770
1918
|
});
|
|
@@ -1892,13 +2040,13 @@ function printHumanReadable(result, quiet) {
|
|
|
1892
2040
|
|
|
1893
2041
|
// src/cli/program.ts
|
|
1894
2042
|
import { readFileSync } from "fs";
|
|
1895
|
-
import { dirname, join as
|
|
2043
|
+
import { dirname, join as join6 } from "path";
|
|
1896
2044
|
import { fileURLToPath } from "url";
|
|
1897
2045
|
import { Command as Command10 } from "commander";
|
|
1898
2046
|
function getVersion() {
|
|
1899
2047
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
1900
2048
|
const __dirname2 = dirname(__filename2);
|
|
1901
|
-
const content = readFileSync(
|
|
2049
|
+
const content = readFileSync(join6(__dirname2, "../package.json"), "utf-8");
|
|
1902
2050
|
const pkg = JSON.parse(content);
|
|
1903
2051
|
return pkg.version;
|
|
1904
2052
|
}
|
|
@@ -1906,7 +2054,7 @@ var version = getVersion();
|
|
|
1906
2054
|
function createProgram() {
|
|
1907
2055
|
const program2 = new Command10();
|
|
1908
2056
|
program2.name("bluera-knowledge").description("CLI tool for managing knowledge stores with semantic search").version(version);
|
|
1909
|
-
program2.option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", "Data directory").option("-p, --project-root <path>", "Project root directory (for resolving relative paths)").option("-f, --format <format>", "Output format: json | table | plain", "table").option("-q, --quiet", "Suppress non-essential output")
|
|
2057
|
+
program2.option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", "Data directory").option("-p, --project-root <path>", "Project root directory (for resolving relative paths)").option("-f, --format <format>", "Output format: json | table | plain", "table").option("-q, --quiet", "Suppress non-essential output");
|
|
1910
2058
|
return program2;
|
|
1911
2059
|
}
|
|
1912
2060
|
function getGlobalOptions(program2) {
|
|
@@ -1916,17 +2064,16 @@ function getGlobalOptions(program2) {
|
|
|
1916
2064
|
dataDir: opts.dataDir,
|
|
1917
2065
|
projectRoot: opts.projectRoot,
|
|
1918
2066
|
format: opts.format,
|
|
1919
|
-
quiet: opts.quiet
|
|
1920
|
-
verbose: opts.verbose
|
|
2067
|
+
quiet: opts.quiet
|
|
1921
2068
|
};
|
|
1922
2069
|
}
|
|
1923
2070
|
|
|
1924
2071
|
// src/index.ts
|
|
1925
2072
|
var registry = AdapterRegistry.getInstance();
|
|
1926
2073
|
registry.register(new ZilAdapter());
|
|
1927
|
-
var DEFAULT_DATA_DIR =
|
|
1928
|
-
var DEFAULT_CONFIG =
|
|
1929
|
-
var DEFAULT_REPOS_DIR2 =
|
|
2074
|
+
var DEFAULT_DATA_DIR = ".bluera/bluera-knowledge/data";
|
|
2075
|
+
var DEFAULT_CONFIG = ".bluera/bluera-knowledge/config.json";
|
|
2076
|
+
var DEFAULT_REPOS_DIR2 = ".bluera/bluera-knowledge/data/repos/<store-id>/";
|
|
1930
2077
|
function formatCommandHelp(cmd, indent = "") {
|
|
1931
2078
|
const lines = [];
|
|
1932
2079
|
const name = cmd.name();
|