gotrain 1.2.4
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/CHANGELOG.md +54 -0
- package/LICENSE +21 -0
- package/README.md +130 -0
- package/dist/api.d.ts +39 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +97 -0
- package/dist/api.js.map +1 -0
- package/dist/commands/alerts.d.ts +5 -0
- package/dist/commands/alerts.d.ts.map +1 -0
- package/dist/commands/alerts.js +85 -0
- package/dist/commands/alerts.js.map +1 -0
- package/dist/commands/board.d.ts +2 -0
- package/dist/commands/board.d.ts.map +1 -0
- package/dist/commands/board.js +147 -0
- package/dist/commands/board.js.map +1 -0
- package/dist/commands/favorites.d.ts +3 -0
- package/dist/commands/favorites.d.ts.map +1 -0
- package/dist/commands/favorites.js +63 -0
- package/dist/commands/favorites.js.map +1 -0
- package/dist/commands/stations.d.ts +2 -0
- package/dist/commands/stations.d.ts.map +1 -0
- package/dist/commands/stations.js +21 -0
- package/dist/commands/stations.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +100 -0
- package/dist/index.js.map +1 -0
- package/dist/utils.d.ts +16 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +56 -0
- package/dist/utils.js.map +1 -0
- package/package.json +66 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
|
|
7
|
+
- Fixed npm, git, and Homebrew installs to use verified release artifacts.
|
|
8
|
+
- Fixed release publishing to use the stable GitHub Actions Node toolchain.
|
|
9
|
+
|
|
10
|
+
### Changes
|
|
11
|
+
|
|
12
|
+
- Renamed the published npm and Homebrew package to `gotrain`.
|
|
13
|
+
- Documented the local release wrapper and normalized release workflow naming.
|
|
14
|
+
|
|
15
|
+
## 1.2.1 - 2026-03-30
|
|
16
|
+
|
|
17
|
+
### Changes
|
|
18
|
+
|
|
19
|
+
- Added release automation scripts.
|
|
20
|
+
|
|
21
|
+
## 1.2.0 - 2026-03-19
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
- Showed ride duration on train boards.
|
|
26
|
+
|
|
27
|
+
## 1.1.1 - 2026-01-25
|
|
28
|
+
|
|
29
|
+
### Changes
|
|
30
|
+
|
|
31
|
+
- Added relevant npm package keywords.
|
|
32
|
+
|
|
33
|
+
## 1.1.0 - 2026-01-25
|
|
34
|
+
|
|
35
|
+
Initial release.
|
|
36
|
+
|
|
37
|
+
### Features
|
|
38
|
+
|
|
39
|
+
- Added the `gotrain` CLI for MTA system train departures.
|
|
40
|
+
- Added commands, tests, favorites support, arrivals, flags, and alerts.
|
|
41
|
+
- Added improved alert aesthetics, deduplication, pagination, filtering, and `--all` support.
|
|
42
|
+
- Added install script verification and PATH setup.
|
|
43
|
+
|
|
44
|
+
### Fixes
|
|
45
|
+
|
|
46
|
+
- Fixed `--help` exit behavior for install verification.
|
|
47
|
+
- Fixed download error handling in `install.sh`.
|
|
48
|
+
- Fixed transit system output formatting.
|
|
49
|
+
|
|
50
|
+
### Changes
|
|
51
|
+
|
|
52
|
+
- Renamed the script from `nyc-train` to `gotrain`.
|
|
53
|
+
- Removed runtime dependencies and refactored API output formatting to TSV.
|
|
54
|
+
- Updated README installation, usage, examples, favorites, and contributing guidance.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gustavo Madeira Santana
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<img src="assets/gotrain.jpg" alt="gotrain terminal preview" width="280" />
|
|
2
|
+
|
|
3
|
+
# 🚂 gotrain
|
|
4
|
+
|
|
5
|
+
> Atomic CLI for MTA system train departures (NYC Subway, LIRR, Metro-North)
|
|
6
|
+
|
|
7
|
+
No dependencies. No config. Just trains.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## Why?
|
|
14
|
+
|
|
15
|
+
Most train apps are bloated. This is one shell script.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
**Via Homebrew:**
|
|
20
|
+
```bash
|
|
21
|
+
brew tap gumadeiras/tap
|
|
22
|
+
brew install gotrain
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Via npm:**
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g gotrain
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**One-liner (Universal Bash):**
|
|
31
|
+
```bash
|
|
32
|
+
curl -sL https://raw.githubusercontent.com/gumadeiras/gotrain-cli/main/install.sh | bash
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Search stations
|
|
39
|
+
gotrain stations penn # Search for "penn"
|
|
40
|
+
gotrain stations # List all stations
|
|
41
|
+
|
|
42
|
+
# Departures & Arrivals
|
|
43
|
+
gotrain departures MNR-149 # Departures from New Haven
|
|
44
|
+
gotrain departures nh --to MNR-1 # Filter departures to Grand Central (using alias)
|
|
45
|
+
gotrain arrivals MNR-1 # Arrivals at Grand Central
|
|
46
|
+
gotrain arrivals MNR-1 --from nh # Filter arrivals from New Haven
|
|
47
|
+
|
|
48
|
+
# Service alerts
|
|
49
|
+
gotrain alerts # Active service alerts
|
|
50
|
+
|
|
51
|
+
# Favorites
|
|
52
|
+
gotrain favs add MNR-149 nh # Add with alias 'nh'
|
|
53
|
+
gotrain favs rm nh # Remove by alias
|
|
54
|
+
gotrain favs # List favorite stations
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Examples
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
$ gotrain stations "new haven"
|
|
61
|
+
🟥 MNR │ New Haven (CT) Lines: New Haven ♿ ID: MNR-149
|
|
62
|
+
🟥 MNR │ New Haven-State St (CT) Lines: New Haven ♿ ID: MNR-150
|
|
63
|
+
|
|
64
|
+
$ gotrain departures MNR-149
|
|
65
|
+
Departures for New Haven (MNR-149)
|
|
66
|
+
──────────────────────────────────────────────────────────
|
|
67
|
+
10:39 AM EST │ Grand Central (Off Peak) [Line: New Haven]
|
|
68
|
+
│ On Time Track 1 • Ride 2h 04m (Train #1539)
|
|
69
|
+
|
|
70
|
+
11:24 AM EST │ Grand Central (Off Peak) [Line: New Haven]
|
|
71
|
+
│ On Time Track 2 • Ride 2h 01m (Train #1545)
|
|
72
|
+
|
|
73
|
+
$ gotrain arrivals MNR-1 --from nh
|
|
74
|
+
Arrivals for Grand Central (MNR-1)
|
|
75
|
+
Origin: New Haven (MNR-149)
|
|
76
|
+
──────────────────────────────────────────────────────────
|
|
77
|
+
12:43 PM EST │ Grand Central (Off Peak) [Line: New Haven]
|
|
78
|
+
│ On Time No Track • Dep 10:39 AM EST • Ride 2h 04m (Train #1539)
|
|
79
|
+
|
|
80
|
+
$ gotrain favorite add MNR-149 home
|
|
81
|
+
Added MNR-149 to favorites (Alias: home) ✅
|
|
82
|
+
|
|
83
|
+
$ gotrain departures home
|
|
84
|
+
🟦 Departures for New Haven (MNR-149)
|
|
85
|
+
──────────────────────────────────────────────────────────
|
|
86
|
+
...
|
|
87
|
+
|
|
88
|
+
$ gotrain alerts
|
|
89
|
+
⚠️ Uptown [4][5] trains are running with delays...
|
|
90
|
+
No description....
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Commands
|
|
94
|
+
|
|
95
|
+
| Command | Description |
|
|
96
|
+
|---------|-------------|
|
|
97
|
+
| `stations [query]` | Search/list stations |
|
|
98
|
+
| `departures <id> [--to <id>]` | Show departures (optional destination filter) |
|
|
99
|
+
| `arrivals <id> [--from <id>]` | Show arrivals (optional origin filter) |
|
|
100
|
+
| `alerts [--station <id>] [--all]` | Active service alerts (optional station filter, all alerts) |
|
|
101
|
+
| `favs [add|rm] [id] [alias]` | Manage favorites (list, add, remove, toggle) |
|
|
102
|
+
|
|
103
|
+
## Clawdbot Integration
|
|
104
|
+
|
|
105
|
+
This tool is available as a **ClawdHub skill**! Use it from any chat where Clawdbot is connected.
|
|
106
|
+
|
|
107
|
+
- **Skill**: [`gotrain`](https://clawdhub.com/skills/gotrain) on ClawdHub
|
|
108
|
+
|
|
109
|
+
## Data Source
|
|
110
|
+
|
|
111
|
+
Powered by [MetroFlow API](https://metroflow.ainslie.digital) — real-time MTA transit data.
|
|
112
|
+
|
|
113
|
+
## Contributing
|
|
114
|
+
|
|
115
|
+
PRs are welcome! If you find any bugs or have feature requests, please [open an issue](https://github.com/gumadeiras/gotrain-cli/issues/new).
|
|
116
|
+
|
|
117
|
+
- **Development**: Run `npm test` and `npm run build` to verify changes locally.
|
|
118
|
+
- **Style**: Keep the CLI small and direct.
|
|
119
|
+
|
|
120
|
+
## Scripts
|
|
121
|
+
|
|
122
|
+
- `./scripts/committer "message" path...`: stage only the listed paths and create a commit
|
|
123
|
+
- `./scripts/release check 1.2.1`: verify synced release versions and run the release test gates
|
|
124
|
+
- `./scripts/release run 1.2.1`: bump versions, run tests, package artifacts, tag, push, wait for the release workflow, publish npm, and update Homebrew
|
|
125
|
+
|
|
126
|
+
Release CI publishes to npm with trusted publishing.
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT 🐧
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface Station {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
system: string;
|
|
5
|
+
borough?: string;
|
|
6
|
+
accessibilityStatus?: string;
|
|
7
|
+
lines: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface Departure {
|
|
10
|
+
routeShortName?: string;
|
|
11
|
+
routeLongName?: string;
|
|
12
|
+
destination: string;
|
|
13
|
+
departureTime: string;
|
|
14
|
+
status: string;
|
|
15
|
+
track?: string;
|
|
16
|
+
peakStatus?: string;
|
|
17
|
+
direction?: string;
|
|
18
|
+
tripId?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface Alert {
|
|
21
|
+
title: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
activePeriods: {
|
|
24
|
+
start?: string;
|
|
25
|
+
end?: string;
|
|
26
|
+
}[];
|
|
27
|
+
affectedLines: string[];
|
|
28
|
+
affectedStations: string[];
|
|
29
|
+
affectedStationsLabels: string[];
|
|
30
|
+
}
|
|
31
|
+
export declare function fetchWithCache<T>(endpoint: string, ttl?: number): Promise<T>;
|
|
32
|
+
export declare function getStations(): Promise<Station[]>;
|
|
33
|
+
export declare function getDepartures(stationId: string): Promise<Departure[]>;
|
|
34
|
+
export declare function getAlerts(): Promise<Alert[]>;
|
|
35
|
+
export declare function getFavorites(): Record<string, string>;
|
|
36
|
+
export declare function addFavorite(id: string, alias?: string): void;
|
|
37
|
+
export declare function removeFavorite(idOrAlias: string): void;
|
|
38
|
+
export declare function resolveAlias(input: string): string;
|
|
39
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClD,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sBAAsB,EAAE,MAAM,EAAE,CAAC;CAClC;AAED,wBAAsB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,OAAO,CAAC,CAAC,CAAC,CAgB7F;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CActD;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAE3E;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAElD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAErD;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,QAIrD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,QAa/C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fetchWithCache = fetchWithCache;
|
|
7
|
+
exports.getStations = getStations;
|
|
8
|
+
exports.getDepartures = getDepartures;
|
|
9
|
+
exports.getAlerts = getAlerts;
|
|
10
|
+
exports.getFavorites = getFavorites;
|
|
11
|
+
exports.addFavorite = addFavorite;
|
|
12
|
+
exports.removeFavorite = removeFavorite;
|
|
13
|
+
exports.resolveAlias = resolveAlias;
|
|
14
|
+
const conf_1 = __importDefault(require("conf"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const os_1 = __importDefault(require("os"));
|
|
18
|
+
const API_BASE = 'https://metroflow.ainslie.digital/api/v1';
|
|
19
|
+
const CACHE_TTL = 60 * 1000; // 60 seconds in ms
|
|
20
|
+
const STATIONS_CACHE_TTL = 7 * 24 * 3600 * 1000; // 7 days in ms
|
|
21
|
+
const config = new conf_1.default({
|
|
22
|
+
projectName: 'gotrain',
|
|
23
|
+
defaults: {
|
|
24
|
+
favorites: {},
|
|
25
|
+
lastStationsUpdate: 0,
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const cacheDir = path_1.default.join(os_1.default.homedir(), '.cache', 'gotrain');
|
|
29
|
+
if (!fs_1.default.existsSync(cacheDir)) {
|
|
30
|
+
fs_1.default.mkdirSync(cacheDir, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
async function fetchWithCache(endpoint, ttl = CACHE_TTL) {
|
|
33
|
+
const cacheKey = endpoint.replace(/\//g, '-');
|
|
34
|
+
const cacheFile = path_1.default.join(cacheDir, `${cacheKey}.json`);
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
if (fs_1.default.existsSync(cacheFile)) {
|
|
37
|
+
const stats = fs_1.default.statSync(cacheFile);
|
|
38
|
+
if (now - stats.mtimeMs < ttl) {
|
|
39
|
+
return JSON.parse(fs_1.default.readFileSync(cacheFile, 'utf-8'));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const response = await fetch(`${API_BASE}${endpoint}`);
|
|
43
|
+
const data = await response.json();
|
|
44
|
+
fs_1.default.writeFileSync(cacheFile, JSON.stringify(data));
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
async function getStations() {
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
const lastUpdate = config.get('lastStationsUpdate');
|
|
50
|
+
const stationsFile = path_1.default.join(cacheDir, 'stations.json');
|
|
51
|
+
if (fs_1.default.existsSync(stationsFile) && (now - lastUpdate < STATIONS_CACHE_TTL)) {
|
|
52
|
+
return JSON.parse(fs_1.default.readFileSync(stationsFile, 'utf-8'));
|
|
53
|
+
}
|
|
54
|
+
const response = await fetch(`${API_BASE}/stations`);
|
|
55
|
+
const data = await response.json();
|
|
56
|
+
fs_1.default.writeFileSync(stationsFile, JSON.stringify(data));
|
|
57
|
+
config.set('lastStationsUpdate', now);
|
|
58
|
+
return data;
|
|
59
|
+
}
|
|
60
|
+
async function getDepartures(stationId) {
|
|
61
|
+
return fetchWithCache(`/departures/${stationId}`);
|
|
62
|
+
}
|
|
63
|
+
async function getAlerts() {
|
|
64
|
+
return fetchWithCache('/alerts?activeNow=true&includeLabels=true');
|
|
65
|
+
}
|
|
66
|
+
function getFavorites() {
|
|
67
|
+
return config.get('favorites');
|
|
68
|
+
}
|
|
69
|
+
function addFavorite(id, alias) {
|
|
70
|
+
const favorites = config.get('favorites');
|
|
71
|
+
favorites[id] = alias || '';
|
|
72
|
+
config.set('favorites', favorites);
|
|
73
|
+
}
|
|
74
|
+
function removeFavorite(idOrAlias) {
|
|
75
|
+
const favorites = config.get('favorites');
|
|
76
|
+
// Check if it's an ID
|
|
77
|
+
if (favorites[idOrAlias] !== undefined) {
|
|
78
|
+
delete favorites[idOrAlias];
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Check if it's an alias
|
|
82
|
+
const id = Object.keys(favorites).find(key => favorites[key] === idOrAlias);
|
|
83
|
+
if (id) {
|
|
84
|
+
delete favorites[id];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
config.set('favorites', favorites);
|
|
88
|
+
}
|
|
89
|
+
function resolveAlias(input) {
|
|
90
|
+
const favorites = config.get('favorites');
|
|
91
|
+
// If it's an alias, return the ID
|
|
92
|
+
const id = Object.keys(favorites).find(key => favorites[key] === input);
|
|
93
|
+
if (id)
|
|
94
|
+
return id;
|
|
95
|
+
return input;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../src/commands/alerts.ts"],"names":[],"mappings":"AAIA,wBAAsB,SAAS,CAAC,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,iBAwF3E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cmdAlerts = cmdAlerts;
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
async function cmdAlerts(options) {
|
|
7
|
+
const alerts = await (0, api_1.getAlerts)();
|
|
8
|
+
let filterId = '';
|
|
9
|
+
let filterName = '';
|
|
10
|
+
if (options.station) {
|
|
11
|
+
filterId = (0, api_1.resolveAlias)(options.station);
|
|
12
|
+
const stations = await (0, api_1.getStations)();
|
|
13
|
+
const station = stations.find(s => s.id === filterId);
|
|
14
|
+
filterName = station ? station.name : options.station;
|
|
15
|
+
}
|
|
16
|
+
console.log(utils_1.colors.bold(utils_1.colors.yellow('Service Alerts')));
|
|
17
|
+
if (filterName) {
|
|
18
|
+
console.log(`Filtering for: ${utils_1.colors.bold(filterName)}`);
|
|
19
|
+
}
|
|
20
|
+
console.log(utils_1.colors.dim('──────────────────────────────────────────────────────────'));
|
|
21
|
+
let filteredAlerts = alerts;
|
|
22
|
+
if (filterId) {
|
|
23
|
+
filteredAlerts = alerts.filter(a => a.affectedStations.includes(filterId) ||
|
|
24
|
+
(filterName && a.affectedStationsLabels.some(label => label.toLowerCase().includes(filterName.toLowerCase()))));
|
|
25
|
+
}
|
|
26
|
+
// Deduplicate by title
|
|
27
|
+
const uniqueAlerts = Array.from(new Map(filteredAlerts.map(a => [a.title, a])).values());
|
|
28
|
+
// Sort by start time (newest first)
|
|
29
|
+
uniqueAlerts.sort((a, b) => {
|
|
30
|
+
const startA = a.activePeriods[0]?.start ? new Date(a.activePeriods[0].start).getTime() : 0;
|
|
31
|
+
const startB = b.activePeriods[0]?.start ? new Date(b.activePeriods[0].start).getTime() : 0;
|
|
32
|
+
return startB - startA;
|
|
33
|
+
});
|
|
34
|
+
const total = uniqueAlerts.length;
|
|
35
|
+
const limit = options.all ? total : 5;
|
|
36
|
+
const displayAlerts = uniqueAlerts.slice(0, limit);
|
|
37
|
+
if (total > 0) {
|
|
38
|
+
if (options.all) {
|
|
39
|
+
console.log(utils_1.colors.dim(`Showing all ${utils_1.colors.bold(total.toString())} distinct active alerts.`));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.log(utils_1.colors.dim(`Showing top ${utils_1.colors.bold(displayAlerts.length.toString())} of ${utils_1.colors.bold(total.toString())} distinct active alerts.`));
|
|
43
|
+
}
|
|
44
|
+
console.log('');
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log('No active alerts found.');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
displayAlerts.forEach(a => {
|
|
51
|
+
const start = a.activePeriods[0]?.start;
|
|
52
|
+
const end = a.activePeriods[0]?.end;
|
|
53
|
+
let timeInfo = '';
|
|
54
|
+
if (start) {
|
|
55
|
+
const startFmt = (0, utils_1.formatTime)(start, 'MMM dd h:mm a');
|
|
56
|
+
timeInfo = `🕒 ${utils_1.colors.dim('Start:')} ${startFmt}`;
|
|
57
|
+
}
|
|
58
|
+
if (end) {
|
|
59
|
+
const endFmt = (0, utils_1.formatTime)(end, 'MMM dd h:mm a');
|
|
60
|
+
timeInfo += ` ${utils_1.colors.dim('End:')} ${endFmt}`;
|
|
61
|
+
}
|
|
62
|
+
let scopeInfo = '';
|
|
63
|
+
if (a.affectedLines.length > 0) {
|
|
64
|
+
scopeInfo = utils_1.colors.magenta(`Lines: ${a.affectedLines.join(', ')}`);
|
|
65
|
+
}
|
|
66
|
+
else if (a.affectedStationsLabels.length > 0) {
|
|
67
|
+
let stations = a.affectedStationsLabels.join(', ');
|
|
68
|
+
if (stations.length > 50)
|
|
69
|
+
stations = stations.substring(0, 47) + '...';
|
|
70
|
+
scopeInfo = utils_1.colors.magenta(`Stations: ${stations}`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
scopeInfo = utils_1.colors.dim('General');
|
|
74
|
+
}
|
|
75
|
+
console.log(`${utils_1.colors.yellow('⚠️')} ${utils_1.colors.bold(a.title)}`);
|
|
76
|
+
console.log(` ${timeInfo} • ${scopeInfo}`);
|
|
77
|
+
if (a.description) {
|
|
78
|
+
console.log(` ${utils_1.colors.dim('────────────────────────────────────────────────')}`);
|
|
79
|
+
const cleanDesc = a.description.replace(/\n/g, '\n ');
|
|
80
|
+
console.log(` ${cleanDesc}`);
|
|
81
|
+
}
|
|
82
|
+
console.log('');
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=alerts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alerts.js","sourceRoot":"","sources":["../../src/commands/alerts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board.d.ts","sourceRoot":"","sources":["../../src/commands/board.ts"],"names":[],"mappings":"AAsCA,wBAAsB,QAAQ,CAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,YAAY,GAAG,UAAU,EAC/B,QAAQ,CAAC,EAAE,MAAM,iBAmJpB"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cmdBoard = cmdBoard;
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function normalizeStationName(name) {
|
|
7
|
+
return name.trim().toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
function resolveStationIdByName(stations, stationName, preferredSystem) {
|
|
10
|
+
const normalizedName = normalizeStationName(stationName);
|
|
11
|
+
const exactMatches = stations.filter(s => normalizeStationName(s.name) === normalizedName);
|
|
12
|
+
if (preferredSystem) {
|
|
13
|
+
const sameSystemMatches = exactMatches.filter(s => s.system === preferredSystem);
|
|
14
|
+
if (sameSystemMatches.length > 0)
|
|
15
|
+
return sameSystemMatches[0].id;
|
|
16
|
+
}
|
|
17
|
+
return exactMatches[0]?.id;
|
|
18
|
+
}
|
|
19
|
+
function formatRideDuration(startTime, endTime) {
|
|
20
|
+
if (!startTime || !endTime)
|
|
21
|
+
return undefined;
|
|
22
|
+
const diffMs = new Date(endTime).getTime() - new Date(startTime).getTime();
|
|
23
|
+
if (!Number.isFinite(diffMs) || diffMs <= 0)
|
|
24
|
+
return undefined;
|
|
25
|
+
const totalMinutes = Math.round(diffMs / 60000);
|
|
26
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
27
|
+
const minutes = totalMinutes % 60;
|
|
28
|
+
if (hours === 0)
|
|
29
|
+
return `${minutes}m`;
|
|
30
|
+
return `${hours}h ${String(minutes).padStart(2, '0')}m`;
|
|
31
|
+
}
|
|
32
|
+
async function cmdBoard(stationId, mode, filterId) {
|
|
33
|
+
const resolvedId = (0, api_1.resolveAlias)(stationId);
|
|
34
|
+
const resolvedFilterId = filterId ? (0, api_1.resolveAlias)(filterId) : undefined;
|
|
35
|
+
const stations = await (0, api_1.getStations)();
|
|
36
|
+
const station = stations.find(s => s.id === resolvedId);
|
|
37
|
+
const stationName = station ? station.name : resolvedId;
|
|
38
|
+
const filterStation = resolvedFilterId ? stations.find(s => s.id === resolvedFilterId) : undefined;
|
|
39
|
+
const filterName = filterStation ? filterStation.name : resolvedFilterId;
|
|
40
|
+
let departures = await (0, api_1.getDepartures)(resolvedId);
|
|
41
|
+
// Filter based on mode
|
|
42
|
+
if (mode === 'departures') {
|
|
43
|
+
departures = departures.filter(d => d.destination !== stationName);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
departures = departures.filter(d => d.destination === stationName);
|
|
47
|
+
}
|
|
48
|
+
// Filter by destination/origin if provided
|
|
49
|
+
if (resolvedFilterId && filterName) {
|
|
50
|
+
if (mode === 'departures') {
|
|
51
|
+
departures = departures.filter(d => d.destination.toLowerCase().includes(filterName.toLowerCase()));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// Arrivals origin filter logic (from bash script)
|
|
55
|
+
departures = departures.filter(d => {
|
|
56
|
+
const routeMatch = (d.routeLongName?.toLowerCase().includes(filterName.toLowerCase()) ||
|
|
57
|
+
d.routeShortName?.toLowerCase().includes(filterName.toLowerCase()));
|
|
58
|
+
// Hub logic from bash
|
|
59
|
+
const isHub = resolvedFilterId === 'MNR-1' || resolvedFilterId === 'LIRR-1';
|
|
60
|
+
if (isHub && d.direction === 'Outbound')
|
|
61
|
+
return true;
|
|
62
|
+
return routeMatch;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Sort by departure time
|
|
67
|
+
departures.sort((a, b) => new Date(a.departureTime).getTime() - new Date(b.departureTime).getTime());
|
|
68
|
+
const tripLookups = new Map();
|
|
69
|
+
if (mode === 'departures') {
|
|
70
|
+
const destinationStationIds = Array.from(new Set(departures
|
|
71
|
+
.map(d => resolveStationIdByName(stations, d.destination, station?.system))
|
|
72
|
+
.filter((id) => Boolean(id))));
|
|
73
|
+
const destinationBoards = await Promise.all(destinationStationIds.map(async (id) => [id, await (0, api_1.getDepartures)(id)]));
|
|
74
|
+
destinationBoards.forEach(([id, board]) => {
|
|
75
|
+
tripLookups.set(id, new Map(board
|
|
76
|
+
.filter(item => Boolean(item.tripId))
|
|
77
|
+
.map(item => [item.tripId, item])));
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (mode === 'arrivals' && resolvedFilterId) {
|
|
81
|
+
const originBoard = await (0, api_1.getDepartures)(resolvedFilterId);
|
|
82
|
+
tripLookups.set(resolvedFilterId, new Map(originBoard
|
|
83
|
+
.filter(item => Boolean(item.tripId))
|
|
84
|
+
.map(item => [item.tripId, item])));
|
|
85
|
+
}
|
|
86
|
+
const title = mode === 'departures' ? 'Departures' : 'Arrivals';
|
|
87
|
+
console.log(`${utils_1.colors.bold(utils_1.colors.blue(title))} for ${utils_1.colors.bold(`${stationName} (${resolvedId})`)}`);
|
|
88
|
+
if (filterName) {
|
|
89
|
+
const label = mode === 'departures' ? 'Destination' : 'Origin';
|
|
90
|
+
console.log(utils_1.colors.dim(`${label}: ${filterName} (${resolvedFilterId})`));
|
|
91
|
+
}
|
|
92
|
+
console.log(utils_1.colors.dim('──────────────────────────────────────────────────────────'));
|
|
93
|
+
departures.forEach(d => {
|
|
94
|
+
const timeFmt = (0, utils_1.formatTime)(d.departureTime);
|
|
95
|
+
const metadata = [];
|
|
96
|
+
let statusColor = utils_1.colors.green;
|
|
97
|
+
if (d.status.includes('Delayed'))
|
|
98
|
+
statusColor = utils_1.colors.yellow;
|
|
99
|
+
else if (d.status.includes('Cancel'))
|
|
100
|
+
statusColor = utils_1.colors.red;
|
|
101
|
+
else if (d.status.includes('Due'))
|
|
102
|
+
statusColor = utils_1.colors.green;
|
|
103
|
+
let destDisplay = d.destination;
|
|
104
|
+
if (mode === 'arrivals') {
|
|
105
|
+
let originGuess = '';
|
|
106
|
+
if (d.direction === 'Outbound') {
|
|
107
|
+
if (resolvedId.startsWith('MNR'))
|
|
108
|
+
originGuess = 'Grand Central';
|
|
109
|
+
if (resolvedId.startsWith('LIRR'))
|
|
110
|
+
originGuess = 'New York';
|
|
111
|
+
}
|
|
112
|
+
if (originGuess === stationName)
|
|
113
|
+
originGuess = '';
|
|
114
|
+
if (d.destination === stationName) {
|
|
115
|
+
destDisplay = originGuess ? `From ${originGuess}` : d.destination;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
destDisplay = originGuess ? `${originGuess} ➤ ${d.destination}` : `Continues to ${d.destination}`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (mode === 'departures') {
|
|
122
|
+
const destinationStationId = resolveStationIdByName(stations, d.destination, station?.system);
|
|
123
|
+
const destinationStop = destinationStationId ? tripLookups.get(destinationStationId)?.get(d.tripId ?? '') : undefined;
|
|
124
|
+
const rideDuration = formatRideDuration(d.departureTime, destinationStop?.departureTime);
|
|
125
|
+
if (rideDuration)
|
|
126
|
+
metadata.push(utils_1.colors.dim(`Ride ${rideDuration}`));
|
|
127
|
+
}
|
|
128
|
+
if (mode === 'arrivals' && resolvedFilterId) {
|
|
129
|
+
const originStop = tripLookups.get(resolvedFilterId)?.get(d.tripId ?? '');
|
|
130
|
+
if (originStop) {
|
|
131
|
+
metadata.push(utils_1.colors.dim(`Dep ${(0, utils_1.formatTime)(originStop.departureTime)}`));
|
|
132
|
+
const rideDuration = formatRideDuration(originStop.departureTime, d.departureTime);
|
|
133
|
+
if (rideDuration)
|
|
134
|
+
metadata.push(utils_1.colors.dim(`Ride ${rideDuration}`));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const peakStr = d.peakStatus && d.peakStatus !== 'null' ? ` ${utils_1.colors.dim(`(${d.peakStatus})`)}` : '';
|
|
138
|
+
const lineInfo = d.routeLongName && d.routeLongName !== 'null' ? ` ${utils_1.colors.magenta(`[Line: ${d.routeLongName}]`)}` : '';
|
|
139
|
+
const metadataStr = metadata.length > 0 ? ` ${utils_1.colors.dim('•')} ${metadata.join(` ${utils_1.colors.dim('•')} `)}` : '';
|
|
140
|
+
console.log(`${utils_1.colors.cyan(timeFmt.padEnd(15))} ${utils_1.colors.dim('│')} ${utils_1.colors.bold(destDisplay)}${peakStr}${lineInfo}`);
|
|
141
|
+
const trackDisplay = d.track && d.track !== '-' && d.track !== 'null' ? `Track ${utils_1.colors.bold(d.track)}` : utils_1.colors.dim('No Track');
|
|
142
|
+
const tripDisplay = d.tripId ? ` ${utils_1.colors.dim(`(Train #${d.tripId})`)}` : '';
|
|
143
|
+
console.log(` ${utils_1.colors.dim('│')} ${statusColor(d.status.padEnd(14))} ${trackDisplay}${metadataStr}${tripDisplay}`);
|
|
144
|
+
console.log('');
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=board.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board.js","sourceRoot":"","sources":["../../src/commands/board.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"favorites.d.ts","sourceRoot":"","sources":["../../src/commands/favorites.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,iBAgC5E;AAED,wBAAsB,OAAO,kBA2B5B"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cmdFavorite = cmdFavorite;
|
|
4
|
+
exports.cmdFavs = cmdFavs;
|
|
5
|
+
const api_1 = require("../api");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
async function cmdFavorite(subcmd, id, alias) {
|
|
8
|
+
if (subcmd === 'add') {
|
|
9
|
+
if (!id) {
|
|
10
|
+
console.error(utils_1.colors.red('Usage: gotrain favs add <station-id> [alias]'));
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
(0, api_1.addFavorite)(id, alias);
|
|
14
|
+
console.log(`${utils_1.colors.green('Added/Updated')} ${utils_1.colors.bold(id)} ${utils_1.colors.green('to favorites')}${alias ? ` with alias '${utils_1.colors.bold(alias)}'` : ''} ${utils_1.colors.green('✅')}`);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (subcmd === 'remove' || subcmd === 'rm') {
|
|
18
|
+
if (!id) {
|
|
19
|
+
console.error(utils_1.colors.red('Usage: gotrain favs rm <station-id|alias>'));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const resolved = (0, api_1.resolveAlias)(id);
|
|
23
|
+
(0, api_1.removeFavorite)(resolved);
|
|
24
|
+
console.log(`${utils_1.colors.red('Removed')} ${utils_1.colors.bold(resolved)} ${utils_1.colors.red('from favorites')} 🗑️`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Toggle behavior for convenience
|
|
28
|
+
const favorites = (0, api_1.getFavorites)();
|
|
29
|
+
const resolved = (0, api_1.resolveAlias)(subcmd);
|
|
30
|
+
if (favorites[resolved] !== undefined) {
|
|
31
|
+
(0, api_1.removeFavorite)(resolved);
|
|
32
|
+
console.log(`${utils_1.colors.red('Removed')} ${utils_1.colors.bold(resolved)} ${utils_1.colors.red('from favorites')} 🗑️`);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
(0, api_1.addFavorite)(resolved, id); // id here would be alias
|
|
36
|
+
console.log(`${utils_1.colors.green('Added')} ${utils_1.colors.bold(resolved)} ${utils_1.colors.green('to favorites')}${id ? ` (Alias: ${id})` : ''} ✅`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function cmdFavs() {
|
|
40
|
+
console.log(utils_1.colors.bold(utils_1.colors.blue('Favorite Stations')));
|
|
41
|
+
console.log(utils_1.colors.dim('──────────────────────────────────────────────────────────'));
|
|
42
|
+
const favorites = (0, api_1.getFavorites)();
|
|
43
|
+
const stationIds = Object.keys(favorites);
|
|
44
|
+
if (stationIds.length === 0) {
|
|
45
|
+
console.log("No favorites yet. Use 'gotrain favs add <id>' to add.");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const stations = await (0, api_1.getStations)();
|
|
49
|
+
stationIds.forEach(id => {
|
|
50
|
+
const station = stations.find(s => s.id === id);
|
|
51
|
+
if (station) {
|
|
52
|
+
const alias = favorites[id];
|
|
53
|
+
const aliasDisplay = alias ? ` ${utils_1.colors.magenta(`(Alias: ${alias})`)}` : '';
|
|
54
|
+
const sysIcon = (0, utils_1.getSystemIcon)(station.system);
|
|
55
|
+
console.log(`${sysIcon} ${utils_1.colors.bold(station.system.padEnd(6))} | ${station.name} ${utils_1.colors.dim(`(${station.id})`)}${aliasDisplay}`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// In case station is no longer in the cache but in favorites
|
|
59
|
+
console.log(` Unknown | ${id} ${favorites[id] ? utils_1.colors.magenta(`(Alias: ${favorites[id]})`) : ''}`);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=favorites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"favorites.js","sourceRoot":"","sources":["../../src/commands/favorites.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stations.d.ts","sourceRoot":"","sources":["../../src/commands/stations.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,iBAkB/C"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cmdStations = cmdStations;
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
async function cmdStations(query) {
|
|
7
|
+
const stations = await (0, api_1.getStations)();
|
|
8
|
+
console.log(utils_1.colors.bold(utils_1.colors.blue('NYC Transit Stations')));
|
|
9
|
+
console.log(utils_1.colors.dim('──────────────────────────────────────────────────────────'));
|
|
10
|
+
const filteredStations = query
|
|
11
|
+
? stations.filter(s => s.name.toLowerCase().includes(query.toLowerCase()))
|
|
12
|
+
: stations;
|
|
13
|
+
filteredStations.forEach(s => {
|
|
14
|
+
const sysIcon = (0, utils_1.getSystemIcon)(s.system);
|
|
15
|
+
const accessIcon = (0, utils_1.getAccessIcon)(s.accessibilityStatus);
|
|
16
|
+
const locInfo = s.borough && s.borough !== 'null' ? utils_1.colors.dim(`(${s.borough})`) : '';
|
|
17
|
+
const linesInfo = s.lines.length > 0 ? ` ${utils_1.colors.magenta('Lines: ' + s.lines.join(','))}` : '';
|
|
18
|
+
console.log(`${sysIcon} ${utils_1.colors.bold(s.system)} │ ${s.name} ${locInfo}${linesInfo}${accessIcon} ${utils_1.colors.dim('ID: ' + s.id)}`);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=stations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stations.js","sourceRoot":"","sources":["../../src/commands/stations.ts"],"names":[],"mappings":";;AAIA,kCAkBC;AArBD,gCAA8C;AAC9C,oCAAgE;AAEzD,KAAK,UAAU,WAAW,CAAC,KAAc;IAC5C,MAAM,QAAQ,GAAG,MAAM,IAAA,iBAAW,GAAE,CAAC;IAErC,OAAO,CAAC,GAAG,CAAC,cAAM,CAAC,IAAI,CAAC,cAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,cAAM,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC,CAAC;IAEtF,MAAM,gBAAgB,GAAG,KAAK;QAC1B,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1E,CAAC,CAAC,QAAQ,CAAC;IAEf,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;QACzB,MAAM,OAAO,GAAG,IAAA,qBAAa,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,UAAU,GAAG,IAAA,qBAAa,EAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,cAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,cAAM,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAEhG,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,cAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,OAAO,GAAG,SAAS,GAAG,UAAU,IAAI,cAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACpI,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const stations_1 = require("./commands/stations");
|
|
6
|
+
const board_1 = require("./commands/board");
|
|
7
|
+
const alerts_1 = require("./commands/alerts");
|
|
8
|
+
const favorites_1 = require("./commands/favorites");
|
|
9
|
+
const program = new commander_1.Command();
|
|
10
|
+
const pkg = require('../package.json');
|
|
11
|
+
program
|
|
12
|
+
.name('gotrain')
|
|
13
|
+
.description('Atomic CLI for NYC train departures (MTA, LIRR, MNR)')
|
|
14
|
+
.version(pkg.version);
|
|
15
|
+
program
|
|
16
|
+
.command('stations')
|
|
17
|
+
.alias('s')
|
|
18
|
+
.description('List stations (filter by query)')
|
|
19
|
+
.argument('[query]', 'filter stations by name')
|
|
20
|
+
.action(async (query) => {
|
|
21
|
+
try {
|
|
22
|
+
await (0, stations_1.cmdStations)(query);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
console.error('Error fetching stations:', err instanceof Error ? err.message : err);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
program
|
|
29
|
+
.command('departures')
|
|
30
|
+
.alias('d')
|
|
31
|
+
.description('Show departures')
|
|
32
|
+
.argument('<id>', 'station ID or alias')
|
|
33
|
+
.option('--to <id>', 'destination station ID or alias')
|
|
34
|
+
.action(async (id, options) => {
|
|
35
|
+
try {
|
|
36
|
+
await (0, board_1.cmdBoard)(id, 'departures', options.to);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.error('Error fetching departures:', err instanceof Error ? err.message : err);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
program
|
|
43
|
+
.command('arrivals')
|
|
44
|
+
.alias('ar')
|
|
45
|
+
.description('Show arrivals')
|
|
46
|
+
.argument('<id>', 'station ID or alias')
|
|
47
|
+
.option('--from <id>', 'origin station ID or alias')
|
|
48
|
+
.action(async (id, options) => {
|
|
49
|
+
try {
|
|
50
|
+
await (0, board_1.cmdBoard)(id, 'arrivals', options.from);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
console.error('Error fetching arrivals:', err instanceof Error ? err.message : err);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
program
|
|
57
|
+
.command('alerts')
|
|
58
|
+
.alias('a')
|
|
59
|
+
.description('Show active service alerts')
|
|
60
|
+
.option('-s, --station <id>', 'filter by station ID or alias')
|
|
61
|
+
.option('--all', 'show all alerts instead of top 5')
|
|
62
|
+
.action(async (options) => {
|
|
63
|
+
try {
|
|
64
|
+
await (0, alerts_1.cmdAlerts)(options);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
console.error('Error fetching alerts:', err instanceof Error ? err.message : err);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
program
|
|
71
|
+
.command('favs')
|
|
72
|
+
.alias('fav')
|
|
73
|
+
.description('Manage favorite stations (list, add, remove)')
|
|
74
|
+
.argument('[subcmd|id]', 'subcommand (add, remove, rm) or station ID')
|
|
75
|
+
.argument('[id|alias]', 'station ID for add/remove, or alias if toggle')
|
|
76
|
+
.argument('[alias]', 'alias if add/remove and ID provided')
|
|
77
|
+
.action(async (arg1, arg2, arg3) => {
|
|
78
|
+
try {
|
|
79
|
+
if (!arg1) {
|
|
80
|
+
await (0, favorites_1.cmdFavs)();
|
|
81
|
+
}
|
|
82
|
+
else if (['add', 'remove', 'rm', 'list'].includes(arg1)) {
|
|
83
|
+
if (arg1 === 'list') {
|
|
84
|
+
await (0, favorites_1.cmdFavs)();
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
await (0, favorites_1.cmdFavorite)(arg1, arg2, arg3);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Default toggle/fallback behavior
|
|
92
|
+
await (0, favorites_1.cmdFavorite)(arg1, arg2);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
console.error('Error managing favorites:', err instanceof Error ? err.message : err);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
program.parse();
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
export declare function formatTime(isoString: string | null | undefined, fmt?: string): string;
|
|
3
|
+
export declare const colors: {
|
|
4
|
+
bold: chalk.Chalk;
|
|
5
|
+
dim: chalk.Chalk;
|
|
6
|
+
red: chalk.Chalk;
|
|
7
|
+
green: chalk.Chalk;
|
|
8
|
+
yellow: chalk.Chalk;
|
|
9
|
+
blue: chalk.Chalk;
|
|
10
|
+
magenta: chalk.Chalk;
|
|
11
|
+
cyan: chalk.Chalk;
|
|
12
|
+
nc: chalk.Chalk;
|
|
13
|
+
};
|
|
14
|
+
export declare function getSystemIcon(system: string): string;
|
|
15
|
+
export declare function getAccessIcon(status?: string): string;
|
|
16
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAiBrF;AAED,eAAO,MAAM,MAAM;;;;;;;;;;CAUlB,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED,wBAAgB,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAIrD"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.colors = void 0;
|
|
7
|
+
exports.formatTime = formatTime;
|
|
8
|
+
exports.getSystemIcon = getSystemIcon;
|
|
9
|
+
exports.getAccessIcon = getAccessIcon;
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
function formatTime(isoString, fmt) {
|
|
12
|
+
if (!isoString || isoString === 'null')
|
|
13
|
+
return '--';
|
|
14
|
+
try {
|
|
15
|
+
const date = new Date(isoString);
|
|
16
|
+
if (isNaN(date.getTime()))
|
|
17
|
+
return isoString;
|
|
18
|
+
const options = {
|
|
19
|
+
hour: 'numeric',
|
|
20
|
+
minute: '2-digit',
|
|
21
|
+
hour12: true,
|
|
22
|
+
timeZoneName: 'short'
|
|
23
|
+
};
|
|
24
|
+
return new Intl.DateTimeFormat('en-US', options).format(date);
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
return isoString;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.colors = {
|
|
31
|
+
bold: chalk_1.default.bold,
|
|
32
|
+
dim: chalk_1.default.gray,
|
|
33
|
+
red: chalk_1.default.red,
|
|
34
|
+
green: chalk_1.default.green,
|
|
35
|
+
yellow: chalk_1.default.yellow,
|
|
36
|
+
blue: chalk_1.default.blue,
|
|
37
|
+
magenta: chalk_1.default.magenta,
|
|
38
|
+
cyan: chalk_1.default.cyan,
|
|
39
|
+
nc: chalk_1.default.reset,
|
|
40
|
+
};
|
|
41
|
+
function getSystemIcon(system) {
|
|
42
|
+
switch (system.toUpperCase()) {
|
|
43
|
+
case 'SUBWAY': return '🟦';
|
|
44
|
+
case 'LIRR': return '🟩';
|
|
45
|
+
case 'MNR': return '🟥';
|
|
46
|
+
default: return ' ';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function getAccessIcon(status) {
|
|
50
|
+
if (status === 'Fully Accessible')
|
|
51
|
+
return ' ♿';
|
|
52
|
+
if (status === 'Partially Accessible')
|
|
53
|
+
return ' ⚠️';
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;;;;AAEA,gCAiBC;AAcD,sCAOC;AAED,sCAIC;AA9CD,kDAA0B;AAE1B,SAAgB,UAAU,CAAC,SAAoC,EAAE,GAAY;IACzE,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACpD,IAAI,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;QACjC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAAE,OAAO,SAAS,CAAC;QAE5C,MAAM,OAAO,GAA+B;YACxC,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,IAAI;YACZ,YAAY,EAAE,OAAO;SACxB,CAAC;QAEF,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC;AAEY,QAAA,MAAM,GAAG;IAClB,IAAI,EAAE,eAAK,CAAC,IAAI;IAChB,GAAG,EAAE,eAAK,CAAC,IAAI;IACf,GAAG,EAAE,eAAK,CAAC,GAAG;IACd,KAAK,EAAE,eAAK,CAAC,KAAK;IAClB,MAAM,EAAE,eAAK,CAAC,MAAM;IACpB,IAAI,EAAE,eAAK,CAAC,IAAI;IAChB,OAAO,EAAE,eAAK,CAAC,OAAO;IACtB,IAAI,EAAE,eAAK,CAAC,IAAI;IAChB,EAAE,EAAE,eAAK,CAAC,KAAK;CAClB,CAAC;AAEF,SAAgB,aAAa,CAAC,MAAc;IACxC,QAAQ,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;QAC3B,KAAK,QAAQ,CAAC,CAAC,OAAO,IAAI,CAAC;QAC3B,KAAK,MAAM,CAAC,CAAC,OAAO,IAAI,CAAC;QACzB,KAAK,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC;QACxB,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC;IACzB,CAAC;AACL,CAAC;AAED,SAAgB,aAAa,CAAC,MAAe;IACzC,IAAI,MAAM,KAAK,kBAAkB;QAAE,OAAO,IAAI,CAAC;IAC/C,IAAI,MAAM,KAAK,sBAAsB;QAAE,OAAO,KAAK,CAAC;IACpD,OAAO,EAAE,CAAC;AACd,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gotrain",
|
|
3
|
+
"version": "1.2.4",
|
|
4
|
+
"description": "Atomic CLI for MTA system train departures (NYC Subway, LIRR, Metro-North)",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"gotrain": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"CHANGELOG.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"directories": {
|
|
16
|
+
"test": "tests"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "rimraf dist && tsc",
|
|
20
|
+
"postbuild": "chmod +x dist/index.js",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
22
|
+
"test": "npm run build && jest",
|
|
23
|
+
"start": "node dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/gumadeiras/gotrain-cli.git"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"mta",
|
|
31
|
+
"nyc",
|
|
32
|
+
"subway",
|
|
33
|
+
"lirr",
|
|
34
|
+
"mnr",
|
|
35
|
+
"metro-north",
|
|
36
|
+
"train",
|
|
37
|
+
"departures",
|
|
38
|
+
"arrivals",
|
|
39
|
+
"transit",
|
|
40
|
+
"cli",
|
|
41
|
+
"real-time"
|
|
42
|
+
],
|
|
43
|
+
"author": "",
|
|
44
|
+
"license": "ISC",
|
|
45
|
+
"type": "commonjs",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/gumadeiras/gotrain-cli/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/gumadeiras/gotrain-cli#readme",
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/jest": "^30.0.0",
|
|
52
|
+
"@types/node": "^25.0.10",
|
|
53
|
+
"jest": "^30.2.0",
|
|
54
|
+
"nock": "^14.0.10",
|
|
55
|
+
"rimraf": "^6.1.2",
|
|
56
|
+
"supertest": "^7.2.2",
|
|
57
|
+
"ts-jest": "^29.4.6",
|
|
58
|
+
"ts-node": "^10.9.2",
|
|
59
|
+
"typescript": "^5.9.3"
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"chalk": "^4.1.2",
|
|
63
|
+
"commander": "^14.0.2",
|
|
64
|
+
"conf": "^10.2.0"
|
|
65
|
+
}
|
|
66
|
+
}
|