Modifiche'; public function handle(): int { $generatedDir = storage_path('app/support/generated'); File::ensureDirectoryExists($generatedDir); $outputPath = trim((string) $this->option('output')) !== '' ? trim((string) $this->option('output')) : $generatedDir . '/CONTINUITA-SVILUPPO-SNAPSHOT.md'; $jsonPath = trim((string) $this->option('json')) !== '' ? trim((string) $this->option('json')) : $generatedDir . '/CONTINUITA-SVILUPPO-SNAPSHOT.json'; $manualPath = base_path('docs/support/MANUALE-SVILUPPO-OPERATIVO.md'); $bugPath = base_path('docs/support/BUG-RISOLTI-E-VALIDAZIONI.md'); $continuityPath = base_path('docs/support/CONTINUITA-SVILUPPO-AGENT.md'); $pbxPath = base_path('docs/support/PBX-PANASONIC-STATO-OPERATIVO.md'); $manual = is_file($manualPath) ? (string) @file_get_contents($manualPath) : ''; $bugs = is_file($bugPath) ? (string) @file_get_contents($bugPath) : ''; $continuity = is_file($continuityPath) ? (string) @file_get_contents($continuityPath) : ''; $pbx = is_file($pbxPath) ? (string) @file_get_contents($pbxPath) : ''; $branch = $this->gitValue(['rev-parse', '--abbrev-ref', 'HEAD']) ?? '-'; $commit = $this->gitValue(['rev-parse', '--short', 'HEAD']) ?? '-'; $recentCommits = $this->recentCommits(); $recentPages = $this->recentPages(); $commitNotes = $this->recentCommitNotes(); $snapshot = []; $snapshot[] = '# Snapshot continuita sviluppo'; $snapshot[] = ''; $snapshot[] = 'Generata automaticamente il ' . now()->format('d/m/Y H:i:s') . '.'; $snapshot[] = ''; $snapshot[] = '## Stato Git corrente'; $snapshot[] = ''; $snapshot[] = '- Branch: `' . $branch . '`'; $snapshot[] = '- Commit: `' . $commit . '`'; $snapshot[] = '- Workspace: `' . base_path() . '`'; $snapshot[] = ''; $snapshot[] = '## Focus operativo'; $snapshot[] = ''; $snapshot[] = $this->normalizeSectionLines($this->extractSection($manual, '## Implementazioni recenti da tenere come riferimento')); $snapshot[] = ''; $snapshot[] = '## Stato PBX Panasonic'; $snapshot[] = ''; $snapshot[] = $this->normalizeSectionLines($this->extractSection($pbx, '## Stato attuale')); $snapshot[] = ''; $snapshot[] = '## Validazioni ancora aperte'; $snapshot[] = ''; $snapshot[] = $this->normalizeSectionLines($this->extractSection($bugs, '## Validazioni ancora aperte')); $snapshot[] = ''; $snapshot[] = '## Prossimi passi consigliati'; $snapshot[] = ''; $snapshot[] = $this->normalizeSectionLines($this->extractSection($manual, '## Prossimi passi consigliati')); $snapshot[] = ''; $snapshot[] = '## Regole di continuita'; $snapshot[] = ''; $snapshot[] = $this->normalizeSectionLines($this->extractSection($continuity, '## Regola semplice')); $snapshot[] = ''; $snapshot[] = '## Ultimi commit'; $snapshot[] = ''; $snapshot[] = '| Data | Commit | Messaggio |'; $snapshot[] = '| --- | --- | --- |'; foreach ($recentCommits as $row) { $snapshot[] = '| ' . $row['date'] . ' | `' . $row['hash'] . '` | ' . str_replace('|', '-', $row['message']) . ' |'; } $snapshot[] = ''; $snapshot[] = '## Note commit recenti'; $snapshot[] = ''; if ($commitNotes === []) { $snapshot[] = '- Nessuna nota commit strutturata disponibile tra gli ultimi commit.'; } else { foreach ($commitNotes as $row) { $snapshot[] = '- `' . $row['hash'] . '` ' . $row['message']; $snapshot[] = ' - Nota: ' . $row['note']; } } $snapshot[] = ''; $snapshot[] = '## Pagine toccate di recente'; $snapshot[] = ''; if ($recentPages === []) { $snapshot[] = '- Nessuna pagina recente rilevata.'; } else { foreach ($recentPages as $row) { $snapshot[] = '- `' . $row['commit'] . '` ' . $row['page'] . ' -> `' . $row['path'] . '`'; } } $snapshot[] = ''; $snapshot[] = '## Fonti da leggere per ripartire'; $snapshot[] = ''; $snapshot[] = '- `docs/support/MANUALE-SVILUPPO-OPERATIVO.md`'; $snapshot[] = '- `docs/support/PBX-PANASONIC-STATO-OPERATIVO.md`'; $snapshot[] = '- `docs/support/BUG-RISOLTI-E-VALIDAZIONI.md`'; $snapshot[] = '- `docs/support/CONTINUITA-SVILUPPO-AGENT.md`'; File::put($outputPath, implode(PHP_EOL, $snapshot) . PHP_EOL); File::put($jsonPath, json_encode([ 'generated_at' => now()->toIso8601String(), 'branch' => $branch, 'commit' => $commit, 'output_path' => $outputPath, 'source_files' => [ 'docs/support/MANUALE-SVILUPPO-OPERATIVO.md', 'docs/support/PBX-PANASONIC-STATO-OPERATIVO.md', 'docs/support/BUG-RISOLTI-E-VALIDAZIONI.md', 'docs/support/CONTINUITA-SVILUPPO-AGENT.md', ], ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); $this->info('Snapshot continuita sviluppo aggiornata.'); return self::SUCCESS; } private function gitValue(array $arguments): ?string { $result = Process::path(base_path()) ->timeout(120) ->run(array_merge(['git'], $arguments)); if (! $result->successful()) { return null; } $output = trim((string) $result->output()); return $output !== '' ? $output : null; } /** @return array */ private function recentCommits(): array { $rows = []; $result = Process::path(base_path())->timeout(120)->run([ 'git', 'log', '-n', '8', '--date=format:%d/%m/%Y %H:%M', '--pretty=format:%h|%ad|%s', ]); if (! $result->successful()) { return []; } $lines = preg_split('/\r\n|\r|\n/', trim((string) $result->output())) ?: []; foreach ($lines as $line) { $parts = explode('|', $line, 3); if (count($parts) !== 3) { continue; } $rows[] = [ 'hash' => (string) $parts[0], 'date' => (string) $parts[1], 'message' => (string) $parts[2], ]; } return $rows; } /** @return array */ private function recentPages(): array { $rows = []; $seen = []; $result = Process::path(base_path())->timeout(120)->run([ 'git', 'log', '-n', '12', '--name-only', '--pretty=format:@@@%h', '--', 'app/Filament/Pages', 'resources/views/filament/pages', ]); if (! $result->successful()) { return []; } $currentCommit = null; $lines = preg_split('/\r\n|\r|\n/', (string) $result->output()) ?: []; foreach ($lines as $line) { $line = trim((string) $line); if ($line === '') { continue; } if (str_starts_with($line, '@@@')) { $currentCommit = substr($line, 3); continue; } if ($currentCommit === null || isset($seen[$line])) { continue; } if (! str_starts_with($line, 'app/Filament/Pages/') && ! str_starts_with($line, 'resources/views/filament/pages/')) { continue; } $seen[$line] = true; $rows[] = [ 'page' => basename($line), 'path' => $line, 'commit' => $currentCommit, ]; if (count($rows) >= 10) { break; } } return $rows; } /** @return array */ private function recentCommitNotes(): array { $path = storage_path('app/support/commit-notes.json'); if (! is_file($path)) { return []; } $decoded = json_decode((string) @file_get_contents($path), true); if (! is_array($decoded)) { return []; } $rows = []; foreach ($this->recentCommits() as $commit) { $fullHash = $this->gitValue(['rev-parse', $commit['hash']]); if (! is_string($fullHash) || ! isset($decoded[$fullHash]) || ! is_string($decoded[$fullHash])) { continue; } $rows[] = [ 'hash' => $commit['hash'], 'message' => $commit['message'], 'note' => trim($decoded[$fullHash]), ]; } return array_slice($rows, 0, 5); } private function extractSection(string $markdown, string $heading): string { if ($markdown === '' || ! str_contains($markdown, $heading)) { return '- Sezione non disponibile.'; } $offset = strpos($markdown, $heading); if ($offset === false) { return '- Sezione non disponibile.'; } $slice = substr($markdown, $offset + strlen($heading)); if (! is_string($slice)) { return '- Sezione non disponibile.'; } if (preg_match('/\n##\s+/', $slice, $match, PREG_OFFSET_CAPTURE) === 1) { $slice = substr($slice, 0, (int) $match[0][1]); } return trim($slice) !== '' ? trim($slice) : '- Sezione non disponibile.'; } private function normalizeSectionLines(string $text): string { $lines = preg_split('/\r\n|\r|\n/', trim($text)) ?: []; $cleaned = []; foreach ($lines as $line) { $line = trim((string) $line); if ($line === '') { continue; } $cleaned[] = $line; } return $cleaned === [] ? '- Nessuna informazione disponibile.' : implode(PHP_EOL, $cleaned); } }