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
This commit is contained in:
AgentePotente 2026-03-11 00:48:40 +01:00
parent f0605645d3
commit 0b4c56d744
3 changed files with 68 additions and 55 deletions

View file

@ -3,20 +3,23 @@
* extract_archive.js Estrae archivi (zip, tar, rar) e organizza risorse * extract_archive.js Estrae archivi (zip, tar, rar) e organizza risorse
* *
* Usage: * Usage:
* node extract_archive.js <path_or_url> --client <client_name> * node extract_archive.js <path_or_url> --project <project_path>
* node extract_archive.js brand_assets.zip --client demo_co_srl * node extract_archive.js brand_assets.zip --project demo_co_srl
* node extract_archive.js https://example.com/assets.zip --client demo_co_srl * node extract_archive.js https://example.com/assets.zip --project campagna_x
* *
* Options: * Options:
* --base-path Base directory (default: current dir o ENV)
* --keep-archive Mantieni file originale * --keep-archive Mantieni file originale
* --verbose Log dettagliato * --verbose Log dettagliato
* --dry-run Simula senza estrazione * --dry-run Simula senza estrazione
*
* Environment:
* AGENCY_PROJECTS_BASE Base directory per progetti (opzionale)
*/ */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { execSync } = require('child_process'); const { execSync } = require('child_process');
const os = require('os');
// Mapping parole chiave → cartelle // Mapping parole chiave → cartelle
const CATEGORY_KEYWORDS = { const CATEGORY_KEYWORDS = {
@ -73,7 +76,7 @@ function downloadFile(url, destPath, verbose = false) {
try { try {
if (verbose) console.log(`📥 Download: ${url}`); if (verbose) console.log(`📥 Download: ${url}`);
// Usa curl o wget (più affidabili di https module per download grandi) // Usa curl o wget (più affidabili)
execSync(`curl -L -o "${destPath}" "${url}"`, { stdio: verbose ? 'inherit' : 'pipe' }); execSync(`curl -L -o "${destPath}" "${url}"`, { stdio: verbose ? 'inherit' : 'pipe' });
if (verbose) console.log(`✅ Download completato: ${destPath}`); if (verbose) console.log(`✅ Download completato: ${destPath}`);
@ -99,7 +102,6 @@ function extractArchive(archivePath, extractTo, verbose = false) {
stdio: verbose ? 'inherit' : 'pipe' stdio: verbose ? 'inherit' : 'pipe'
}); });
// Lista file estratti
const output = execSync(`unzip -l "${archivePath}" | tail -n +4 | head -n -2`, { encoding: 'utf8' }); const output = execSync(`unzip -l "${archivePath}" | tail -n +4 | head -n -2`, { encoding: 'utf8' });
return output.split('\n').filter(line => line.trim()).map(line => { return output.split('\n').filter(line => line.trim()).map(line => {
const parts = line.trim().split(/\s+/); const parts = line.trim().split(/\s+/);
@ -139,7 +141,7 @@ function extractArchive(archivePath, extractTo, verbose = false) {
} }
} }
function organizeFiles(tempDir, assetsDir, client, verbose = false) { function organizeFiles(tempDir, assetsDir, verbose = false) {
const organized = []; const organized = [];
// Crea struttura cartelle // Crea struttura cartelle
@ -210,7 +212,7 @@ function organizeFiles(tempDir, assetsDir, client, verbose = false) {
return organized; return organized;
} }
function logOperation(client, archiveName, organizedFiles, opsLogPath) { function logOperation(project, archiveName, organizedFiles, opsLogPath) {
const timestamp = new Date().toISOString().slice(0, 16).replace('T', ' '); const timestamp = new Date().toISOString().slice(0, 16).replace('T', ' ');
const images = organizedFiles.filter(f => f.type === 'images'); const images = organizedFiles.filter(f => f.type === 'images');
@ -242,14 +244,17 @@ function main() {
// Parse arguments // Parse arguments
let pathOrUrl = null; let pathOrUrl = null;
let client = null; let project = null;
let basePath = process.env.AGENCY_PROJECTS_BASE || process.cwd();
let keepArchive = false; let keepArchive = false;
let verbose = false; let verbose = false;
let dryRun = false; let dryRun = false;
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
if (args[i] === '--client' && args[i + 1]) { if (args[i] === '--project' && args[i + 1]) {
client = args[++i]; project = args[++i];
} else if (args[i] === '--base-path' && args[i + 1]) {
basePath = args[++i];
} else if (args[i] === '--keep-archive') { } else if (args[i] === '--keep-archive') {
keepArchive = true; keepArchive = true;
} else if (args[i] === '--verbose') { } else if (args[i] === '--verbose') {
@ -261,29 +266,29 @@ function main() {
} }
} }
if (!pathOrUrl || !client) { if (!pathOrUrl || !project) {
console.error('Usage: node extract_archive.js <path_or_url> --client <client_name>'); console.error('Usage: node extract_archive.js <path_or_url> --project <project_name>');
console.error('Options: --keep-archive, --verbose, --dry-run'); console.error('Options: --base-path <dir>, --keep-archive, --verbose, --dry-run');
console.error('Environment: AGENCY_PROJECTS_BASE (opzionale)');
process.exit(1); process.exit(1);
} }
// Path // Path
const workspace = path.join(os.homedir(), '.openclaw', 'workspace', 'agency-skills-suite'); const projectDir = path.join(basePath, project);
const clientDir = path.join(workspace, 'clients', client); const assetsDir = path.join(projectDir, 'assets');
const assetsDir = path.join(clientDir, 'assets');
const archiveDir = path.join(assetsDir, 'archive'); const archiveDir = path.join(assetsDir, 'archive');
const opsLog = path.join(clientDir, 'ops', 'run_log.md'); const opsLog = path.join(projectDir, 'ops', 'run_log.md');
// Verifica cartella cliente // Verifica cartella progetto
if (!fs.existsSync(clientDir)) { if (!fs.existsSync(projectDir)) {
console.error(`❌ Cartella cliente non trovata: ${clientDir}`); console.error(`❌ Cartella progetto non trovata: ${projectDir}`);
console.error(' Crea prima il progetto con agency-orchestrator'); console.error(' Crea prima il progetto con agency-orchestrator');
process.exit(1); process.exit(1);
} }
// Crea cartelle // Crea cartelle
fs.mkdirSync(archiveDir, { recursive: true }); fs.mkdirSync(archiveDir, { recursive: true });
fs.mkdirSync(path.join(clientDir, 'ops'), { recursive: true }); fs.mkdirSync(path.join(projectDir, 'ops'), { recursive: true });
// URL o path locale? // URL o path locale?
const isUrl = pathOrUrl.startsWith('http://') || pathOrUrl.startsWith('https://') || pathOrUrl.startsWith('ftp://'); const isUrl = pathOrUrl.startsWith('http://') || pathOrUrl.startsWith('https://') || pathOrUrl.startsWith('ftp://');
@ -341,13 +346,13 @@ function main() {
// Organizza file // Organizza file
console.log('\n🗂 Organizzazione file...'); console.log('\n🗂 Organizzazione file...');
const organized = organizeFiles(tempDir, assetsDir, client, verbose); const organized = organizeFiles(tempDir, assetsDir, verbose);
// Pulisci temporanea // Pulisci temporanea
fs.rmSync(tempDir, { recursive: true, force: true }); fs.rmSync(tempDir, { recursive: true, force: true });
// Log operazione // Log operazione
logOperation(client, archiveName, organized, opsLog); logOperation(project, archiveName, organized, opsLog);
// Elimina archivio originale (se non --keep-archive) // Elimina archivio originale (se non --keep-archive)
if (!keepArchive) { if (!keepArchive) {
@ -360,7 +365,7 @@ function main() {
console.log(` 📦 File estratti: ${organized.length}`); console.log(` 📦 File estratti: ${organized.length}`);
console.log(` 📁 Cartella: ${assetsDir}`); console.log(` 📁 Cartella: ${assetsDir}`);
console.log(` 📝 Log: ${opsLog}`); console.log(` 📝 Log: ${opsLog}`);
console.log(`\n👉 Prossimo step: node scripts/scan_resources.js --client ${client}`); console.log(`\n👉 Prossimo step: node scripts/scan_resources.js --project ${project}`);
} }
main(); main();

View file

@ -3,8 +3,8 @@
* generate_catalog.js Genera catalogo markdown dai metadata * generate_catalog.js Genera catalogo markdown dai metadata
* *
* Usage: * Usage:
* node generate_catalog.js --client <client_name> * node generate_catalog.js --project <project_name>
* node generate_catalog.js --client demo_co_srl * node generate_catalog.js --project demo_co_srl
* *
* Options: * Options:
* --input Path metadata JSON * --input Path metadata JSON
@ -158,13 +158,15 @@ function generateGlobalTags(resources) {
return sortedTags.map(t => `#${t}`).join(' '); return sortedTags.map(t => `#${t}`).join(' ');
} }
function generateCatalog(clientName, metadata, outputPath, verbose = false) { function generateCatalog(projectName, metadata, outputPath, verbose = false) {
const resources = metadata.resources || []; const resources = metadata.resources || [];
const generated = (metadata.generated || new Date().toISOString()).split('T')[0]; const generated = (metadata.generated || new Date().toISOString()).split('T')[0];
const grouped = groupByType(resources); const grouped = groupByType(resources);
const catalog = `# Asset Catalog — ${clientName.replace(/_/g, ' ').split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')} 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_ _Generato: ${generated} | Totale: ${resources.length} risorse_
@ -220,36 +222,39 @@ ${generateGlobalTags(resources)}
function main() { function main() {
const args = process.argv.slice(2); const args = process.argv.slice(2);
let client = null; let project = null;
let inputPath = null; let inputPath = null;
let outputPath = null; let outputPath = null;
let verbose = false; let verbose = false;
let basePath = process.env.AGENCY_PROJECTS_BASE || process.cwd();
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
if (args[i] === '--client' && args[i + 1]) { if (args[i] === '--project' && args[i + 1]) {
client = args[++i]; project = args[++i];
} else if (args[i] === '--input' && args[i + 1]) { } else if (args[i] === '--input' && args[i + 1]) {
inputPath = args[++i]; inputPath = args[++i];
} else if (args[i] === '--output' && args[i + 1]) { } else if (args[i] === '--output' && args[i + 1]) {
outputPath = args[++i]; outputPath = args[++i];
} else if (args[i] === '--base-path' && args[i + 1]) {
basePath = args[++i];
} else if (args[i] === '--verbose') { } else if (args[i] === '--verbose') {
verbose = true; verbose = true;
} }
} }
if (!client) { if (!project) {
console.error('Usage: node generate_catalog.js --client <client_name>'); console.error('Usage: node generate_catalog.js --project <project_name>');
console.error('Options: --input, --output, --verbose'); console.error('Options: --base-path <dir>, --input, --output, --verbose');
console.error('Environment: AGENCY_PROJECTS_BASE (opzionale)');
process.exit(1); process.exit(1);
} }
// Path // Path
const workspace = path.join(os.homedir(), '.openclaw', 'workspace', 'agency-skills-suite'); const projectDir = path.join(basePath, project);
const clientDir = path.join(workspace, 'clients', client); const assetsDir = path.join(projectDir, 'assets');
const assetsDir = path.join(clientDir, 'assets');
if (!fs.existsSync(clientDir)) { if (!fs.existsSync(projectDir)) {
console.error(`❌ Cartella cliente non trovata: ${clientDir}`); console.error(`❌ Cartella progetto non trovata: ${projectDir}`);
process.exit(1); process.exit(1);
} }
@ -282,7 +287,7 @@ function main() {
const metadata = loadMetadata(inputPath); const metadata = loadMetadata(inputPath);
// Genera catalogo // Genera catalogo
generateCatalog(client, metadata, outputPath, verbose); generateCatalog(project, metadata, outputPath, verbose);
// Riepilogo // Riepilogo
const resources = metadata.resources || []; const resources = metadata.resources || [];

View file

@ -3,8 +3,8 @@
* scan_resources.js Scansiona risorse ed estrae metadata * scan_resources.js Scansiona risorse ed estrae metadata
* *
* Usage: * Usage:
* node scan_resources.js --client <client_name> --pass 1|2 * node scan_resources.js --project <project_name> --pass 1|2
* node scan_resources.js --client demo_co_srl --pass 1 * node scan_resources.js --project demo_co_srl --pass 1
* *
* Options: * Options:
* --pass 1 Solo metadata base (veloce) * --pass 1 Solo metadata base (veloce)
@ -343,39 +343,42 @@ function saveMetadata(resources, outputPath) {
function main() { function main() {
const args = process.argv.slice(2); const args = process.argv.slice(2);
let client = null; let project = null;
let passLevel = 1; let passLevel = 1;
let vision = false; let vision = false;
let outputPath = null; let outputPath = null;
let verbose = false; let verbose = false;
let basePath = process.env.AGENCY_PROJECTS_BASE || process.cwd();
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
if (args[i] === '--client' && args[i + 1]) { if (args[i] === '--project' && args[i + 1]) {
client = args[++i]; project = args[++i];
} else if (args[i] === '--pass' && args[i + 1]) { } else if (args[i] === '--pass' && args[i + 1]) {
passLevel = parseInt(args[++i]); passLevel = parseInt(args[++i]);
} else if (args[i] === '--vision') { } else if (args[i] === '--vision') {
vision = true; vision = true;
} else if (args[i] === '--output' && args[i + 1]) { } else if (args[i] === '--output' && args[i + 1]) {
outputPath = args[++i]; outputPath = args[++i];
} else if (args[i] === '--base-path' && args[i + 1]) {
basePath = args[++i];
} else if (args[i] === '--verbose') { } else if (args[i] === '--verbose') {
verbose = true; verbose = true;
} }
} }
if (!client) { if (!project) {
console.error('Usage: node scan_resources.js --client <client_name>'); console.error('Usage: node scan_resources.js --project <project_name>');
console.error('Options: --pass 1|2, --vision, --output, --verbose'); console.error('Options: --base-path <dir>, --pass 1|2, --vision, --output, --verbose');
console.error('Environment: AGENCY_PROJECTS_BASE (opzionale)');
process.exit(1); process.exit(1);
} }
// Path // Path
const workspace = path.join(os.homedir(), '.openclaw', 'workspace', 'agency-skills-suite'); const projectDir = path.join(basePath, project);
const clientDir = path.join(workspace, 'clients', client); const assetsDir = path.join(projectDir, 'assets');
const assetsDir = path.join(clientDir, 'assets');
if (!fs.existsSync(clientDir)) { if (!fs.existsSync(projectDir)) {
console.error(`❌ Cartella cliente non trovata: ${clientDir}`); console.error(`❌ Cartella progetto non trovata: ${projectDir}`);
process.exit(1); process.exit(1);
} }
@ -419,7 +422,7 @@ function main() {
console.log(` 🎬 Video: ${videos.length}`); console.log(` 🎬 Video: ${videos.length}`);
console.log(` 📄 Documenti: ${docs.length}`); console.log(` 📄 Documenti: ${docs.length}`);
console.log(` 💾 Metadata: ${outputPath}`); console.log(` 💾 Metadata: ${outputPath}`);
console.log(`\n👉 Prossimo step: node scripts/generate_catalog.js --client ${client}`); console.log(`\n👉 Prossimo step: node scripts/generate_catalog.js --project ${project}`);
} }
main(); main();