github YangtseSu/cirrocast v1.1.0

latest releases: v1.3.0, v1.2.0
3 days ago

[1.1.0] - 2026-10-04

Phase D's first three steps — severe-weather alerts (15), air quality (16) and moon/astro (17) —
on top of the 2026-10-02 review fixes
(docs/reviews/02-review-01-fixes-2026-10-02.md).
The v1 CLI contract is unchanged; the JSON document moves to schema_version 2 because the
alerts array arrived with the alerts work (see below), and the config document stays at
schema_version 1 — the [alerts] and [air] tables are additive.

Added

  • Severe-weather alerts (step 15). cirrocast now fetches official warnings by default —
    --no-alerts opts out, --alerts forces them, --alerts-from nws,meteoalarm,… names the sources —
    and renders them as a severity-coloured banner above art-table/one-line, as alert: records in
    plain, as the new --format alerts listing and as the alerts array in json. Sources are
    selected by coverage: NWS (US and territories), MeteoAlarm (EUMETNET members, optional
    CIRROCAST_METEOALARM_KEY), HKO (Hong Kong), QWeather (China, on its provider's chain) and the two
    global aggregators WMO SWIC and FPAS (self-hostable through [alerts] fpas_url). Warnings are
    normalised to CAP 1.2, expired ones are dropped (ends, else expires), duplicates across sources
    are collapsed, and strongest comes first. The threshold is [alerts] severity_threshold/--severity
    (default minor); the cache namespace alerts/ has a 300 s TTL and --offline replays the last
    set. One-line's %A expands to the strongest alert's event (empty when none).
  • JSON output: schema_version is now 2, adding the alerts array and alert_credits
    (docs/schema.md); version 1 documents still parse. provider info gained the alert row
    (provider info qweather → alerts: qweather, provider info smhi → alerts: none).
  • [alerts] configuration table (enabled, severity_threshold, sources, fpas_url,
    cache_ttl_secs) with config get/set support.
  • Air quality (step 16). --aqi appends an air-quality panel to art-table and plain — the
    US and European AQI, the six regulated pollutants in μg/m³ and, inside the CAMS European domain,
    the six pollen species in grains/m³ — --format aqi prints it standalone, one-line gains the
    %q token, and json carries an air object (additive within schema_version 2). The reading
    is one keyless request to Open-Meteo's Air Quality API for the location the run already resolved,
    cached under weather/open-meteo-air-<lat>-<lon>-<local-date>.json with cache.weather_ttl_secs
    and the usual --no-cache/--refresh/--offline semantics. Categories are computed locally from
    the published breakpoints; --aqi-index ([air] index, default us) picks the scale that drives
    the category colour and %q; --units leaves the pollutant values alone by design. The fetch is
    best-effort: a failure prints warning: air quality unavailable: … on stderr and never changes
    the run's exit code, and a location outside the pollen domain says not covered at this location
    instead of inventing a zero.
  • Moon phase and astronomy (step 17). --moon appends a locally computed moon/sun block to
    art-table and plain, --format moon prints the standalone view, one-line gains %m (the
    phase's art glyph) and %M (the phase's name), and json carries an astro object (additive
    within schema_version 2). Nothing is fetched: the phase, the geocentric illuminated fraction,
    the age, moonrise/moonset, the next four phase instants and — when the backend sends no sun
    times — sunrise/sunset/daylight are computed from the truncated Meeus series (ELP-2000/82 and
    solar, ΔT from the Espenak–Meeus fits). The sun block prefers the provider's own times and records
    where they came from in astro.sun.source; inside the polar circles the state is named
    (polar day/polar night) instead of clamping to 00:00, and an event a day does not have
    prints —. %m/%M are always available; --moon is a usage error for the formats that have
    no astro surface (one-line, alerts, aqi).

Changed

  • network.proxy accepts only http:// and https:// URLs. A SOCKS URL is refused by the config
    validator, naming the key, instead of reaching ureq — which is built without a SOCKS connector and
    panicked on a hand-written setting.
  • providers.qweather.host must be the account's HTTPS host, https://<account-id>.re.qweatherapi.com.
    A legacy shared host or a plain-http:// value now fails validation on every run: the legacy hosts
    answer 403 Invalid Host, and cleartext would leak the key.
  • config show prints the values config get reports, CIRROCAST_* overrides included, and exits 4
    when an override is invalid; it previously ignored the environment.
  • config edit rejects unknown keys like config validate; config set validates only the key it
    writes, so an unrelated invalid value no longer blocks it.
  • config init, and config edit on a missing file, seed the new file with the effective
    configuration when a system document is shadowed (that one case writes canonical TOML without the
    commented template; with no other source the template is unchanged).
  • A whitespace-only CIRROCAST_* override counts as unset, like a whitespace-only config value.
  • --lang accepts POSIX spellings (zh_CN.UTF-8 → zh-CN), and en-*/zh-* tags resolve through
    their family chain (en-GB → en-US) without the fallback warning.
  • art-table: the dumb/ASCII arrows are , (SW) and ` (NW) — the previous keypad digits read
    as part of the speed — and the arrow sector follows the 16-point compass, so arrow and label always
    turn together.
  • art-table at 20–36 columns: the stacked ladder's rungs keep the precipitation and wind fields
    instead of silently dropping them (at ≥37 columns the output is unchanged).
  • -f dumb is always plain, escapes included: --color always no longer paints the ASCII table.
  • -f one-line: %w prints the speed alone when the direction is absent, instead of n/a.
  • -f json: -0.0 is written as 0.0, like every other display path.
  • -v: the missing-key dump runs after the forecast and reports each missing key once per run; -vv
    request logs redact secrets in their percent-encoded spelling too.
  • Messages: an unknown location no longer promises a candidate list it does not print, an unknown
    station points at @lat,lon, --lat/--lon report the command-line source, and the help epilogue
    spells the precedence as LOCATION CIRROCAST_LOCATION.

Fixed

  • A reading that is NaN or inf is refused with Error::Upstream in Provider::fetch — the one
    path every backend's answer takes — before it can be cached or rendered.
  • QWeather: precipitation probability is read as the percent upstream sends (a 40 came out as 100%
    through the fraction helper), and code 515 maps to WMO 56 (freezing drizzle), not a fog variant.
  • Open-Meteo: an absent or truncated precipitation_probability array means "no probability", not an
    upstream error.
  • Pirate Weather: -999 sentinels in humidity, cloud cover and probability are missing values, not
    readings.
  • WorldWeatherOnline: the {"data":{"error":[…]}} envelope is an upstream error carrying the message,
    not a decode failure.
  • METAR: an unmapped obscuration falls back to the sky condition, IC maps to WMO 79 (ice pellets,
    the nearest described family) instead of failing, and conversions keep the exact value rather than a
    pre-rounded one.
  • A value just below a .5 tie no longer rounds to the wrong side (fmt_int on large readings,
    fmt_small on a negative reading).
  • An extreme timestamp in an upstream payload produces a typed error instead of overflowing.
  • A failed cache write logs at -vv and still serves the fetched answer.
  • Nominatim requests are sent once, without retry, so its 1 req/s policy is never breached by backoff.
  • A non-absolute XDG_CONFIG_DIRS entry is ignored instead of read.
  • A days array whose parts are not exactly [Morning, Noon, Evening, Night] is rejected at
    deserialisation, so no renderer can show a part under another part's label.
  • defaults.format accepts moon: the validator's list stopped at aqi and the template comment
    at dumb, so config set defaults.format moon failed and a hand-written format = "moon" was
    refused on every run although -f moon and CIRROCAST_FORMAT=moon worked. The three lists are
    now pinned to each other by a test.

Don't miss a new cirrocast release

NewReleases is sending notifications on new releases.