Skip to content

Commit d721f43

Browse files
Enhance batch importer with fuzzy duplicate detection and flexible parsing
- Add support for input variations: "convert jpg to png", "jpg 2 png", "jpg → png" - Implement format aliases detection (jpg/jpeg, tiff/tif, mpeg/mpg, mov/qt) - Add semantic matching for tool names and IDs - Enhance parsing with prefix/suffix cleaning and multiple separator support - Add CLI test mode with --test-parsing flag - Improve reporting with match type grouping and detailed explanations Co-authored-by: devinschumacher <45643901+devinschumacher@users.noreply.github.com>
1 parent 939071f commit d721f43

3 files changed

Lines changed: 344 additions & 99 deletions

File tree

packages/app-core/src/cli.ts

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -341,18 +341,38 @@ program
341341
.option('--skip-existing', 'Skip tools that already exist')
342342
.option('--generate-content', 'Generate basic content for new tools')
343343
.option('--report <file>', 'Save report to file')
344+
.option('--test-parsing', 'Test parsing capabilities with sample inputs')
344345
.action(async (options) => {
345346
try {
346347
console.log(chalk.blue('📥 Batch Tool Import'));
347348

349+
const registryManager = createRegistryManager(DEFAULT_REGISTRY_PATH);
350+
const importer = createBatchToolImporter(registryManager);
351+
352+
// Test parsing capabilities
353+
if (options.testParsing) {
354+
console.log(chalk.cyan('\n🧪 Testing Parsing Capabilities:'));
355+
const testResults = importer.testParsingCapabilities();
356+
357+
console.log(chalk.green('\n✅ Successful Parses:'));
358+
testResults.filter(r => r.success).forEach(({ input, parsed }) => {
359+
console.log(` "${input}" → ${parsed.from} to ${parsed.to}`);
360+
});
361+
362+
console.log(chalk.red('\n❌ Failed Parses:'));
363+
testResults.filter(r => !r.success).forEach(({ input }) => {
364+
console.log(` "${input}" → (not parsed)`);
365+
});
366+
367+
console.log(chalk.blue(`\n📊 Summary: ${testResults.filter(r => r.success).length}/${testResults.length} successful`));
368+
return;
369+
}
370+
348371
if (!options.file && !options.input) {
349-
console.error(chalk.red('❌ Please provide either --file or --input'));
372+
console.error(chalk.red('❌ Please provide either --file or --input, or use --test-parsing'));
350373
process.exit(1);
351374
}
352375

353-
const registryManager = createRegistryManager(DEFAULT_REGISTRY_PATH);
354-
const importer = createBatchToolImporter(registryManager);
355-
356376
let input: string;
357377
if (options.file) {
358378
console.log(chalk.gray(`Reading from file: ${options.file}`));
@@ -363,12 +383,12 @@ program
363383
}
364384

365385
// Parse input
366-
console.log(chalk.gray('Parsing import requests...'));
386+
console.log(chalk.gray('Parsing import requests with enhanced fuzzy matching...'));
367387
const requests = importer.parseImportList(input);
368388
console.log(chalk.cyan(`Found ${requests.length} conversion requests`));
369389

370-
// Analyze requests
371-
console.log(chalk.gray('Analyzing against existing tools...'));
390+
// Analyze requests with enhanced duplicate detection
391+
console.log(chalk.gray('Analyzing against existing tools (includes fuzzy matching)...'));
372392
const analysis = await importer.analyzeImportRequests(requests);
373393

374394
console.log(chalk.cyan(`\n📊 Analysis Results:`));
@@ -377,14 +397,29 @@ program
377397
console.log(` New tools: ${analysis.new.length}`);
378398
console.log(` Conflicts: ${analysis.conflicts.length}`);
379399

380-
// Show existing tools
400+
// Show existing tools with match types
381401
if (analysis.existing.length > 0) {
382-
console.log(chalk.yellow(`\n⚠️ Existing Tools (${analysis.existing.length}):`));
383-
analysis.existing.slice(0, 5).forEach(({ request, existingTool, match }) => {
384-
console.log(` ${match === 'exact' ? '🎯' : '🔍'} ${request.from}${request.to} (${match} match: ${existingTool.name})`);
385-
});
386-
if (analysis.existing.length > 5) {
387-
console.log(` ... and ${analysis.existing.length - 5} more`);
402+
const exactMatches = analysis.existing.filter(e => e.match === 'exact');
403+
const similarMatches = analysis.existing.filter(e => e.match === 'similar');
404+
405+
if (exactMatches.length > 0) {
406+
console.log(chalk.green(`\n🎯 Exact Matches (${exactMatches.length}):`));
407+
exactMatches.slice(0, 3).forEach(({ request, existingTool }) => {
408+
console.log(` ${request.from}${request.to} (matches: ${existingTool.name})`);
409+
});
410+
if (exactMatches.length > 3) {
411+
console.log(` ... and ${exactMatches.length - 3} more exact matches`);
412+
}
413+
}
414+
415+
if (similarMatches.length > 0) {
416+
console.log(chalk.yellow(`\n🔍 Fuzzy/Similar Matches (${similarMatches.length}):`));
417+
similarMatches.slice(0, 3).forEach(({ request, existingTool }) => {
418+
console.log(` ${request.from}${request.to} (similar to: ${existingTool.name})`);
419+
});
420+
if (similarMatches.length > 3) {
421+
console.log(` ... and ${similarMatches.length - 3} more similar matches`);
422+
}
388423
}
389424
}
390425

@@ -429,7 +464,7 @@ program
429464
const fs = await import('fs/promises');
430465
await fs.writeFile(options.report, report);
431466
console.log(chalk.green(`\n📝 Report saved to: ${options.report}`));
432-
} else {
467+
} else if (!options.testParsing) {
433468
console.log('\n' + report);
434469
}
435470

0 commit comments

Comments
 (0)