tuiweather 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -13
- package/bin/tuiweather.js +39 -2
- package/dist/index.js +748 -289
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -16,7 +16,9 @@ Keyboard-driven terminal weather app: Dark Sky-style rain nowcasting, hourly and
|
|
|
16
16
|
|
|
17
17
|
## Install
|
|
18
18
|
|
|
19
|
-
Requires Node.js
|
|
19
|
+
Requires Node.js to run: the package declares `engines.node >= 20`, and the command-line
|
|
20
|
+
paths (`--version`, `--help`, `--one-line`) work on any such Node; the interactive TUI
|
|
21
|
+
needs Node >= 26.4.0, enforced at runtime by the launcher. Install globally with npm:
|
|
20
22
|
|
|
21
23
|
```sh
|
|
22
24
|
npm install --global tuiweather
|
|
@@ -28,7 +30,20 @@ or with the Bun package manager:
|
|
|
28
30
|
bun install --global tuiweather
|
|
29
31
|
```
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
or run without installing:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npx tuiweather --version
|
|
37
|
+
bunx tuiweather --version
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Standalone binaries for macOS, Linux, and Windows (x64) are attached to each [GitHub release](https://github.com/brndnsh-labs/tuiweather/releases). On Windows (no Node or Bun required), in cmd.exe or any shell with `curl.exe` on PATH:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
curl.exe -Lo tuiweather-windows-x64.tar.gz https://github.com/brndnsh-labs/tuiweather/releases/latest/download/tuiweather-windows-x64.tar.gz
|
|
44
|
+
tar -xzf tuiweather-windows-x64.tar.gz
|
|
45
|
+
.\tuiweather.exe --version
|
|
46
|
+
```
|
|
32
47
|
|
|
33
48
|
### macOS Gatekeeper
|
|
34
49
|
|
|
@@ -43,8 +58,9 @@ xattr -d com.apple.quarantine /path/to/tuiweather
|
|
|
43
58
|
Run `tuiweather` with no arguments for the full TUI.
|
|
44
59
|
|
|
45
60
|
On the first run, tuiweather opens a short keyboard tour, asks for metric or imperial units, and
|
|
46
|
-
lets you search for your first location.
|
|
47
|
-
|
|
61
|
+
lets you search for your first location. Press `s` on the welcome step to skip for now and see the
|
|
62
|
+
empty main view, or `o` from the help overlay to re-run setup later. The completed setup is written
|
|
63
|
+
atomically to the normal config path before weather data loads.
|
|
48
64
|
|
|
49
65
|
Use `tuiweather --help` for command-line options and `tuiweather --version` to print the installed version.
|
|
50
66
|
|
|
@@ -63,7 +79,8 @@ Use `tuiweather --help` for command-line options and `tuiweather --version` to p
|
|
|
63
79
|
| `J` / `K` | Move focused location down/up in sidebar order (lg tier) |
|
|
64
80
|
| `↑` / `↓` | Scroll the main panel when content overflows |
|
|
65
81
|
| `?` | Toggle help overlay |
|
|
66
|
-
| `
|
|
82
|
+
| `o` | Re-run setup (from help overlay) |
|
|
83
|
+
| `esc` | Clear sidebar focus if set; otherwise close the help overlay |
|
|
67
84
|
| `q` | Quit |
|
|
68
85
|
|
|
69
86
|
While the search overlay is open it owns the keyboard: type to search, up/down to move the cursor, enter to add the highlighted result, esc to cancel. Number, focus, and reorder keys are ignored while the search input is focused (same as `d`/`r`).
|
|
@@ -125,10 +142,11 @@ bell. The bell depends on the minute-level nowcast, which is Open-Meteo only: un
|
|
|
125
142
|
Config lives at `~/.config/tuiweather/config.toml` (respects `XDG_CONFIG_HOME`). Every field is optional unless marked required; unknown fields are ignored.
|
|
126
143
|
|
|
127
144
|
```toml
|
|
128
|
-
schema_version =
|
|
145
|
+
schema_version = 4
|
|
129
146
|
time_format = "auto"
|
|
130
147
|
refresh_minutes = 10
|
|
131
148
|
theme = "auto"
|
|
149
|
+
ink = "auto"
|
|
132
150
|
provider = "openmeteo"
|
|
133
151
|
daily_days = 7
|
|
134
152
|
hourly_hours = 24
|
|
@@ -155,24 +173,26 @@ longitude = -122.6765
|
|
|
155
173
|
|
|
156
174
|
| Field | Type | Default | Constraints |
|
|
157
175
|
| --- | --- | --- | --- |
|
|
158
|
-
| `schema_version` | integer | `
|
|
176
|
+
| `schema_version` | integer | `4` | Required; currently always `4`. Version 1, 2, and 3 files are migrated in place on load |
|
|
159
177
|
| `time_format` | `12h` / `24h` / `auto` | `"auto"` | `auto` picks 12h when temperature units are imperial, else 24h |
|
|
160
178
|
| `refresh_minutes` | integer | `10` | Minimum `1` |
|
|
161
|
-
| `
|
|
179
|
+
| `reduced_motion` | boolean | `false` | Replace the animated loading spinner with a static indicator |
|
|
180
|
+
| `theme` | `day` / `night` / `auto` | `"auto"` | Accent palette; `auto` follows the location's sunrise/sunset. Text ink adapts via `ink` |
|
|
181
|
+
| `ink` | `auto` / `light` / `dark` | `"auto"` | Terminal ink override; `auto` detects the background via an OSC query (300ms timeout, fallback dark), `light`/`dark` skips detection and uses that ink directly |
|
|
162
182
|
| `provider` | `openmeteo` / `nws` | `"openmeteo"` | Weather data source. Open-Meteo is the default full-feature experience; NWS is the official US source fallback — works: conditions, temperatures, precipitation probabilities; goes quiet: minute-level nowcast (panel hides, watch bell inactive), hourly/daily precip amounts (blank bars/chips), air quality |
|
|
163
183
|
| `daily_days` | integer | `7` | `1`–`16` forecast days |
|
|
164
184
|
| `hourly_hours` | integer | `24` | `12`–`48` forecast hours |
|
|
165
185
|
| `default_location` | string | none | Must match a `[[locations]]` slug |
|
|
166
|
-
| `units.temp` | `metric` / `imperial` | legacy `units` | Display unit for temperatures |
|
|
167
|
-
| `units.wind` | `metric` / `imperial` | legacy `units` | Display unit for wind speed and visibility |
|
|
168
|
-
| `units.precip` | `metric` / `imperial` | legacy `units` | Display unit for precipitation amounts |
|
|
169
|
-
| `units.pressure` | `metric` / `imperial` | legacy `units` | Display unit for pressure; `metric` → hPa (rounded), `imperial` → inHg to 2 decimals;
|
|
186
|
+
| `units.temp` | `metric` / `imperial` | legacy `units`, else `imperial` | Display unit for temperatures |
|
|
187
|
+
| `units.wind` | `metric` / `imperial` | legacy `units`, else `imperial` | Display unit for wind speed and visibility |
|
|
188
|
+
| `units.precip` | `metric` / `imperial` | legacy `units`, else `imperial` | Display unit for precipitation amounts |
|
|
189
|
+
| `units.pressure` | `metric` / `imperial` | legacy `units`, else `imperial` | Display unit for pressure; `metric` → hPa (rounded), `imperial` → inHg to 2 decimals; falls back to `imperial` when unset |
|
|
170
190
|
| `panels.nowcast` | boolean | `true` | Show/hide the nowcast banner |
|
|
171
191
|
| `panels.details` | boolean | `true` | Show/hide the details grid |
|
|
172
192
|
| `panels.hourly` | boolean | `true` | Show/hide the hourly strip |
|
|
173
193
|
| `panels.daily` | boolean | `true` | Show/hide the daily list |
|
|
174
194
|
|
|
175
|
-
Each `[units]` field can be set independently, so mixed display such as °C temperatures with mph wind works everywhere including one-line mode. The legacy top-level `units = "metric" | "imperial"` scalar is still accepted and acts as the fallback for any `[units]` field you omit;
|
|
195
|
+
Each `[units]` field can be set independently, so mixed display such as °C temperatures with mph wind works everywhere including one-line mode. The legacy top-level `units = "metric" | "imperial"` scalar is still accepted and acts as the fallback for any `[units]` field you omit; when neither the field nor the legacy scalar is set, the unit falls back to `imperial`. Because TOML forbids a key and table with the same name, saved configs contain either the scalar (uniform prefs) or the full `[units]` table (mixed prefs), never both.
|
|
176
196
|
|
|
177
197
|
Each `[[locations]]` entry:
|
|
178
198
|
|
package/bin/tuiweather.js
CHANGED
|
@@ -1,2 +1,39 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
import "
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const FFI_FLAGS = ["--experimental-ffi", "--disable-warning=ExperimentalWarning"];
|
|
6
|
+
const FFI_MIN_NODE = [26, 4, 0];
|
|
7
|
+
|
|
8
|
+
function nodeAtLeast(min) {
|
|
9
|
+
const parts = process.versions.node.split(".").map(Number);
|
|
10
|
+
for (let i = 0; i < min.length; i++) {
|
|
11
|
+
const have = parts[i] ?? 0;
|
|
12
|
+
if (have !== min[i]) return have > min[i];
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const underBun = Boolean(process.versions.bun);
|
|
18
|
+
const hasFlags = FFI_FLAGS.every((flag) => process.execArgv.includes(flag));
|
|
19
|
+
|
|
20
|
+
if (underBun || hasFlags || !nodeAtLeast(FFI_MIN_NODE)) {
|
|
21
|
+
await import("../dist/index.js");
|
|
22
|
+
} else {
|
|
23
|
+
const script = fileURLToPath(new URL("../dist/index.js", import.meta.url));
|
|
24
|
+
const child = spawnSync(process.execPath, [...FFI_FLAGS, script, ...process.argv.slice(2)], {
|
|
25
|
+
stdio: "inherit",
|
|
26
|
+
});
|
|
27
|
+
if (child.error) {
|
|
28
|
+
console.error(child.error.message);
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
} else if (child.signal) {
|
|
31
|
+
try {
|
|
32
|
+
process.kill(process.pid, child.signal);
|
|
33
|
+
} catch {
|
|
34
|
+
process.exitCode = child.status ?? 1;
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
process.exitCode = child.status ?? 1;
|
|
38
|
+
}
|
|
39
|
+
}
|