tpmjs/packages/cli/src/commands/collection/import.ts
Ajax Davis 48c41e8733 feat: add use cases marketing product with AI-generated content
Transform qualifying scenarios into marketing-ready use cases with:
- AI-generated titles, descriptions, ROI estimates, business value
- Persona/industry/category taxonomy for targeting
- Browseable feed with filtering and ranking
- SEO-optimized case study pages
- Daily cron job for generation and ranking

Database:
- Add Persona, Industry, Category lookup tables
- Add UseCase model with marketing content fields
- Add junction tables for personas/industries/categories
- Add SocialProof model for cached metrics

API:
- GET /api/use-cases - Global directory with filtering
- GET /api/use-cases/[id] - Individual use case details
- GET /api/public/users/[username]/collections/[slug]/use-cases
- POST /api/cron/use-cases - Nightly generation job

Frontend:
- /use-cases - Global feed with persona dropdown
- /use-cases/[slug] - SEO case study page
- /[username]/collections/[slug]/use-cases - Collection feed
- UseCasesFeed component - Sortable table component
- UseCaseCaseStudy component - Full case study layout
2026-01-20 16:17:35 +10:00

124 lines
3.2 KiB
TypeScript

import * as fs from 'node:fs';
import { Args, Command, Flags } from '@oclif/core';
import { getClient } from '../../lib/api-client.js';
import { createOutput } from '../../lib/output.js';
export default class CollectionImport extends Command {
static description = 'Import tools to a collection from a file';
static examples = [
'<%= config.bin %> <%= command.id %> my-collection --file tools.txt',
'<%= config.bin %> <%= command.id %> my-collection --file tools.json',
];
static flags = {
file: Flags.string({
char: 'f',
description: 'File containing tool IDs (one per line or JSON array)',
required: true,
}),
json: Flags.boolean({
description: 'Output in JSON format',
default: false,
}),
verbose: Flags.boolean({
char: 'v',
description: 'Show verbose output',
default: false,
}),
};
static args = {
collection: Args.string({
description: 'Collection ID or slug',
required: true,
}),
};
async run(): Promise<void> {
const { args, flags } = await this.parse(CollectionImport);
const output = createOutput(flags);
const client = getClient();
if (!client.isAuthenticated()) {
output.error('Not authenticated. Run `tpm auth login` first.');
return;
}
// Read tool IDs from file
if (!fs.existsSync(flags.file)) {
output.error(`File not found: ${flags.file}`);
return;
}
const content = fs.readFileSync(flags.file, 'utf-8').trim();
let toolIds: string[];
// Try to parse as JSON first
try {
const parsed = JSON.parse(content);
if (Array.isArray(parsed)) {
toolIds = parsed.map(String);
} else {
output.error('JSON file must contain an array of tool IDs');
return;
}
} catch {
// Parse as line-separated text
toolIds = content
.split('\n')
.map((line) => line.trim())
.filter((line) => line && !line.startsWith('#'));
}
if (toolIds.length === 0) {
output.error('No tool IDs found in file');
return;
}
output.info(`Found ${toolIds.length} tool(s) in file`);
const spinner = output.spinner(`Adding ${toolIds.length} tool(s)...`);
try {
let added = 0;
let failed = 0;
const errors: string[] = [];
for (const toolId of toolIds) {
try {
await client.addToolsToCollection(args.collection, [toolId]);
added++;
} catch (error) {
failed++;
errors.push(`${toolId}: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
spinner.stop();
if (flags.json) {
output.json({ success: true, added, failed, errors });
return;
}
if (added > 0) {
output.success(`Added ${added} tool(s) to collection`);
}
if (failed > 0) {
output.warning(`Failed to add ${failed} tool(s)`);
if (flags.verbose) {
for (const err of errors) {
output.listItem(err);
}
}
}
} catch (error) {
spinner.fail('Import failed');
output.error(
error instanceof Error ? error.message : 'Unknown error',
flags.verbose ? String(error) : undefined
);
}
}
}