Add meteorologist skill with 9 weather/climate tools

New skill:
- .smallclaw/skills/meteorologist/SKILL.md — 기상 전문가 스킬 (Windy iframe 규칙 포함)

New weather tools (src/tools/weather.ts):
- weather_airpollution: OpenWeather 대기질 (AQI, PM2.5/PM10/O3/NO2)
- weather_openmeteo: Open-Meteo 시간별 예보 (ECMWF/GFS, 키 불필요)
- weather_kma: 기상청 공식 API (초단기실황·단기예보)
- weather_airkorea: 에어코리아 실시간 대기질
- weather_nasa_power: NASA POWER 기후 데이터 (MERRA-2, 키 불필요)
- weather_era5: ERA5 재분석 과거 데이터 (Open-Meteo Historical, 키 불필요)
- weather_cds: Copernicus CDS 정식 API (ERA5·CMIP6 SSP 시나리오)
- weather_cmip6: CMIP6 기후 모델 (Open-Meteo Climate API, 키 불필요)

Scripts:
- scripts/era5_cds_fetch.py — CDS/CMIP6 Python 헬퍼 (ZIP→NetCDF 처리 포함)

web-ui:
- Windy URL → iframe 자동 렌더링 (standalone URL + 마크다운 링크 모두 감지)
- windyToEmbedUrl: windy.com comma 형식 URL 파싱 개선

server-v2.ts:
- BROWSER RULE: "열어줘" 제거 → 오용 방지
- weather context: 9개 도구 선택 기준 추가
- JSON schema 8개 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
kim
2026-05-26 14:22:49 +09:00
co-authored by Claude Sonnet 4.6
parent ed25f457df
commit d7eb0abc6d
18 changed files with 2545 additions and 126 deletions
+10
View File
@@ -763,6 +763,16 @@
.msg.user .msg-content { color: #0f3d8a; }
.md-img { max-width: 100%; max-height: 400px; border-radius: 8px; cursor: pointer; margin: 8px 0; display: block; }
.md-img:hover { opacity: 0.9; }
.md-img-err { display: inline-block; color: var(--muted, #888); font-size: 13px; padding: 4px 8px; background: var(--surface2, #f0f0f0); border-radius: 6px; margin: 4px 0; }
.map-embed-wrap { margin: 10px 0; border-radius: 10px; overflow: hidden; border: 1px solid var(--line, #dde3f0); }
.map-embed { width: 100%; height: 420px; border: none; display: block; }
.map-embed-link { padding: 6px 12px; background: var(--surface2, #f5f5f7); font-size: 12px; }
.map-embed-link a { color: var(--accent, #1a73e8); text-decoration: none; }
.map-embed-link a:hover { text-decoration: underline; }
.yt-embed-wrap { margin: 10px 0; border-radius: 10px; overflow: hidden; border: 1px solid var(--line, #dde3f0); }
.yt-embed { width: 100%; aspect-ratio: 16/9; border: none; display: block; }
.windy-embed-wrap { margin: 10px 0; border-radius: 10px; overflow: hidden; border: 1px solid var(--line, #dde3f0); }
.windy-embed { width: 100%; height: 500px; border: none; display: block; }
.md-code-block { background: #1e1e2e; color: #cdd6f4; padding: 12px 16px; border-radius: 8px; overflow-x: auto; font-size: 13px; line-height: 1.5; margin: 8px 0; }
.md-inline-code { background: #e8edf6; color: #17243b; padding: 2px 6px; border-radius: 4px; font-size: 13px; }
:root[data-theme="dark"] .md-inline-code { background: #2a2a3e; color: #cdd6f4; }