88 lines
3.2 KiB
JavaScript
88 lines
3.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Competitor Research — Save & Query Findings
|
|
*
|
|
* The actual research is done by the agent using the browser.
|
|
* This script manages the competitor-research.json file.
|
|
*
|
|
* Usage:
|
|
* node competitor-research.js --dir tiktok-marketing/ --summary
|
|
* node competitor-research.js --dir tiktok-marketing/ --add-competitor '{"name":"AppX","tiktokHandle":"@appx",...}'
|
|
* node competitor-research.js --dir tiktok-marketing/ --gaps
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const args = process.argv.slice(2);
|
|
const dir = args.includes('--dir') ? args[args.indexOf('--dir') + 1] : 'tiktok-marketing';
|
|
const filePath = path.join(dir, 'competitor-research.json');
|
|
|
|
function loadData() {
|
|
if (!fs.existsSync(filePath)) {
|
|
return {
|
|
researchDate: '',
|
|
competitors: [],
|
|
nicheInsights: { trendingSounds: [], commonFormats: [], gapOpportunities: '', avoidPatterns: '' }
|
|
};
|
|
}
|
|
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
}
|
|
|
|
function saveData(data) {
|
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
}
|
|
|
|
if (args.includes('--summary')) {
|
|
const data = loadData();
|
|
if (data.competitors.length === 0) {
|
|
console.log('No competitor research yet. Use the browser to research competitors first.');
|
|
process.exit(0);
|
|
}
|
|
console.log(`📊 Competitor Research (${data.researchDate})\n`);
|
|
console.log(`Found ${data.competitors.length} competitors:\n`);
|
|
data.competitors.forEach(c => {
|
|
console.log(` ${c.name} (${c.tiktokHandle || 'no handle'})`);
|
|
console.log(` Followers: ${c.followers || '?'} | Avg views: ${c.avgViews || '?'}`);
|
|
if (c.bestVideo) console.log(` Best: ${c.bestVideo.views} views — "${c.bestVideo.hook}"`);
|
|
if (c.strengths) console.log(` Strengths: ${c.strengths}`);
|
|
if (c.weaknesses) console.log(` Weaknesses: ${c.weaknesses}`);
|
|
console.log('');
|
|
});
|
|
if (data.nicheInsights?.gapOpportunities) {
|
|
console.log(`💡 Gap opportunities: ${data.nicheInsights.gapOpportunities}`);
|
|
}
|
|
if (data.nicheInsights?.avoidPatterns) {
|
|
console.log(`⚠️ Avoid: ${data.nicheInsights.avoidPatterns}`);
|
|
}
|
|
}
|
|
|
|
if (args.includes('--add-competitor')) {
|
|
const idx = args.indexOf('--add-competitor');
|
|
const json = args[idx + 1];
|
|
try {
|
|
const competitor = JSON.parse(json);
|
|
const data = loadData();
|
|
data.competitors.push(competitor);
|
|
data.researchDate = new Date().toISOString().split('T')[0];
|
|
saveData(data);
|
|
console.log(`✅ Added competitor: ${competitor.name}`);
|
|
} catch (e) {
|
|
console.error('Invalid JSON for competitor:', e.message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (args.includes('--gaps')) {
|
|
const data = loadData();
|
|
if (!data.nicheInsights) {
|
|
console.log('No niche insights yet.');
|
|
process.exit(0);
|
|
}
|
|
console.log('Gap Analysis:\n');
|
|
console.log(` Opportunities: ${data.nicheInsights.gapOpportunities || 'None recorded'}`);
|
|
console.log(` Avoid: ${data.nicheInsights.avoidPatterns || 'None recorded'}`);
|
|
console.log(` Common formats: ${(data.nicheInsights.commonFormats || []).join(', ') || 'None recorded'}`);
|
|
console.log(` Trending sounds: ${(data.nicheInsights.trendingSounds || []).join(', ') || 'None recorded'}`);
|
|
}
|