njtransit 1.0.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.
- checksums.yaml +7 -0
- data/.claude/commands/njtransit.md +196 -0
- data/.mcp.json.example +12 -0
- data/.mcp.json.sample +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +87 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +37 -0
- data/CLAUDE.md +159 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +148 -0
- data/Rakefile +12 -0
- data/docs/plans/2025-01-24-njtransit-gem-design.md +112 -0
- data/docs/plans/2026-01-24-bus-api-design.md +119 -0
- data/docs/plans/2026-01-24-gtfs-implementation.md +2216 -0
- data/docs/plans/2026-01-24-gtfs-loader-design.md +351 -0
- data/docs/superpowers/plans/2026-03-26-dev-infra-and-agent.md +480 -0
- data/lefthook.yml +17 -0
- data/lib/njtransit/client.rb +291 -0
- data/lib/njtransit/configuration.rb +49 -0
- data/lib/njtransit/error.rb +50 -0
- data/lib/njtransit/gtfs/database.rb +145 -0
- data/lib/njtransit/gtfs/importer.rb +124 -0
- data/lib/njtransit/gtfs/models/route.rb +59 -0
- data/lib/njtransit/gtfs/models/stop.rb +63 -0
- data/lib/njtransit/gtfs/queries/routes_between.rb +62 -0
- data/lib/njtransit/gtfs/queries/schedule.rb +75 -0
- data/lib/njtransit/gtfs.rb +119 -0
- data/lib/njtransit/railtie.rb +9 -0
- data/lib/njtransit/resources/base.rb +35 -0
- data/lib/njtransit/resources/bus/enrichment.rb +105 -0
- data/lib/njtransit/resources/bus.rb +95 -0
- data/lib/njtransit/resources/bus_gtfs.rb +34 -0
- data/lib/njtransit/resources/rail.rb +47 -0
- data/lib/njtransit/resources/rail_gtfs.rb +27 -0
- data/lib/njtransit/tasks.rb +74 -0
- data/lib/njtransit/version.rb +5 -0
- data/lib/njtransit.rb +40 -0
- data/sig/njtransit.rbs +4 -0
- metadata +177 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
# NJTransit Gem: Dev Infra Alignment + Terminal Agent — Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Align njtransit gem's dev infrastructure (linting, CI, hooks) with the tenor project's patterns, and create a Claude Code terminal agent that can answer real-time NJ Transit questions.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Four independent workstreams: (1) RuboCop + Gemfile cleanup, (2) GitHub Actions CI upgrade, (3) lefthook alignment, (4) Claude Code slash command agent. The first three are infrastructure — no Ruby code changes. The fourth is a new `.claude/commands/njtransit.md` file that teaches Claude how to use the gem's API.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** RuboCop, RSpec, Lefthook, GitHub Actions, Claude Code custom commands
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## File Structure
|
|
14
|
+
|
|
15
|
+
| File | Action | Purpose |
|
|
16
|
+
|------|--------|---------|
|
|
17
|
+
| `.rubocop.yml` | Modify | Tighten config, add rubocop-rspec |
|
|
18
|
+
| `Gemfile` | Modify | Add rubocop-rspec dev dependency |
|
|
19
|
+
| `.github/workflows/ci.yml` | Modify | Add RuboCop caching, update action versions, add dependabot |
|
|
20
|
+
| `.github/dependabot.yml` | Create | Weekly dependency updates (matches tenor) |
|
|
21
|
+
| `lefthook.yml` | Modify | Add `parallel: true` to pre-push (minor alignment) |
|
|
22
|
+
| `.claude/commands/njtransit.md` | Create | Claude Code slash command for NJ Transit queries |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
### Task 1: RuboCop + Gemfile Alignment
|
|
27
|
+
|
|
28
|
+
**Files:**
|
|
29
|
+
- Modify: `Gemfile`
|
|
30
|
+
- Modify: `.rubocop.yml`
|
|
31
|
+
|
|
32
|
+
- [ ] **Step 1: Add rubocop-rspec to Gemfile**
|
|
33
|
+
|
|
34
|
+
In `Gemfile`, change:
|
|
35
|
+
```ruby
|
|
36
|
+
gem "rubocop", "~> 1.21"
|
|
37
|
+
```
|
|
38
|
+
to:
|
|
39
|
+
```ruby
|
|
40
|
+
gem "rubocop", "~> 1.21"
|
|
41
|
+
gem "rubocop-rspec", "~> 3.0", require: false
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- [ ] **Step 2: Update .rubocop.yml**
|
|
45
|
+
|
|
46
|
+
Replace the full `.rubocop.yml` with:
|
|
47
|
+
```yaml
|
|
48
|
+
require:
|
|
49
|
+
- rubocop-rspec
|
|
50
|
+
|
|
51
|
+
AllCops:
|
|
52
|
+
TargetRubyVersion: 3.2
|
|
53
|
+
NewCops: enable
|
|
54
|
+
SuggestExtensions: false
|
|
55
|
+
|
|
56
|
+
Style/StringLiterals:
|
|
57
|
+
EnforcedStyle: double_quotes
|
|
58
|
+
|
|
59
|
+
Style/StringLiteralsInInterpolation:
|
|
60
|
+
EnforcedStyle: double_quotes
|
|
61
|
+
|
|
62
|
+
Style/Documentation:
|
|
63
|
+
Enabled: false
|
|
64
|
+
|
|
65
|
+
Style/CommentedKeyword:
|
|
66
|
+
Enabled: false
|
|
67
|
+
|
|
68
|
+
Layout/LineLength:
|
|
69
|
+
Max: 120
|
|
70
|
+
|
|
71
|
+
Metrics/BlockLength:
|
|
72
|
+
Exclude:
|
|
73
|
+
- "spec/**/*"
|
|
74
|
+
- "*.gemspec"
|
|
75
|
+
- "lib/njtransit/tasks.rb"
|
|
76
|
+
|
|
77
|
+
# HTTP client code tends to have longer classes/methods
|
|
78
|
+
Metrics/ClassLength:
|
|
79
|
+
Exclude:
|
|
80
|
+
- "lib/njtransit/client.rb"
|
|
81
|
+
- "lib/njtransit/gtfs/database.rb"
|
|
82
|
+
|
|
83
|
+
Metrics/MethodLength:
|
|
84
|
+
Exclude:
|
|
85
|
+
- "lib/njtransit/client.rb"
|
|
86
|
+
|
|
87
|
+
Metrics/AbcSize:
|
|
88
|
+
Exclude:
|
|
89
|
+
- "lib/njtransit/client.rb"
|
|
90
|
+
|
|
91
|
+
Metrics/CyclomaticComplexity:
|
|
92
|
+
Exclude:
|
|
93
|
+
- "lib/njtransit/client.rb"
|
|
94
|
+
|
|
95
|
+
# GTFS database schema is inherently verbose
|
|
96
|
+
Metrics/ModuleLength:
|
|
97
|
+
Exclude:
|
|
98
|
+
- "lib/njtransit/gtfs/database.rb"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Key changes: added `rubocop-rspec` require, reduced line length from 180 to 120.
|
|
102
|
+
|
|
103
|
+
- [ ] **Step 3: Run bundle install**
|
|
104
|
+
|
|
105
|
+
Run: `cd /Users/jravaliya/Code/njtransit && bundle install`
|
|
106
|
+
Expected: Gemfile.lock updated with rubocop-rspec
|
|
107
|
+
|
|
108
|
+
- [ ] **Step 4: Run rubocop to check for new violations**
|
|
109
|
+
|
|
110
|
+
Run: `cd /Users/jravaliya/Code/njtransit && bundle exec rubocop`
|
|
111
|
+
Expected: May have new violations from rubocop-rspec and shorter line length. Fix any that appear.
|
|
112
|
+
|
|
113
|
+
- [ ] **Step 5: Auto-fix what's possible, manually fix the rest**
|
|
114
|
+
|
|
115
|
+
Run: `cd /Users/jravaliya/Code/njtransit && bundle exec rubocop -a`
|
|
116
|
+
Then fix any remaining violations manually. If specific cops are too noisy for existing code, add targeted exclusions to `.rubocop.yml` rather than rewriting working code.
|
|
117
|
+
|
|
118
|
+
- [ ] **Step 6: Verify clean rubocop run**
|
|
119
|
+
|
|
120
|
+
Run: `cd /Users/jravaliya/Code/njtransit && bundle exec rubocop`
|
|
121
|
+
Expected: 0 offenses
|
|
122
|
+
|
|
123
|
+
- [ ] **Step 7: Run rspec to ensure nothing broke**
|
|
124
|
+
|
|
125
|
+
Run: `cd /Users/jravaliya/Code/njtransit && bundle exec rspec`
|
|
126
|
+
Expected: All tests pass
|
|
127
|
+
|
|
128
|
+
- [ ] **Step 8: Commit**
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
cd /Users/jravaliya/Code/njtransit
|
|
132
|
+
git add Gemfile Gemfile.lock .rubocop.yml lib/ spec/
|
|
133
|
+
git commit -m "chore: tighten rubocop config, add rubocop-rspec
|
|
134
|
+
|
|
135
|
+
Reduce max line length to 120, add rubocop-rspec for spec linting.
|
|
136
|
+
Fix all resulting violations.
|
|
137
|
+
|
|
138
|
+
Co-Authored-By: Claude <noreply@anthropic.com>"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### Task 2: GitHub Actions CI Upgrade
|
|
144
|
+
|
|
145
|
+
**Files:**
|
|
146
|
+
- Modify: `.github/workflows/ci.yml`
|
|
147
|
+
- Create: `.github/dependabot.yml`
|
|
148
|
+
|
|
149
|
+
- [ ] **Step 1: Create .ruby-version file**
|
|
150
|
+
|
|
151
|
+
Create `.ruby-version` with content `3.2` (needed for CI cache key and ruby/setup-ruby auto-detection).
|
|
152
|
+
|
|
153
|
+
- [ ] **Step 2: Upgrade ci.yml to match tenor patterns**
|
|
154
|
+
|
|
155
|
+
Replace `.github/workflows/ci.yml` with:
|
|
156
|
+
```yaml
|
|
157
|
+
name: CI
|
|
158
|
+
|
|
159
|
+
on:
|
|
160
|
+
pull_request:
|
|
161
|
+
push:
|
|
162
|
+
branches: [main]
|
|
163
|
+
|
|
164
|
+
jobs:
|
|
165
|
+
lint:
|
|
166
|
+
runs-on: ubuntu-latest
|
|
167
|
+
env:
|
|
168
|
+
RUBOCOP_CACHE_ROOT: tmp/rubocop
|
|
169
|
+
steps:
|
|
170
|
+
- name: Checkout code
|
|
171
|
+
uses: actions/checkout@v4
|
|
172
|
+
|
|
173
|
+
- name: Set up Ruby
|
|
174
|
+
uses: ruby/setup-ruby@v1
|
|
175
|
+
with:
|
|
176
|
+
bundler-cache: true
|
|
177
|
+
|
|
178
|
+
- name: Prepare RuboCop cache
|
|
179
|
+
uses: actions/cache@v4
|
|
180
|
+
env:
|
|
181
|
+
DEPENDENCIES_HASH: ${{ hashFiles('.ruby-version', '**/.rubocop.yml', 'Gemfile.lock') }}
|
|
182
|
+
with:
|
|
183
|
+
path: ${{ env.RUBOCOP_CACHE_ROOT }}
|
|
184
|
+
key: rubocop-${{ runner.os }}-${{ env.DEPENDENCIES_HASH }}-${{ github.ref_name == github.event.repository.default_branch && github.run_id || 'default' }}
|
|
185
|
+
restore-keys: |
|
|
186
|
+
rubocop-${{ runner.os }}-${{ env.DEPENDENCIES_HASH }}-
|
|
187
|
+
|
|
188
|
+
- name: Lint code for consistent style
|
|
189
|
+
run: bundle exec rubocop --parallel -f github
|
|
190
|
+
|
|
191
|
+
test:
|
|
192
|
+
runs-on: ubuntu-latest
|
|
193
|
+
strategy:
|
|
194
|
+
matrix:
|
|
195
|
+
ruby-version: ["3.2", "3.3"]
|
|
196
|
+
steps:
|
|
197
|
+
- name: Checkout code
|
|
198
|
+
uses: actions/checkout@v4
|
|
199
|
+
|
|
200
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
|
201
|
+
uses: ruby/setup-ruby@v1
|
|
202
|
+
with:
|
|
203
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
204
|
+
bundler-cache: true
|
|
205
|
+
|
|
206
|
+
- name: Run RSpec
|
|
207
|
+
run: bundle exec rspec
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Key changes from current: RuboCop caching with `actions/cache@v4`, GitHub-format output (`--parallel -f github`), `.ruby-version` auto-detection, triggers on all PRs (not just to main).
|
|
211
|
+
|
|
212
|
+
- [ ] **Step 2: Create dependabot.yml**
|
|
213
|
+
|
|
214
|
+
Create `.github/dependabot.yml`:
|
|
215
|
+
```yaml
|
|
216
|
+
version: 2
|
|
217
|
+
updates:
|
|
218
|
+
- package-ecosystem: bundler
|
|
219
|
+
directory: "/"
|
|
220
|
+
schedule:
|
|
221
|
+
interval: weekly
|
|
222
|
+
open-pull-requests-limit: 10
|
|
223
|
+
- package-ecosystem: github-actions
|
|
224
|
+
directory: "/"
|
|
225
|
+
schedule:
|
|
226
|
+
interval: weekly
|
|
227
|
+
open-pull-requests-limit: 10
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
- [ ] **Step 4: Commit**
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
cd /Users/jravaliya/Code/njtransit
|
|
234
|
+
git add .ruby-version .github/workflows/ci.yml .github/dependabot.yml
|
|
235
|
+
git commit -m "chore: upgrade CI to match tenor patterns
|
|
236
|
+
|
|
237
|
+
Add RuboCop caching, update to actions/checkout@v6, add dependabot
|
|
238
|
+
for weekly bundler and GH Actions dependency updates.
|
|
239
|
+
|
|
240
|
+
Co-Authored-By: Claude <noreply@anthropic.com>"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
### Task 3: Lefthook Alignment
|
|
246
|
+
|
|
247
|
+
**Files:**
|
|
248
|
+
- Modify: `lefthook.yml`
|
|
249
|
+
|
|
250
|
+
- [ ] **Step 1: Add parallel flag to pre-push**
|
|
251
|
+
|
|
252
|
+
Update `lefthook.yml` to:
|
|
253
|
+
```yaml
|
|
254
|
+
# Lefthook configuration for git hooks
|
|
255
|
+
# Install hooks: bundle exec lefthook install
|
|
256
|
+
# Docs: https://github.com/evilmartians/lefthook
|
|
257
|
+
|
|
258
|
+
pre-commit:
|
|
259
|
+
parallel: true
|
|
260
|
+
commands:
|
|
261
|
+
rubocop:
|
|
262
|
+
glob: "*.rb"
|
|
263
|
+
run: bundle exec rubocop --force-exclusion {staged_files}
|
|
264
|
+
stage_fixed: true
|
|
265
|
+
|
|
266
|
+
pre-push:
|
|
267
|
+
parallel: true
|
|
268
|
+
commands:
|
|
269
|
+
rspec:
|
|
270
|
+
run: bundle exec rspec
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Only change: added `parallel: true` to pre-push block (matches tenor).
|
|
274
|
+
|
|
275
|
+
- [ ] **Step 2: Verify hooks work**
|
|
276
|
+
|
|
277
|
+
Run: `cd /Users/jravaliya/Code/njtransit && bundle exec lefthook run pre-commit`
|
|
278
|
+
Expected: rubocop runs on staged files
|
|
279
|
+
|
|
280
|
+
Run: `cd /Users/jravaliya/Code/njtransit && bundle exec lefthook run pre-push`
|
|
281
|
+
Expected: rspec runs
|
|
282
|
+
|
|
283
|
+
- [ ] **Step 3: Commit**
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
cd /Users/jravaliya/Code/njtransit
|
|
287
|
+
git add lefthook.yml
|
|
288
|
+
git commit -m "chore: align lefthook config with tenor patterns
|
|
289
|
+
|
|
290
|
+
Add parallel: true to pre-push block.
|
|
291
|
+
|
|
292
|
+
Co-Authored-By: Claude <noreply@anthropic.com>"
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
### Task 4: Claude Code NJTransit Terminal Agent
|
|
298
|
+
|
|
299
|
+
**Files:**
|
|
300
|
+
- Create: `.claude/commands/njtransit.md`
|
|
301
|
+
|
|
302
|
+
This is the creative centerpiece. The slash command teaches Claude how to use the njtransit gem to answer real-time transit questions from the terminal.
|
|
303
|
+
|
|
304
|
+
- [ ] **Step 1: Create the commands directory**
|
|
305
|
+
|
|
306
|
+
Run: `mkdir -p /Users/jravaliya/Code/njtransit/.claude/commands`
|
|
307
|
+
|
|
308
|
+
- [ ] **Step 2: Create the agent command file**
|
|
309
|
+
|
|
310
|
+
Create `.claude/commands/njtransit.md`:
|
|
311
|
+
|
|
312
|
+
````markdown
|
|
313
|
+
---
|
|
314
|
+
description: Ask NJ Transit questions - bus arrivals, routes, stops, schedules, light rail. Uses the njtransit gem to query real-time data.
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
You are an NJ Transit assistant. The user is asking a transit question from their terminal. Your job is to answer it by writing and executing Ruby code using the `njtransit` gem in this repository.
|
|
318
|
+
|
|
319
|
+
## Setup
|
|
320
|
+
|
|
321
|
+
The gem is in the current directory. Credentials come from environment variables. Before making any API call, run this setup:
|
|
322
|
+
|
|
323
|
+
```ruby
|
|
324
|
+
require "dotenv"
|
|
325
|
+
Dotenv.load
|
|
326
|
+
|
|
327
|
+
$LOAD_PATH.unshift(File.join(Dir.pwd, "lib"))
|
|
328
|
+
require "njtransit"
|
|
329
|
+
|
|
330
|
+
NJTransit.configure do |config|
|
|
331
|
+
config.username = ENV["NJTRANSIT_USERNAME"]
|
|
332
|
+
config.password = ENV["NJTRANSIT_PASSWORD"]
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
client = NJTransit.client
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
If credentials are missing, tell the user to set `NJTRANSIT_USERNAME` and `NJTRANSIT_PASSWORD` in their `.env` file. They can register at https://developer.njtransit.com/registration
|
|
339
|
+
|
|
340
|
+
## Available API Methods
|
|
341
|
+
|
|
342
|
+
### Bus & Light Rail Routes
|
|
343
|
+
```ruby
|
|
344
|
+
# Get all routes (mode: "BUS", "NLR", "HBLR", "RL", or "ALL")
|
|
345
|
+
# Currently the gem hardcodes BUS mode, so pass mode directly:
|
|
346
|
+
client.bus.routes # BUS routes only
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Directions for a Route
|
|
350
|
+
```ruby
|
|
351
|
+
client.bus.directions(route: "197")
|
|
352
|
+
# => [{"Direction_1"=>"New York", "Direction_2"=>"Willowbrook Mall"}]
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Stops on a Route
|
|
356
|
+
```ruby
|
|
357
|
+
client.bus.stops(route: "197", direction: "New York", enrich: false)
|
|
358
|
+
# => [{"busstopdescription"=>"...", "busstopnumber"=>"..."}]
|
|
359
|
+
# Use name_contains: "keyword" to filter
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Stop Name Lookup
|
|
363
|
+
```ruby
|
|
364
|
+
client.bus.stop_name(stop_number: "19159", enrich: false)
|
|
365
|
+
# => {"stopName"=>"15TH AVE AT BEDFORD ST"}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Real-Time Departures (most useful for "when is my bus?")
|
|
369
|
+
```ruby
|
|
370
|
+
client.bus.departures(stop: "PABT", enrich: false)
|
|
371
|
+
# Returns trips active in next hour
|
|
372
|
+
# Can filter: route: "197", direction: "New York"
|
|
373
|
+
# Response includes: public_route, header (destination), departuretime ("in 18 mins"),
|
|
374
|
+
# lanegate, vehicle_id, passload, sched_dep_time
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Route Trips at a Location
|
|
378
|
+
```ruby
|
|
379
|
+
client.bus.route_trips(location: "PABT", route: "113")
|
|
380
|
+
# Returns scheduled trips with departure times, lane/gate info
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Trip Stops (track a specific bus)
|
|
384
|
+
```ruby
|
|
385
|
+
client.bus.trip_stops(
|
|
386
|
+
internal_trip_number: "19624134",
|
|
387
|
+
sched_dep_time: "6/22/2023 12:50:00 AM"
|
|
388
|
+
)
|
|
389
|
+
# Returns every stop the trip makes with status (Departed/Approaching/etc)
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Nearby Stops
|
|
393
|
+
```ruby
|
|
394
|
+
client.bus.stops_nearby(lat: 40.8523, lon: -74.2567, radius: 2000, enrich: false)
|
|
395
|
+
# radius is in feet. Returns stops with distance
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Nearby Vehicles
|
|
399
|
+
```ruby
|
|
400
|
+
client.bus.vehicles_nearby(lat: 40.8523, lon: -74.2567, radius: 5000, enrich: false)
|
|
401
|
+
# Returns live vehicle positions with route, destination, passenger load
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Locations (terminals/hubs)
|
|
405
|
+
```ruby
|
|
406
|
+
client.bus.locations
|
|
407
|
+
# => [{"bus_terminal_code"=>"PABT", "bus_terminal_name"=>"Port Authority Bus Terminal"}, ...]
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### GTFS Static Data (schedules, offline queries)
|
|
411
|
+
```ruby
|
|
412
|
+
# Only if GTFS data has been imported
|
|
413
|
+
gtfs = NJTransit::GTFS.new
|
|
414
|
+
gtfs.stops.find_by_code("WBRK") # Find a stop
|
|
415
|
+
gtfs.routes.find("197") # Find a route
|
|
416
|
+
gtfs.routes_between(from: "WBRK", to: "PABT") # Routes connecting two stops
|
|
417
|
+
gtfs.schedule(route: "197", stop: "WBRK", date: Date.today) # Full day schedule
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Common Terminal Codes
|
|
421
|
+
|
|
422
|
+
- **PABT** — Port Authority Bus Terminal (Manhattan)
|
|
423
|
+
- **NWKP** — Newark Penn Station
|
|
424
|
+
- **JCSQ** — Journal Square
|
|
425
|
+
- **HOBO** — Hoboken Terminal
|
|
426
|
+
- **SECC** — Secaucus Junction
|
|
427
|
+
|
|
428
|
+
## How to Answer Questions
|
|
429
|
+
|
|
430
|
+
1. **"When is my next bus?"** → Use `departures` with the stop and optionally route. Show departure times, destinations, and vehicle info in a clean table.
|
|
431
|
+
|
|
432
|
+
2. **"What buses go from X to Y?"** → Use GTFS `routes_between` if available, otherwise use `routes` + `stops` to find matching routes.
|
|
433
|
+
|
|
434
|
+
3. **"What stops are near me?"** → Ask for their location or use a known landmark's coordinates with `stops_nearby`.
|
|
435
|
+
|
|
436
|
+
4. **"Where is the 197 bus right now?"** → Use `vehicles_nearby` with a wide radius, filtered by route in the results.
|
|
437
|
+
|
|
438
|
+
5. **"What's the schedule for route X?"** → Use `departures` for real-time, or GTFS `schedule` for the full day.
|
|
439
|
+
|
|
440
|
+
## Response Style
|
|
441
|
+
|
|
442
|
+
- Be concise — the user is in a terminal, probably in a hurry
|
|
443
|
+
- Format departure times as a clean table
|
|
444
|
+
- Highlight the NEXT departure prominently
|
|
445
|
+
- Include passenger load info when available (EMPTY, LIGHT, MODERATE, HEAVY)
|
|
446
|
+
- If enrichment fails (GTFS not imported), use `enrich: false` and still return results
|
|
447
|
+
- Always use `enrich: false` to avoid GTFS dependency unless the user specifically asks for enriched data
|
|
448
|
+
|
|
449
|
+
## User's Question
|
|
450
|
+
|
|
451
|
+
$ARGUMENTS
|
|
452
|
+
````
|
|
453
|
+
|
|
454
|
+
- [ ] **Step 3: Test the command works**
|
|
455
|
+
|
|
456
|
+
From the njtransit directory, run: `/njtransit what routes are available?`
|
|
457
|
+
Verify Claude picks up the command and attempts to use the gem.
|
|
458
|
+
|
|
459
|
+
- [ ] **Step 4: Commit**
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
cd /Users/jravaliya/Code/njtransit
|
|
463
|
+
git add .claude/commands/njtransit.md
|
|
464
|
+
git commit -m "feat: add Claude Code terminal agent for NJ Transit queries
|
|
465
|
+
|
|
466
|
+
New /njtransit slash command lets you ask transit questions from terminal.
|
|
467
|
+
Supports real-time departures, route lookup, nearby stops, vehicle tracking,
|
|
468
|
+
and GTFS schedule queries via the njtransit gem.
|
|
469
|
+
|
|
470
|
+
Co-Authored-By: Claude <noreply@anthropic.com>"
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Execution Order
|
|
476
|
+
|
|
477
|
+
Tasks 1-3 are independent infrastructure and can be parallelized.
|
|
478
|
+
Task 4 (agent) is also independent but is the most creative piece.
|
|
479
|
+
|
|
480
|
+
Recommended: run all 4 in parallel if using subagent-driven development.
|
data/lefthook.yml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Lefthook configuration for git hooks
|
|
2
|
+
# Install hooks: bundle exec lefthook install
|
|
3
|
+
# Docs: https://github.com/evilmartians/lefthook
|
|
4
|
+
|
|
5
|
+
pre-commit:
|
|
6
|
+
parallel: true
|
|
7
|
+
commands:
|
|
8
|
+
rubocop:
|
|
9
|
+
glob: "*.rb"
|
|
10
|
+
run: bundle exec rubocop --force-exclusion {staged_files}
|
|
11
|
+
stage_fixed: true
|
|
12
|
+
|
|
13
|
+
pre-push:
|
|
14
|
+
parallel: true
|
|
15
|
+
commands:
|
|
16
|
+
rspec:
|
|
17
|
+
run: bundle exec rspec
|