bluera-knowledge 0.11.9 → 0.11.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bluera-knowledge",
3
- "version": "0.11.9",
3
+ "version": "0.11.10",
4
4
  "description": "CLI tool for managing knowledge stores with semantic search",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,9 +9,10 @@ import {
9
9
  } from './commands.js';
10
10
  import type { ServiceContainer } from '../services/index.js';
11
11
 
12
- // Mock the createServices function
12
+ // Mock the createServices and destroyServices functions
13
13
  vi.mock('../services/index.js', () => ({
14
14
  createServices: vi.fn(),
15
+ destroyServices: vi.fn().mockResolvedValue(undefined),
15
16
  }));
16
17
 
17
18
  // Mock extractRepoName
@@ -2,7 +2,7 @@ import ora from 'ora';
2
2
  import { extractRepoName } from './git-clone.js';
3
3
  import { DependencyUsageAnalyzer } from '../analysis/dependency-usage-analyzer.js';
4
4
  import { RepoUrlResolver } from '../analysis/repo-url-resolver.js';
5
- import { createServices } from '../services/index.js';
5
+ import { createServices, destroyServices } from '../services/index.js';
6
6
 
7
7
  /**
8
8
  * Options passed from CLI global options to plugin command handlers.
@@ -22,37 +22,42 @@ export async function handleSearch(args: {
22
22
  }): Promise<void> {
23
23
  // PWD is set by Claude Code to user's project directory
24
24
  const services = await createServices(undefined, undefined, process.env['PWD']);
25
- const storeNames = args.stores?.split(',').map((s: string) => s.trim());
26
25
 
27
- const allStores = await services.store.list();
28
- const targetStores =
29
- storeNames !== undefined ? allStores.filter((s) => storeNames.includes(s.name)) : allStores;
26
+ try {
27
+ const storeNames = args.stores?.split(',').map((s: string) => s.trim());
30
28
 
31
- if (targetStores.length === 0) {
32
- console.error('No stores found to search');
33
- process.exit(1);
34
- }
29
+ const allStores = await services.store.list();
30
+ const targetStores =
31
+ storeNames !== undefined ? allStores.filter((s) => storeNames.includes(s.name)) : allStores;
35
32
 
36
- // Initialize stores
37
- for (const store of targetStores) {
38
- await services.lance.initialize(store.id);
39
- }
33
+ if (targetStores.length === 0) {
34
+ console.error('No stores found to search');
35
+ process.exit(1);
36
+ }
40
37
 
41
- const results = await services.search.search({
42
- query: args.query,
43
- stores: targetStores.map((s) => s.id),
44
- mode: 'hybrid',
45
- limit: parseInt(args.limit ?? '10', 10),
46
- detail: 'contextual',
47
- });
48
-
49
- console.log(`Found ${String(results.totalResults)} results:\n`);
50
- for (const r of results.results) {
51
- if (r.summary !== undefined) {
52
- console.log(`Score: ${r.score.toFixed(2)} - ${r.summary.location}`);
53
- console.log(r.summary.purpose);
38
+ // Initialize stores
39
+ for (const store of targetStores) {
40
+ await services.lance.initialize(store.id);
54
41
  }
55
- console.log('---');
42
+
43
+ const results = await services.search.search({
44
+ query: args.query,
45
+ stores: targetStores.map((s) => s.id),
46
+ mode: 'hybrid',
47
+ limit: parseInt(args.limit ?? '10', 10),
48
+ detail: 'contextual',
49
+ });
50
+
51
+ console.log(`Found ${String(results.totalResults)} results:\n`);
52
+ for (const r of results.results) {
53
+ if (r.summary !== undefined) {
54
+ console.log(`Score: ${r.score.toFixed(2)} - ${r.summary.location}`);
55
+ console.log(r.summary.purpose);
56
+ }
57
+ console.log('---');
58
+ }
59
+ } finally {
60
+ await destroyServices(services);
56
61
  }
57
62
  }
58
63
 
@@ -69,35 +74,40 @@ export async function handleAddRepo(
69
74
  options.dataDir,
70
75
  options.projectRoot ?? process.env['PWD']
71
76
  );
72
- const storeName = args.name ?? extractRepoName(args.url);
73
77
 
74
- console.log(`Cloning ${args.url}...`);
78
+ try {
79
+ const storeName = args.name ?? extractRepoName(args.url);
75
80
 
76
- const result = await services.store.create({
77
- name: storeName,
78
- type: 'repo',
79
- url: args.url,
80
- ...(args.branch !== undefined ? { branch: args.branch } : {}),
81
- });
81
+ console.log(`Cloning ${args.url}...`);
82
82
 
83
- if (!result.success) {
84
- console.error(`Error: ${result.error.message}`);
85
- process.exit(1);
86
- }
83
+ const result = await services.store.create({
84
+ name: storeName,
85
+ type: 'repo',
86
+ url: args.url,
87
+ ...(args.branch !== undefined ? { branch: args.branch } : {}),
88
+ });
87
89
 
88
- console.log(`Created store: ${storeName} (${result.data.id})`);
89
- if ('path' in result.data) {
90
- console.log(`Location: ${result.data.path}`);
91
- }
90
+ if (!result.success) {
91
+ console.error(`Error: ${result.error.message}`);
92
+ process.exit(1);
93
+ }
94
+
95
+ console.log(`Created store: ${storeName} (${result.data.id})`);
96
+ if ('path' in result.data) {
97
+ console.log(`Location: ${result.data.path}`);
98
+ }
92
99
 
93
- // Auto-index
94
- console.log('\nIndexing...');
95
- const indexResult = await services.index.indexStore(result.data);
100
+ // Auto-index
101
+ console.log('\nIndexing...');
102
+ const indexResult = await services.index.indexStore(result.data);
96
103
 
97
- if (indexResult.success) {
98
- console.log(`Indexed ${String(indexResult.data.documentsIndexed)} files`);
99
- } else {
100
- console.error(`Indexing failed: ${indexResult.error.message}`);
104
+ if (indexResult.success) {
105
+ console.log(`Indexed ${String(indexResult.data.documentsIndexed)} files`);
106
+ } else {
107
+ console.error(`Indexing failed: ${indexResult.error.message}`);
108
+ }
109
+ } finally {
110
+ await destroyServices(services);
101
111
  }
102
112
  }
103
113
 
@@ -110,58 +120,68 @@ export async function handleAddFolder(
110
120
  options.dataDir,
111
121
  options.projectRoot ?? process.env['PWD']
112
122
  );
113
- const { basename } = await import('node:path');
114
- const storeName = args.name ?? basename(args.path);
115
123
 
116
- console.log(`Adding folder: ${args.path}...`);
124
+ try {
125
+ const { basename } = await import('node:path');
126
+ const storeName = args.name ?? basename(args.path);
117
127
 
118
- const result = await services.store.create({
119
- name: storeName,
120
- type: 'file',
121
- path: args.path,
122
- });
128
+ console.log(`Adding folder: ${args.path}...`);
123
129
 
124
- if (!result.success) {
125
- console.error(`Error: ${result.error.message}`);
126
- process.exit(1);
127
- }
130
+ const result = await services.store.create({
131
+ name: storeName,
132
+ type: 'file',
133
+ path: args.path,
134
+ });
128
135
 
129
- console.log(`Created store: ${storeName} (${result.data.id})`);
130
- if ('path' in result.data) {
131
- console.log(`Location: ${result.data.path}`);
132
- }
136
+ if (!result.success) {
137
+ console.error(`Error: ${result.error.message}`);
138
+ process.exit(1);
139
+ }
140
+
141
+ console.log(`Created store: ${storeName} (${result.data.id})`);
142
+ if ('path' in result.data) {
143
+ console.log(`Location: ${result.data.path}`);
144
+ }
133
145
 
134
- // Auto-index
135
- console.log('\nIndexing...');
136
- const indexResult = await services.index.indexStore(result.data);
146
+ // Auto-index
147
+ console.log('\nIndexing...');
148
+ const indexResult = await services.index.indexStore(result.data);
137
149
 
138
- if (indexResult.success) {
139
- console.log(`Indexed ${String(indexResult.data.documentsIndexed)} files`);
140
- } else {
141
- console.error(`Indexing failed: ${indexResult.error.message}`);
150
+ if (indexResult.success) {
151
+ console.log(`Indexed ${String(indexResult.data.documentsIndexed)} files`);
152
+ } else {
153
+ console.error(`Indexing failed: ${indexResult.error.message}`);
154
+ }
155
+ } finally {
156
+ await destroyServices(services);
142
157
  }
143
158
  }
144
159
 
145
160
  export async function handleIndex(args: { store: string }): Promise<void> {
146
161
  // PWD is set by Claude Code to user's project directory
147
162
  const services = await createServices(undefined, undefined, process.env['PWD']);
148
- const store = await services.store.getByIdOrName(args.store);
149
163
 
150
- if (store === undefined) {
151
- console.error(`Store not found: ${args.store}`);
152
- process.exit(1);
153
- }
164
+ try {
165
+ const store = await services.store.getByIdOrName(args.store);
154
166
 
155
- console.log(`Indexing ${store.name}...`);
156
- const result = await services.index.indexStore(store);
167
+ if (store === undefined) {
168
+ console.error(`Store not found: ${args.store}`);
169
+ process.exit(1);
170
+ }
157
171
 
158
- if (result.success) {
159
- console.log(
160
- `Indexed ${String(result.data.documentsIndexed)} documents in ${String(result.data.timeMs)}ms`
161
- );
162
- } else {
163
- console.error(`Error: ${result.error.message}`);
164
- process.exit(1);
172
+ console.log(`Indexing ${store.name}...`);
173
+ const result = await services.index.indexStore(store);
174
+
175
+ if (result.success) {
176
+ console.log(
177
+ `Indexed ${String(result.data.documentsIndexed)} documents in ${String(result.data.timeMs)}ms`
178
+ );
179
+ } else {
180
+ console.error(`Error: ${result.error.message}`);
181
+ process.exit(1);
182
+ }
183
+ } finally {
184
+ await destroyServices(services);
165
185
  }
166
186
  }
167
187
 
@@ -171,34 +191,39 @@ export async function handleStores(options: CommandOptions = {}): Promise<void>
171
191
  options.dataDir,
172
192
  options.projectRoot ?? process.env['PWD']
173
193
  );
174
- const stores = await services.store.list();
175
-
176
- if (stores.length === 0) {
177
- console.log('No stores found.');
178
- console.log('\nCreate a store with:');
179
- console.log(' /bluera-knowledge:add-repo <url> --name=<name>');
180
- console.log(' /bluera-knowledge:add-folder <path> --name=<name>');
181
- return;
182
- }
183
194
 
184
- // Table header
185
- console.log('| Name | Type | ID | Source |');
186
- console.log('|------|------|----|--------------------|');
187
-
188
- // Table rows
189
- for (const store of stores) {
190
- const name = store.name;
191
- const type = store.type;
192
- const id = store.id;
193
- let source = '';
194
-
195
- if ('url' in store && store.url !== undefined) {
196
- source = store.url;
197
- } else if ('path' in store) {
198
- source = store.path;
195
+ try {
196
+ const stores = await services.store.list();
197
+
198
+ if (stores.length === 0) {
199
+ console.log('No stores found.');
200
+ console.log('\nCreate a store with:');
201
+ console.log(' /bluera-knowledge:add-repo <url> --name=<name>');
202
+ console.log(' /bluera-knowledge:add-folder <path> --name=<name>');
203
+ return;
199
204
  }
200
205
 
201
- console.log(`| ${name} | ${type} | ${id.substring(0, 8)}... | ${source} |`);
206
+ // Table header
207
+ console.log('| Name | Type | ID | Source |');
208
+ console.log('|------|------|----|--------------------|');
209
+
210
+ // Table rows
211
+ for (const store of stores) {
212
+ const name = store.name;
213
+ const type = store.type;
214
+ const id = store.id;
215
+ let source = '';
216
+
217
+ if ('url' in store && store.url !== undefined) {
218
+ source = store.url;
219
+ } else if ('path' in store) {
220
+ source = store.path;
221
+ }
222
+
223
+ console.log(`| ${name} | ${type} | ${id.substring(0, 8)}... | ${source} |`);
224
+ }
225
+ } finally {
226
+ await destroyServices(services);
202
227
  }
203
228
  }
204
229
 
@@ -209,73 +234,78 @@ export async function handleSuggest(options: CommandOptions = {}): Promise<void>
209
234
 
210
235
  // Create analyzer instance
211
236
  const services = await createServices(options.config, options.dataDir, projectRoot);
212
- const analyzer = new DependencyUsageAnalyzer();
213
- const resolver = new RepoUrlResolver();
214
-
215
- // Analyze with progress indicator
216
- const spinner = ora('Scanning source files...').start();
217
237
 
218
- const result = await analyzer.analyze(projectRoot, (current, total, message) => {
219
- spinner.text = `${message} (${String(current)}/${String(total)})`;
220
- });
238
+ try {
239
+ const analyzer = new DependencyUsageAnalyzer();
240
+ const resolver = new RepoUrlResolver();
221
241
 
222
- spinner.stop();
242
+ // Analyze with progress indicator
243
+ const spinner = ora('Scanning source files...').start();
223
244
 
224
- if (!result.success) {
225
- console.error(`Error: ${result.error.message}`);
226
- process.exit(1);
227
- }
228
-
229
- const { usages, totalFilesScanned, skippedFiles } = result.data;
245
+ const result = await analyzer.analyze(projectRoot, (current, total, message) => {
246
+ spinner.text = `${message} (${String(current)}/${String(total)})`;
247
+ });
230
248
 
231
- console.log(
232
- `✔ Scanned ${String(totalFilesScanned)} files${skippedFiles > 0 ? ` (skipped ${String(skippedFiles)})` : ''}\n`
233
- );
249
+ spinner.stop();
234
250
 
235
- if (usages.length === 0) {
236
- console.log('No external dependencies found in this project.');
237
- console.log('\nMake sure you have a package.json or requirements.txt file.');
238
- return;
239
- }
251
+ if (!result.success) {
252
+ console.error(`Error: ${result.error.message}`);
253
+ process.exit(1);
254
+ }
240
255
 
241
- // Filter out packages already in stores
242
- const existingStores = await services.store.list();
243
- const existingRepoNames = new Set(existingStores.map((s) => s.name));
256
+ const { usages, totalFilesScanned, skippedFiles } = result.data;
244
257
 
245
- const newUsages = usages.filter((u) => !existingRepoNames.has(u.packageName));
258
+ console.log(
259
+ `✔ Scanned ${String(totalFilesScanned)} files${skippedFiles > 0 ? ` (skipped ${String(skippedFiles)})` : ''}\n`
260
+ );
246
261
 
247
- if (newUsages.length === 0) {
248
- console.log(' All dependencies are already in knowledge stores!');
249
- return;
250
- }
262
+ if (usages.length === 0) {
263
+ console.log('No external dependencies found in this project.');
264
+ console.log('\nMake sure you have a package.json or requirements.txt file.');
265
+ return;
266
+ }
251
267
 
252
- // Show top 5 suggestions
253
- const topSuggestions = newUsages.slice(0, 5);
268
+ // Filter out packages already in stores
269
+ const existingStores = await services.store.list();
270
+ const existingRepoNames = new Set(existingStores.map((s) => s.name));
254
271
 
255
- console.log('Top dependencies by usage in this project:\n');
256
- topSuggestions.forEach((usage, i) => {
257
- console.log(`${String(i + 1)}. ${usage.packageName}`);
258
- console.log(
259
- ` ${String(usage.importCount)} imports across ${String(usage.fileCount)} files\n`
260
- );
261
- });
272
+ const newUsages = usages.filter((u) => !existingRepoNames.has(u.packageName));
262
273
 
263
- console.log('Searching for repository URLs...\n');
274
+ if (newUsages.length === 0) {
275
+ console.log('✔ All dependencies are already in knowledge stores!');
276
+ return;
277
+ }
264
278
 
265
- // For each package, find repo URL
266
- for (const usage of topSuggestions) {
267
- const repoResult = await resolver.findRepoUrl(usage.packageName, usage.language);
279
+ // Show top 5 suggestions
280
+ const topSuggestions = newUsages.slice(0, 5);
268
281
 
269
- if (repoResult.url !== null) {
270
- console.log(`✔ ${usage.packageName}: ${repoResult.url}`);
271
- console.log(` /bluera-knowledge:add-repo ${repoResult.url} --name=${usage.packageName}\n`);
272
- } else {
273
- console.log(`✗ ${usage.packageName}: Could not find repository URL`);
282
+ console.log('Top dependencies by usage in this project:\n');
283
+ topSuggestions.forEach((usage, i) => {
284
+ console.log(`${String(i + 1)}. ${usage.packageName}`);
274
285
  console.log(
275
- ` You can manually add it: /bluera-knowledge:add-repo <url> --name=${usage.packageName}\n`
286
+ ` ${String(usage.importCount)} imports across ${String(usage.fileCount)} files\n`
276
287
  );
288
+ });
289
+
290
+ console.log('Searching for repository URLs...\n');
291
+
292
+ // For each package, find repo URL
293
+ for (const usage of topSuggestions) {
294
+ const repoResult = await resolver.findRepoUrl(usage.packageName, usage.language);
295
+
296
+ if (repoResult.url !== null) {
297
+ console.log(`✔ ${usage.packageName}: ${repoResult.url}`);
298
+ console.log(` /bluera-knowledge:add-repo ${repoResult.url} --name=${usage.packageName}\n`);
299
+ } else {
300
+ console.log(`✗ ${usage.packageName}: Could not find repository URL`);
301
+ console.log(
302
+ ` You can manually add it: /bluera-knowledge:add-repo <url> --name=${usage.packageName}\n`
303
+ );
304
+ }
277
305
  }
278
- }
279
306
 
280
- console.log('Use the commands above to add repositories to your knowledge stores.');
307
+ console.log('Use the commands above to add repositories to your knowledge stores.');
308
+ } finally {
309
+ await destroyServices(services);
310
+ }
281
311
  }