diff --git a/src/container-runtime.ts b/src/container-runtime.ts index 3ce4ff4..eaf6b92 100644 --- a/src/container-runtime.ts +++ b/src/container-runtime.ts @@ -70,7 +70,9 @@ export function ensureContainerRuntimeRunning(): void { execSync(`${CONTAINER_RUNTIME_BIN} info`, { stdio: 'pipe' }); logger.debug('Docker runtime already running'); } catch { - logger.fatal('Docker (OrbStack) is not running. Please start OrbStack and try again.'); + logger.fatal( + 'Docker (OrbStack) is not running. Please start OrbStack and try again.', + ); process.exit(1); } } @@ -78,10 +80,13 @@ export function ensureContainerRuntimeRunning(): void { /** Kill orphaned NanoClaw containers from previous runs. */ export function cleanupOrphans(): void { try { - const output = execSync(`${CONTAINER_RUNTIME_BIN} ps --filter "name=nanoclaw-" --format "{{.Names}}"`, { - stdio: ['pipe', 'pipe', 'pipe'], - encoding: 'utf-8', - }); + const output = execSync( + `${CONTAINER_RUNTIME_BIN} ps --filter "name=nanoclaw-" --format "{{.Names}}"`, + { + stdio: ['pipe', 'pipe', 'pipe'], + encoding: 'utf-8', + }, + ); const orphans = output.split('\n').filter(Boolean); for (const name of orphans) { try { diff --git a/src/router.ts b/src/router.ts index b42ce9a..b0ff3ba 100644 --- a/src/router.ts +++ b/src/router.ts @@ -109,11 +109,13 @@ interface WeatherData { * Preprocess text to remove separators and non-weather lines. */ function preprocessWeatherText(text: string): string { - return text - // Remove lines that are just --- separators - .split('\n') - .filter((line) => !/^\s*[-─]+\s*$/.test(line)) - .join('\n'); + return ( + text + // Remove lines that are just --- separators + .split('\n') + .filter((line) => !/^\s*[-─]+\s*$/.test(line)) + .join('\n') + ); } /** @@ -121,13 +123,18 @@ function preprocessWeatherText(text: string): string { */ function extractTemperatureValue(line: string): string { // Match "온도: 11.8도 (어제보다...)" or just "온도: 11.8도" - const match = line.match(/(?:온도|temp|temperature|기온|체감)[:\s]*([^\n(]+)/i); + const match = line.match( + /(?:온도|temp|temperature|기온|체감)[:\s]*([^\n(]+)/i, + ); return match ? match[1].trim() : ''; } function parseWeatherContent(text: string): WeatherData | null { const cleanText = preprocessWeatherText(text); - const lines = cleanText.split('\n').map((l) => l.trim()).filter(Boolean); + const lines = cleanText + .split('\n') + .map((l) => l.trim()) + .filter(Boolean); if (lines.length < 2) return null; const data: WeatherData = {}; @@ -157,7 +164,10 @@ function parseWeatherContent(text: string): WeatherData | null { for (const pattern of valuePatterns) { const match = line.match(pattern); if (match) { - const key = pattern.source.match(/(?:온도|temp|temperature|기온|체감|날씨|weather|상태|습도|humidity|바람|wind|풍속|미세먼지|초미세먼지|자외선|일몰)/i)?.[0] || ''; + const key = + pattern.source.match( + /(?:온도|temp|temperature|기온|체감|날씨|weather|상태|습도|humidity|바람|wind|풍속|미세먼지|초미세먼지|자외선|일몰)/i, + )?.[0] || ''; const value = match[1].trim(); if (/온도|temp|temperature|기온/i.test(key) && !data.temperature) { @@ -184,7 +194,13 @@ function parseWeatherContent(text: string): WeatherData | null { // If line has no pattern match but looks like a location name // (short line, no special characters, not a header) - if (!data.location && line.length > 1 && line.length < 20 && !/[:=]/.test(line) && !/^\d/.test(line)) { + if ( + !data.location && + line.length > 1 && + line.length < 20 && + !/[:=]/.test(line) && + !/^\d/.test(line) + ) { data.location = line; } } @@ -225,12 +241,16 @@ function parseMultipleWeatherContent(text: string): WeatherData[] { */ function getWeatherEmoji(weather: string): string { const w = weather.toLowerCase(); - if (w.includes('맑') || w.includes('sunny') || w.includes('clear')) return '☀️'; - if (w.includes('구름') || w.includes('cloud') || w.includes('흐림')) return '☁️'; + if (w.includes('맑') || w.includes('sunny') || w.includes('clear')) + return '☀️'; + if (w.includes('구름') || w.includes('cloud') || w.includes('흐림')) + return '☁️'; if (w.includes('비') || w.includes('rain')) return '🌧️'; if (w.includes('눈') || w.includes('snow')) return '❄️'; - if (w.includes('뇌') || w.includes('thunder') || w.includes('번개')) return '⛈️'; - if (w.includes('안개') || w.includes('fog') || w.includes('mist')) return '🌫️'; + if (w.includes('뇌') || w.includes('thunder') || w.includes('번개')) + return '⛈️'; + if (w.includes('안개') || w.includes('fog') || w.includes('mist')) + return '🌫️'; if (w.includes('바람') || w.includes('wind')) return '💨'; return '🌤️'; } @@ -288,7 +308,10 @@ function formatWeatherCard(data: WeatherData): string { * Format general content into a visually appealing card using Telegram Markdown */ function formatAsCard(text: string): string { - const lines = text.split('\n').map((l) => l.trim()).filter(Boolean); + const lines = text + .split('\n') + .map((l) => l.trim()) + .filter(Boolean); if (lines.length === 0) return text; // Try multi-location weather parsing first