agency-skills-suite/agency-archivist/scripts/generate_catalog.js
AgentePotente 0b4c56d744 Script agency-archivist: compatibilità universale e {project}/
- extract_archive.js: --client → --project, rimossa dipendenza da .openclaw
- scan_resources.js: --client → --project, basePath configurabile
- generate_catalog.js: --client → --project, basePath configurabile
- Environment variable: AGENCY_PROJECTS_BASE per specificare base directory
- Default: current working directory (compatibile con qualsiasi sistema)
- Percorsi aggiornati: clients/{client}/ → {project}/
- Documentazione script aggiornata (usage, options, examples)

Vantaggi:
 Compatibile con OpenClaw e altri sistemi
 Non richiede struttura .openclaw/workspace
 Configurabile via ENV o --base-path
 Funziona in qualsiasi directory di progetto
2026-03-11 00:48:40 +01:00

300 lines
8.7 KiB
JavaScript
Executable file

#!/usr/bin/env node
/**
* generate_catalog.js — Genera catalogo markdown dai metadata
*
* Usage:
* node generate_catalog.js --project <project_name>
* node generate_catalog.js --project demo_co_srl
*
* Options:
* --input Path metadata JSON
* --output Path output catalog.md
* --verbose Log dettagliato
*/
const fs = require('fs');
const path = require('path');
const os = require('os');
function formatSize(bytes) {
const units = ['B', 'KB', 'MB', 'GB'];
let size = bytes;
for (const unit of units) {
if (size < 1024) return `${size.toFixed(1)} ${unit}`;
size /= 1024;
}
return `${size.toFixed(1)} TB`;
}
function loadMetadata(inputPath) {
const content = fs.readFileSync(inputPath, 'utf8');
return JSON.parse(content);
}
function groupByType(resources) {
const grouped = {
images: [],
videos: [],
documents: [],
other: []
};
for (const res of resources) {
const mime = res.mime_type || '';
const ext = res.extension || '';
if (mime.startsWith('image/')) {
grouped.images.push(res);
} else if (mime.startsWith('video/')) {
grouped.videos.push(res);
} else if (['pdf', 'doc', 'docx', 'txt', 'md', 'ppt', 'pptx', 'xls', 'xlsx'].includes(ext)) {
grouped.documents.push(res);
} else {
grouped.other.push(res);
}
}
return grouped;
}
function generateSummary(grouped) {
const rows = [];
for (const [type, label] of [['images', 'Immagini'], ['videos', 'Video'], ['documents', 'Documenti']]) {
const resources = grouped[type] || [];
const count = resources.length;
const totalSize = resources.reduce((sum, r) => sum + (r.size_bytes || 0), 0);
rows.push(`| ${label} | ${count} | ${formatSize(totalSize)} |`);
}
return rows.join('\n');
}
function generateImagesTable(resources) {
if (resources.length === 0) return '_Nessuna immagine trovata_';
const rows = [];
const header = '| File | Tipo | Dimensioni | Risoluzione | Descrizione | Tag | Use Case |';
const separator = '|------|------|------------|-------------|-------------|-----|----------|';
const sorted = [...resources].sort((a, b) => a.filename.localeCompare(b.filename));
for (const res of sorted) {
const filename = res.filename || 'Unknown';
const ext = (res.extension || '?').toUpperCase();
const size = res.size_formatted || '?';
const resolution = res.resolution || '-';
const description = res.description || filename;
const tags = (res.tags || []).slice(0, 5).map(t => `#${t}`).join(', ');
const useCases = (res.use_cases || []).slice(0, 2).join(', ');
rows.push(`| \`${filename}\` | ${ext} | ${size} | ${resolution} | ${description} | ${tags} | ${useCases} |`);
}
return [header, separator, ...rows].join('\n');
}
function generateVideosTable(resources) {
if (resources.length === 0) return '_Nessun video trovato_';
const rows = [];
const header = '| File | Tipo | Dimensioni | Durata | Risoluzione | Descrizione | Tag | Use Case |';
const separator = '|------|------|------------|--------|-------------|-------------|-----|----------|';
const sorted = [...resources].sort((a, b) => a.filename.localeCompare(b.filename));
for (const res of sorted) {
const filename = res.filename || 'Unknown';
const ext = (res.extension || '?').toUpperCase();
const size = res.size_formatted || '?';
const resolution = res.resolution || '-';
const duration = res.duration ? `${Math.floor(res.duration / 60)}:${(res.duration % 60).toFixed(0).padStart(2, '0')}` : '-';
const description = res.description || filename;
const tags = (res.tags || []).slice(0, 5).map(t => `#${t}`).join(', ');
const useCases = (res.use_cases || []).slice(0, 2).join(', ');
rows.push(`| \`{filename}\` | ${ext} | ${size} | ${duration} | ${resolution} | ${description} | ${tags} | ${useCases} |`);
}
return [header, separator, ...rows].join('\n');
}
function generateDocumentsTable(resources) {
if (resources.length === 0) return '_Nessun documento trovato_';
const rows = [];
const header = '| File | Tipo | Dimensioni | Descrizione | Tag | Use Case |';
const separator = '|------|------|------------|-------------|-----|----------|';
const sorted = [...resources].sort((a, b) => a.filename.localeCompare(b.filename));
for (const res of sorted) {
const filename = res.filename || 'Unknown';
const ext = (res.extension || '?').toUpperCase();
const size = res.size_formatted || '?';
const description = res.description || filename;
const tags = (res.tags || []).slice(0, 5).map(t => `#${t}`).join(', ');
const useCases = (res.use_cases || []).slice(0, 2).join(', ');
rows.push(`| \`${filename}\` | ${ext} | ${size} | ${description} | ${tags} | ${useCases} |`);
}
return [header, separator, ...rows].join('\n');
}
function generateGlobalTags(resources) {
const allTags = new Set();
for (const res of resources) {
for (const tag of (res.tags || [])) {
allTags.add(tag);
}
}
if (allTags.size === 0) return '_Nessun tag generato_';
const sortedTags = [...allTags].sort().slice(0, 20);
return sortedTags.map(t => `#${t}`).join(' ');
}
function generateCatalog(projectName, metadata, outputPath, verbose = false) {
const resources = metadata.resources || [];
const generated = (metadata.generated || new Date().toISOString()).split('T')[0];
const grouped = groupByType(resources);
const projectNameFormatted = projectName ? projectName.replace(/_/g, ' ').split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ') : 'Progetto';
const catalog = `# Asset Catalog — ${projectNameFormatted}
_Generato: ${generated} | Totale: ${resources.length} risorse_
## Riepilogo
| Tipo | Count | Dimensione Totale |
|------|-------|-------------------|
${generateSummary(grouped)}
---
## Immagini (${grouped.images.length})
${generateImagesTable(grouped.images)}
---
## Video (${grouped.videos.length})
${generateVideosTable(grouped.videos)}
---
## Documenti (${grouped.documents.length})
${generateDocumentsTable(grouped.documents)}
---
## Tag Globali
${generateGlobalTags(resources)}
---
## Note
- **Ultimo aggiornamento:** ${generated}
- **Archivi originali:** \`assets/archive/\`
- **Per richiedere risorse:** Contatta @agency-archivist
- **Metadata completi:** \`assets/.metadata.json\`
`;
fs.writeFileSync(outputPath, catalog, 'utf8');
if (verbose) {
console.log(`✅ Catalogo generato: ${outputPath}`);
}
return outputPath;
}
function main() {
const args = process.argv.slice(2);
let project = null;
let inputPath = null;
let outputPath = null;
let verbose = false;
let basePath = process.env.AGENCY_PROJECTS_BASE || process.cwd();
for (let i = 0; i < args.length; i++) {
if (args[i] === '--project' && args[i + 1]) {
project = args[++i];
} else if (args[i] === '--input' && args[i + 1]) {
inputPath = args[++i];
} else if (args[i] === '--output' && args[i + 1]) {
outputPath = args[++i];
} else if (args[i] === '--base-path' && args[i + 1]) {
basePath = args[++i];
} else if (args[i] === '--verbose') {
verbose = true;
}
}
if (!project) {
console.error('Usage: node generate_catalog.js --project <project_name>');
console.error('Options: --base-path <dir>, --input, --output, --verbose');
console.error('Environment: AGENCY_PROJECTS_BASE (opzionale)');
process.exit(1);
}
// Path
const projectDir = path.join(basePath, project);
const assetsDir = path.join(projectDir, 'assets');
if (!fs.existsSync(projectDir)) {
console.error(`❌ Cartella progetto non trovata: ${projectDir}`);
process.exit(1);
}
if (!fs.existsSync(assetsDir)) {
console.error(`❌ Cartella assets non trovata: ${assetsDir}`);
process.exit(1);
}
// Input/Output path
if (!inputPath) {
inputPath = path.join(assetsDir, '.metadata.json');
}
if (!outputPath) {
outputPath = path.join(assetsDir, 'catalog.md');
}
if (!fs.existsSync(inputPath)) {
console.error(`❌ Metadata non trovati: ${inputPath}`);
console.error(' Esegui prima: node scripts/scan_resources.js');
process.exit(1);
}
if (verbose) {
console.log(`📥 Input: ${inputPath}`);
console.log(`📝 Output: ${outputPath}`);
console.log();
}
// Carica metadata
const metadata = loadMetadata(inputPath);
// Genera catalogo
generateCatalog(project, metadata, outputPath, verbose);
// Riepilogo
const resources = metadata.resources || [];
console.log(`\n✅ Catalogo generato!`);
console.log(` 📊 Risorse catalogate: ${resources.length}`);
console.log(` 📁 Catalogo: ${outputPath}`);
console.log(`\n👉 Il catalogo è pronto per essere usato dalle altre skill!`);
}
main();