bluera-knowledge 0.17.2 → 0.18.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/CHANGELOG.md +90 -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 +227 -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,7 +852,8 @@ 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) {
|
|
@@ -824,7 +862,7 @@ async function handleAddRepo(args, options = {}) {
|
|
|
824
862
|
console.log("\nIndexing...");
|
|
825
863
|
const indexResult = await services.index.indexStore(result.data);
|
|
826
864
|
if (indexResult.success) {
|
|
827
|
-
console.log(`Indexed ${String(indexResult.data.
|
|
865
|
+
console.log(`Indexed ${String(indexResult.data.filesIndexed)} files`);
|
|
828
866
|
} else {
|
|
829
867
|
console.error(`Indexing failed: ${indexResult.error.message}`);
|
|
830
868
|
}
|
|
@@ -849,7 +887,8 @@ async function handleAddFolder(args, options = {}) {
|
|
|
849
887
|
});
|
|
850
888
|
if (!result.success) {
|
|
851
889
|
console.error(`Error: ${result.error.message}`);
|
|
852
|
-
process.
|
|
890
|
+
process.exitCode = 1;
|
|
891
|
+
return;
|
|
853
892
|
}
|
|
854
893
|
console.log(`Created store: ${storeName} (${result.data.id})`);
|
|
855
894
|
if ("path" in result.data) {
|
|
@@ -858,7 +897,7 @@ async function handleAddFolder(args, options = {}) {
|
|
|
858
897
|
console.log("\nIndexing...");
|
|
859
898
|
const indexResult = await services.index.indexStore(result.data);
|
|
860
899
|
if (indexResult.success) {
|
|
861
|
-
console.log(`Indexed ${String(indexResult.data.
|
|
900
|
+
console.log(`Indexed ${String(indexResult.data.filesIndexed)} files`);
|
|
862
901
|
} else {
|
|
863
902
|
console.error(`Indexing failed: ${indexResult.error.message}`);
|
|
864
903
|
}
|
|
@@ -913,7 +952,8 @@ async function handleSuggest(options = {}) {
|
|
|
913
952
|
spinner.stop();
|
|
914
953
|
if (!result.success) {
|
|
915
954
|
console.error(`Error: ${result.error.message}`);
|
|
916
|
-
process.
|
|
955
|
+
process.exitCode = 1;
|
|
956
|
+
return;
|
|
917
957
|
}
|
|
918
958
|
const { usages, totalFilesScanned, skippedFiles } = result.data;
|
|
919
959
|
console.log(
|
|
@@ -1031,14 +1071,18 @@ function createSearchCommand(getOptions) {
|
|
|
1031
1071
|
).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
1072
|
"--min-relevance <score>",
|
|
1033
1073
|
"Minimum raw cosine similarity 0-1; returns empty if no results meet threshold"
|
|
1034
|
-
).option(
|
|
1074
|
+
).option(
|
|
1035
1075
|
"--detail <level>",
|
|
1036
1076
|
"Context detail: minimal, contextual, full (default: minimal)",
|
|
1037
1077
|
"minimal"
|
|
1038
1078
|
).action(
|
|
1039
1079
|
async (query, options) => {
|
|
1040
1080
|
const globalOpts = getOptions();
|
|
1041
|
-
const services = await createServices(
|
|
1081
|
+
const services = await createServices(
|
|
1082
|
+
globalOpts.config,
|
|
1083
|
+
globalOpts.dataDir,
|
|
1084
|
+
globalOpts.projectRoot
|
|
1085
|
+
);
|
|
1042
1086
|
let exitCode = 0;
|
|
1043
1087
|
try {
|
|
1044
1088
|
let storeIds = (await services.store.list()).map((s) => s.id);
|
|
@@ -1063,18 +1107,48 @@ function createSearchCommand(getOptions) {
|
|
|
1063
1107
|
exitCode = 1;
|
|
1064
1108
|
break searchLogic;
|
|
1065
1109
|
}
|
|
1110
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
1066
1111
|
for (const storeId of storeIds) {
|
|
1067
1112
|
await services.lance.initialize(storeId);
|
|
1068
1113
|
}
|
|
1114
|
+
const limit = parseInt(options.limit, 10);
|
|
1115
|
+
if (Number.isNaN(limit)) {
|
|
1116
|
+
throw new Error(
|
|
1117
|
+
`Invalid value for --limit: "${options.limit}" is not a valid integer`
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
let threshold;
|
|
1121
|
+
if (options.threshold !== void 0) {
|
|
1122
|
+
threshold = parseFloat(options.threshold);
|
|
1123
|
+
if (Number.isNaN(threshold)) {
|
|
1124
|
+
throw new Error(
|
|
1125
|
+
`Invalid value for --threshold: "${options.threshold}" is not a valid number`
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
if (threshold < 0 || threshold > 1) {
|
|
1129
|
+
throw new Error(`Invalid value for --threshold: must be between 0 and 1`);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
let minRelevance;
|
|
1133
|
+
if (options.minRelevance !== void 0) {
|
|
1134
|
+
minRelevance = parseFloat(options.minRelevance);
|
|
1135
|
+
if (Number.isNaN(minRelevance)) {
|
|
1136
|
+
throw new Error(
|
|
1137
|
+
`Invalid value for --min-relevance: "${options.minRelevance}" is not a valid number`
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
if (minRelevance < 0 || minRelevance > 1) {
|
|
1141
|
+
throw new Error(`Invalid value for --min-relevance: must be between 0 and 1`);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1069
1144
|
const results = await services.search.search({
|
|
1070
1145
|
query,
|
|
1071
1146
|
stores: storeIds,
|
|
1072
|
-
mode: options.mode
|
|
1073
|
-
limit
|
|
1074
|
-
threshold
|
|
1075
|
-
minRelevance
|
|
1076
|
-
|
|
1077
|
-
detail: options.detail ?? "minimal"
|
|
1147
|
+
mode: options.mode,
|
|
1148
|
+
limit,
|
|
1149
|
+
threshold,
|
|
1150
|
+
minRelevance,
|
|
1151
|
+
detail: options.detail
|
|
1078
1152
|
});
|
|
1079
1153
|
if (globalOpts.format === "json") {
|
|
1080
1154
|
console.log(JSON.stringify(results, null, 2));
|
|
@@ -1086,7 +1160,7 @@ function createSearchCommand(getOptions) {
|
|
|
1086
1160
|
} else {
|
|
1087
1161
|
console.log(`
|
|
1088
1162
|
Search: "${query}"`);
|
|
1089
|
-
let statusLine = `Mode: ${results.mode} | Detail: ${
|
|
1163
|
+
let statusLine = `Mode: ${results.mode} | Detail: ${options.detail} | Stores: ${String(results.stores.length)} | Results: ${String(results.totalResults)} | Time: ${String(results.timeMs)}ms`;
|
|
1090
1164
|
if (results.confidence !== void 0) {
|
|
1091
1165
|
statusLine += ` | Confidence: ${results.confidence}`;
|
|
1092
1166
|
}
|
|
@@ -1168,6 +1242,8 @@ import { serve } from "@hono/node-server";
|
|
|
1168
1242
|
import { Command as Command6 } from "commander";
|
|
1169
1243
|
|
|
1170
1244
|
// src/server/app.ts
|
|
1245
|
+
import { rm } from "fs/promises";
|
|
1246
|
+
import { join as join2 } from "path";
|
|
1171
1247
|
import { Hono } from "hono";
|
|
1172
1248
|
import { cors } from "hono/cors";
|
|
1173
1249
|
import { z } from "zod";
|
|
@@ -1229,6 +1305,13 @@ function createApp(services) {
|
|
|
1229
1305
|
app.delete("/api/stores/:id", async (c) => {
|
|
1230
1306
|
const store = await services.store.getByIdOrName(c.req.param("id"));
|
|
1231
1307
|
if (!store) return c.json({ error: "Not found" }, 404);
|
|
1308
|
+
await services.lance.deleteStore(store.id);
|
|
1309
|
+
await services.codeGraph.deleteGraph(store.id);
|
|
1310
|
+
await services.manifest.delete(store.id);
|
|
1311
|
+
const resolvedDataDir = services.config.resolveDataDir();
|
|
1312
|
+
if (store.type === "repo" && "url" in store && store.url !== void 0 && store.path.startsWith(join2(resolvedDataDir, "repos"))) {
|
|
1313
|
+
await rm(store.path, { recursive: true, force: true });
|
|
1314
|
+
}
|
|
1232
1315
|
const result = await services.store.delete(store.id);
|
|
1233
1316
|
if (result.success) return c.json({ deleted: true });
|
|
1234
1317
|
return c.json({ error: result.error.message }, 400);
|
|
@@ -1240,10 +1323,22 @@ function createApp(services) {
|
|
|
1240
1323
|
return c.json({ error: parseResult.error.issues[0]?.message ?? "Invalid request body" }, 400);
|
|
1241
1324
|
}
|
|
1242
1325
|
const storeIds = (await services.store.list()).map((s) => s.id);
|
|
1326
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
1243
1327
|
for (const id of storeIds) {
|
|
1244
1328
|
await services.lance.initialize(id);
|
|
1245
1329
|
}
|
|
1246
|
-
|
|
1330
|
+
let requestedStores = storeIds;
|
|
1331
|
+
if (parseResult.data.stores !== void 0) {
|
|
1332
|
+
const resolvedStores = [];
|
|
1333
|
+
for (const requested of parseResult.data.stores) {
|
|
1334
|
+
const store = await services.store.getByIdOrName(requested);
|
|
1335
|
+
if (store === void 0) {
|
|
1336
|
+
return c.json({ error: `Store not found: ${requested}` }, 404);
|
|
1337
|
+
}
|
|
1338
|
+
resolvedStores.push(store.id);
|
|
1339
|
+
}
|
|
1340
|
+
requestedStores = resolvedStores;
|
|
1341
|
+
}
|
|
1247
1342
|
const query = {
|
|
1248
1343
|
query: parseResult.data.query,
|
|
1249
1344
|
detail: parseResult.data.detail ?? "minimal",
|
|
@@ -1256,6 +1351,7 @@ function createApp(services) {
|
|
|
1256
1351
|
app.post("/api/stores/:id/index", async (c) => {
|
|
1257
1352
|
const store = await services.store.getByIdOrName(c.req.param("id"));
|
|
1258
1353
|
if (!store) return c.json({ error: "Not found" }, 404);
|
|
1354
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
1259
1355
|
await services.lance.initialize(store.id);
|
|
1260
1356
|
const result = await services.index.indexStore(store);
|
|
1261
1357
|
if (result.success) return c.json(result.data);
|
|
@@ -1266,16 +1362,28 @@ function createApp(services) {
|
|
|
1266
1362
|
|
|
1267
1363
|
// src/cli/commands/serve.ts
|
|
1268
1364
|
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 (
|
|
1365
|
+
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
1366
|
"--host <host>",
|
|
1271
|
-
"Bind address (
|
|
1272
|
-
"127.0.0.1"
|
|
1367
|
+
"Bind address (reads from config if not specified, use 0.0.0.0 for all interfaces)"
|
|
1273
1368
|
).action(async (options) => {
|
|
1274
1369
|
const globalOpts = getOptions();
|
|
1275
|
-
const services = await createServices(
|
|
1370
|
+
const services = await createServices(
|
|
1371
|
+
globalOpts.config,
|
|
1372
|
+
globalOpts.dataDir,
|
|
1373
|
+
globalOpts.projectRoot
|
|
1374
|
+
);
|
|
1375
|
+
const appConfig = await services.config.load();
|
|
1276
1376
|
const app = createApp(services);
|
|
1277
|
-
|
|
1278
|
-
|
|
1377
|
+
let port;
|
|
1378
|
+
if (options.port !== void 0) {
|
|
1379
|
+
port = parseInt(options.port, 10);
|
|
1380
|
+
if (Number.isNaN(port)) {
|
|
1381
|
+
throw new Error(`Invalid value for --port: "${options.port}" is not a valid integer`);
|
|
1382
|
+
}
|
|
1383
|
+
} else {
|
|
1384
|
+
port = appConfig.server.port;
|
|
1385
|
+
}
|
|
1386
|
+
const host = options.host ?? appConfig.server.host;
|
|
1279
1387
|
console.log(`Starting server on http://${host}:${String(port)}`);
|
|
1280
1388
|
const server = serve({
|
|
1281
1389
|
fetch: app.fetch,
|
|
@@ -1300,7 +1408,7 @@ import { spawnSync } from "child_process";
|
|
|
1300
1408
|
import { existsSync as existsSync2 } from "fs";
|
|
1301
1409
|
import { mkdir } from "fs/promises";
|
|
1302
1410
|
import { homedir } from "os";
|
|
1303
|
-
import { join as
|
|
1411
|
+
import { join as join3 } from "path";
|
|
1304
1412
|
import { Command as Command7 } from "commander";
|
|
1305
1413
|
import ora4 from "ora";
|
|
1306
1414
|
|
|
@@ -1357,7 +1465,7 @@ var DEFAULT_REPOS = [
|
|
|
1357
1465
|
];
|
|
1358
1466
|
|
|
1359
1467
|
// src/cli/commands/setup.ts
|
|
1360
|
-
var DEFAULT_REPOS_DIR =
|
|
1468
|
+
var DEFAULT_REPOS_DIR = join3(homedir(), ".bluera", "bluera-knowledge", "repos");
|
|
1361
1469
|
function createSetupCommand(getOptions) {
|
|
1362
1470
|
const setup = new Command7("setup").description(
|
|
1363
1471
|
"Quick-start with pre-configured Claude/Anthropic documentation repos"
|
|
@@ -1382,26 +1490,31 @@ function createSetupCommand(getOptions) {
|
|
|
1382
1490
|
}
|
|
1383
1491
|
return;
|
|
1384
1492
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
);
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
process.exit(1);
|
|
1397
|
-
}
|
|
1493
|
+
let repos = DEFAULT_REPOS;
|
|
1494
|
+
if (options.only !== void 0 && options.only !== "") {
|
|
1495
|
+
const onlyNames = options.only.split(",").map((n) => n.trim().toLowerCase());
|
|
1496
|
+
repos = DEFAULT_REPOS.filter(
|
|
1497
|
+
(r) => onlyNames.some((n) => r.name.toLowerCase().includes(n))
|
|
1498
|
+
);
|
|
1499
|
+
if (repos.length === 0) {
|
|
1500
|
+
console.error(`No repos matched: ${options.only}`);
|
|
1501
|
+
console.log("Available repos:", DEFAULT_REPOS.map((r) => r.name).join(", "));
|
|
1502
|
+
process.exitCode = 1;
|
|
1503
|
+
return;
|
|
1398
1504
|
}
|
|
1505
|
+
}
|
|
1506
|
+
const services = await createServices(
|
|
1507
|
+
globalOpts.config,
|
|
1508
|
+
globalOpts.dataDir,
|
|
1509
|
+
globalOpts.projectRoot
|
|
1510
|
+
);
|
|
1511
|
+
try {
|
|
1399
1512
|
console.log(`
|
|
1400
1513
|
Setting up ${String(repos.length)} repositories...
|
|
1401
1514
|
`);
|
|
1402
1515
|
await mkdir(options.reposDir, { recursive: true });
|
|
1403
1516
|
for (const repo of repos) {
|
|
1404
|
-
const repoPath =
|
|
1517
|
+
const repoPath = join3(options.reposDir, repo.name);
|
|
1405
1518
|
const spinner = ora4(`Processing ${repo.name}`).start();
|
|
1406
1519
|
try {
|
|
1407
1520
|
if (options.skipClone !== true) {
|
|
@@ -1450,6 +1563,7 @@ Setting up ${String(repos.length)} repositories...
|
|
|
1450
1563
|
spinner.text = `${repo.name}: Indexing...`;
|
|
1451
1564
|
const store = await services.store.getByIdOrName(storeId);
|
|
1452
1565
|
if (store) {
|
|
1566
|
+
services.lance.setDimensions(await services.embeddings.ensureDimensions());
|
|
1453
1567
|
await services.lance.initialize(store.id);
|
|
1454
1568
|
const indexResult = await services.index.indexStore(store, (event) => {
|
|
1455
1569
|
if (event.type === "progress") {
|
|
@@ -1458,7 +1572,7 @@ Setting up ${String(repos.length)} repositories...
|
|
|
1458
1572
|
});
|
|
1459
1573
|
if (indexResult.success) {
|
|
1460
1574
|
spinner.succeed(
|
|
1461
|
-
`${repo.name}: ${String(indexResult.data.
|
|
1575
|
+
`${repo.name}: ${String(indexResult.data.filesIndexed)} docs, ${String(indexResult.data.chunksCreated)} chunks`
|
|
1462
1576
|
);
|
|
1463
1577
|
} else {
|
|
1464
1578
|
throw new Error(
|
|
@@ -1485,8 +1599,8 @@ Setting up ${String(repos.length)} repositories...
|
|
|
1485
1599
|
}
|
|
1486
1600
|
|
|
1487
1601
|
// src/cli/commands/store.ts
|
|
1488
|
-
import { rm } from "fs/promises";
|
|
1489
|
-
import { join as
|
|
1602
|
+
import { rm as rm2 } from "fs/promises";
|
|
1603
|
+
import { join as join4 } from "path";
|
|
1490
1604
|
import { Command as Command8 } from "commander";
|
|
1491
1605
|
function createStoreCommand(getOptions) {
|
|
1492
1606
|
const store = new Command8("store").description(
|
|
@@ -1494,7 +1608,11 @@ function createStoreCommand(getOptions) {
|
|
|
1494
1608
|
);
|
|
1495
1609
|
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
1610
|
const globalOpts = getOptions();
|
|
1497
|
-
const services = await createServices(
|
|
1611
|
+
const services = await createServices(
|
|
1612
|
+
globalOpts.config,
|
|
1613
|
+
globalOpts.dataDir,
|
|
1614
|
+
globalOpts.projectRoot
|
|
1615
|
+
);
|
|
1498
1616
|
try {
|
|
1499
1617
|
const stores = await services.store.list(options.type);
|
|
1500
1618
|
if (globalOpts.format === "json") {
|
|
@@ -1524,10 +1642,14 @@ function createStoreCommand(getOptions) {
|
|
|
1524
1642
|
).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
1643
|
async (name, options) => {
|
|
1526
1644
|
const globalOpts = getOptions();
|
|
1527
|
-
const services = await createServices(
|
|
1645
|
+
const services = await createServices(
|
|
1646
|
+
globalOpts.config,
|
|
1647
|
+
globalOpts.dataDir,
|
|
1648
|
+
globalOpts.projectRoot
|
|
1649
|
+
);
|
|
1528
1650
|
let exitCode = 0;
|
|
1529
1651
|
try {
|
|
1530
|
-
const isUrl =
|
|
1652
|
+
const isUrl = isGitUrl(options.source);
|
|
1531
1653
|
const result = await services.store.create({
|
|
1532
1654
|
name,
|
|
1533
1655
|
type: options.type,
|
|
@@ -1559,7 +1681,11 @@ Created store: ${result.data.name} (${result.data.id})
|
|
|
1559
1681
|
);
|
|
1560
1682
|
store.command("info <store>").description("Show store details: ID, type, path/URL, timestamps").action(async (storeIdOrName) => {
|
|
1561
1683
|
const globalOpts = getOptions();
|
|
1562
|
-
const services = await createServices(
|
|
1684
|
+
const services = await createServices(
|
|
1685
|
+
globalOpts.config,
|
|
1686
|
+
globalOpts.dataDir,
|
|
1687
|
+
globalOpts.projectRoot
|
|
1688
|
+
);
|
|
1563
1689
|
let exitCode = 0;
|
|
1564
1690
|
storeInfo: try {
|
|
1565
1691
|
const s = await services.store.getByIdOrName(storeIdOrName);
|
|
@@ -1591,7 +1717,11 @@ Store: ${s.name}`);
|
|
|
1591
1717
|
});
|
|
1592
1718
|
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
1719
|
const globalOpts = getOptions();
|
|
1594
|
-
const services = await createServices(
|
|
1720
|
+
const services = await createServices(
|
|
1721
|
+
globalOpts.config,
|
|
1722
|
+
globalOpts.dataDir,
|
|
1723
|
+
globalOpts.projectRoot
|
|
1724
|
+
);
|
|
1595
1725
|
let exitCode = 0;
|
|
1596
1726
|
storeDelete: try {
|
|
1597
1727
|
const s = await services.store.getByIdOrName(storeIdOrName);
|
|
@@ -1625,10 +1755,11 @@ Store: ${s.name}`);
|
|
|
1625
1755
|
}
|
|
1626
1756
|
await services.lance.deleteStore(s.id);
|
|
1627
1757
|
await services.codeGraph.deleteGraph(s.id);
|
|
1758
|
+
await services.manifest.delete(s.id);
|
|
1628
1759
|
if (s.type === "repo" && "url" in s && s.url !== void 0) {
|
|
1629
1760
|
const dataDir = services.config.resolveDataDir();
|
|
1630
|
-
const repoPath =
|
|
1631
|
-
await
|
|
1761
|
+
const repoPath = join4(dataDir, "repos", s.id);
|
|
1762
|
+
await rm2(repoPath, { recursive: true, force: true });
|
|
1632
1763
|
}
|
|
1633
1764
|
const result = await services.store.delete(s.id);
|
|
1634
1765
|
if (result.success) {
|
|
@@ -1648,6 +1779,8 @@ Store: ${s.name}`);
|
|
|
1648
1779
|
}
|
|
1649
1780
|
|
|
1650
1781
|
// src/cli/commands/sync.ts
|
|
1782
|
+
import { rm as rm3 } from "fs/promises";
|
|
1783
|
+
import { join as join5 } from "path";
|
|
1651
1784
|
import { Command as Command9 } from "commander";
|
|
1652
1785
|
async function createStoreFromDefinition(def, defService, storeService) {
|
|
1653
1786
|
try {
|
|
@@ -1693,6 +1826,9 @@ async function createStoreFromDefinition(def, defService, storeService) {
|
|
|
1693
1826
|
type: "web",
|
|
1694
1827
|
url: def.url,
|
|
1695
1828
|
depth: def.depth,
|
|
1829
|
+
maxPages: def.maxPages,
|
|
1830
|
+
crawlInstructions: def.crawlInstructions,
|
|
1831
|
+
extractInstructions: def.extractInstructions,
|
|
1696
1832
|
description: def.description,
|
|
1697
1833
|
tags: def.tags
|
|
1698
1834
|
},
|
|
@@ -1717,7 +1853,7 @@ function createSyncCommand(getOptions) {
|
|
|
1717
1853
|
);
|
|
1718
1854
|
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
1855
|
const globalOpts = getOptions();
|
|
1720
|
-
const projectRoot = globalOpts.projectRoot ??
|
|
1856
|
+
const projectRoot = globalOpts.projectRoot ?? ProjectRootService.resolve();
|
|
1721
1857
|
const defService = new StoreDefinitionService(projectRoot);
|
|
1722
1858
|
const services = await createServices(globalOpts.config, globalOpts.dataDir, projectRoot);
|
|
1723
1859
|
try {
|
|
@@ -1765,6 +1901,14 @@ function createSyncCommand(getOptions) {
|
|
|
1765
1901
|
for (const orphanName of result.orphans) {
|
|
1766
1902
|
const store = await services.store.getByName(orphanName);
|
|
1767
1903
|
if (store !== void 0) {
|
|
1904
|
+
await services.lance.deleteStore(store.id);
|
|
1905
|
+
await services.codeGraph.deleteGraph(store.id);
|
|
1906
|
+
await services.manifest.delete(store.id);
|
|
1907
|
+
if (store.type === "repo" && "url" in store && store.url !== void 0) {
|
|
1908
|
+
const dataDir = services.config.resolveDataDir();
|
|
1909
|
+
const repoPath = join5(dataDir, "repos", store.id);
|
|
1910
|
+
await rm3(repoPath, { recursive: true, force: true });
|
|
1911
|
+
}
|
|
1768
1912
|
const deleteResult = await services.store.delete(store.id, {
|
|
1769
1913
|
skipDefinitionSync: true
|
|
1770
1914
|
});
|
|
@@ -1892,13 +2036,13 @@ function printHumanReadable(result, quiet) {
|
|
|
1892
2036
|
|
|
1893
2037
|
// src/cli/program.ts
|
|
1894
2038
|
import { readFileSync } from "fs";
|
|
1895
|
-
import { dirname, join as
|
|
2039
|
+
import { dirname, join as join6 } from "path";
|
|
1896
2040
|
import { fileURLToPath } from "url";
|
|
1897
2041
|
import { Command as Command10 } from "commander";
|
|
1898
2042
|
function getVersion() {
|
|
1899
2043
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
1900
2044
|
const __dirname2 = dirname(__filename2);
|
|
1901
|
-
const content = readFileSync(
|
|
2045
|
+
const content = readFileSync(join6(__dirname2, "../package.json"), "utf-8");
|
|
1902
2046
|
const pkg = JSON.parse(content);
|
|
1903
2047
|
return pkg.version;
|
|
1904
2048
|
}
|
|
@@ -1906,7 +2050,7 @@ var version = getVersion();
|
|
|
1906
2050
|
function createProgram() {
|
|
1907
2051
|
const program2 = new Command10();
|
|
1908
2052
|
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")
|
|
2053
|
+
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
2054
|
return program2;
|
|
1911
2055
|
}
|
|
1912
2056
|
function getGlobalOptions(program2) {
|
|
@@ -1916,17 +2060,16 @@ function getGlobalOptions(program2) {
|
|
|
1916
2060
|
dataDir: opts.dataDir,
|
|
1917
2061
|
projectRoot: opts.projectRoot,
|
|
1918
2062
|
format: opts.format,
|
|
1919
|
-
quiet: opts.quiet
|
|
1920
|
-
verbose: opts.verbose
|
|
2063
|
+
quiet: opts.quiet
|
|
1921
2064
|
};
|
|
1922
2065
|
}
|
|
1923
2066
|
|
|
1924
2067
|
// src/index.ts
|
|
1925
2068
|
var registry = AdapterRegistry.getInstance();
|
|
1926
2069
|
registry.register(new ZilAdapter());
|
|
1927
|
-
var DEFAULT_DATA_DIR =
|
|
1928
|
-
var DEFAULT_CONFIG =
|
|
1929
|
-
var DEFAULT_REPOS_DIR2 =
|
|
2070
|
+
var DEFAULT_DATA_DIR = ".bluera/bluera-knowledge/data";
|
|
2071
|
+
var DEFAULT_CONFIG = ".bluera/bluera-knowledge/config.json";
|
|
2072
|
+
var DEFAULT_REPOS_DIR2 = ".bluera/bluera-knowledge/data/repos/<store-id>/";
|
|
1930
2073
|
function formatCommandHelp(cmd, indent = "") {
|
|
1931
2074
|
const lines = [];
|
|
1932
2075
|
const name = cmd.name();
|