codecritique 2.0.0 → 2.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codecritique",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "AI-powered code review tool for any programming language",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -14,6 +14,7 @@ import * as llm from './llm.js';
14
14
  import { FILE_SELECTION_SYSTEM_PROMPT, PROJECT_SUMMARY_SYSTEM_PROMPT } from './prompt-cache.js';
15
15
  import { isDocumentationFile, isTestFile } from './utils/file-validation.js';
16
16
  import { verboseLog } from './utils/logging.js';
17
+ import { escapeSqlString } from './utils/string-utils.js';
17
18
 
18
19
  // Consolidated file classification configuration
19
20
  const FILE_PATTERNS = {
@@ -377,6 +378,7 @@ export class ProjectAnalyzer {
377
378
 
378
379
  try {
379
380
  verboseLog({}, chalk.gray(` 📊 Using LanceDB hybrid search for project: ${projectPath}`));
381
+ const projectPathFilter = `project_path = '${escapeSqlString(projectPath)}'`;
380
382
 
381
383
  // Unified query function
382
384
  const queryFiles = async (config) => {
@@ -384,15 +386,11 @@ export class ProjectAnalyzer {
384
386
  let query = table.query().select(['path', 'name', 'content', 'type', 'language']);
385
387
 
386
388
  if (config.whereClause) {
387
- query = query.where(`project_path = '${projectPath}' AND (${config.whereClause})`);
389
+ query = query.where(`${projectPathFilter} AND (${config.whereClause})`);
388
390
  }
389
391
  else if (config.terms) {
390
392
  // For term-based searches, query ALL files and sort by depth to prioritize shallow config files
391
- const allFiles = await table
392
- .query()
393
- .select(['path', 'name', 'content', 'type', 'language'])
394
- .where(`project_path = '${projectPath}'`)
395
- .toArray(); // NO LIMIT - get all files
393
+ const allFiles = await table.query().select(['path', 'name', 'content', 'type', 'language']).where(projectPathFilter).toArray(); // NO LIMIT - get all files
396
394
 
397
395
  // Sort by path depth (shorter paths first) to prioritize config files
398
396
  allFiles.sort((a, b) => {
@@ -416,7 +414,7 @@ export class ProjectAnalyzer {
416
414
  });
417
415
  }
418
416
  else {
419
- query = query.where(`project_path = '${projectPath}'`);
417
+ query = query.where(projectPathFilter);
420
418
  }
421
419
 
422
420
  return await query.limit(config.limit || 30).toArray();
@@ -655,7 +653,7 @@ Select files following the criteria in the system instructions.`;
655
653
  const records = await table
656
654
  .query()
657
655
  .select(['type', 'path', 'content_hash', 'project_path'])
658
- .where(`project_path = '${projectPath.replace(/'/g, "''")}'`)
656
+ .where(`project_path = '${escapeSqlString(projectPath)}'`)
659
657
  .toArray();
660
658
 
661
659
  const hash = crypto.createHash('sha256');
@@ -402,6 +402,14 @@ describe('ProjectAnalyzer', () => {
402
402
  expect(mockTable.query).toHaveBeenCalled();
403
403
  });
404
404
 
405
+ it('should escape project paths in key file queries', async () => {
406
+ const queryChain = mockTable.query();
407
+
408
+ await analyzer.mineKeyFilesFromEmbeddings("/mock/we're/project");
409
+
410
+ expect(queryChain.where).toHaveBeenCalledWith(expect.stringContaining("/mock/we''re/project"));
411
+ });
412
+
405
413
  it('should handle table optimization errors gracefully', async () => {
406
414
  mockTable.optimize.mockRejectedValue(new Error('legacy format'));
407
415
  mockTable.query().toArray.mockResolvedValue([]);