add skill
This commit is contained in:
149
scripts/query.js
Normal file
149
scripts/query.js
Normal file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Busan Airport Limousine Schedule Query Tool
|
||||
*
|
||||
* Usage:
|
||||
* node query.js <stop-name> # to-airport + from-airport for that stop's line
|
||||
* node query.js <stop-name> --to # to-airport only
|
||||
* node query.js <stop-name> --from # from-airport only
|
||||
* node query.js --from-airport --line 1 # all from-airport departures, line 1
|
||||
* node query.js --from-airport --line 2 # all from-airport departures, line 2
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const DATA = join(__dirname, '../data/schedule.jsonl');
|
||||
|
||||
const trips = readFileSync(DATA, 'utf8')
|
||||
.trim().split('\n')
|
||||
.map(l => JSON.parse(l));
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
if (args.length === 0) {
|
||||
console.error('Usage: node query.js <stop-name>');
|
||||
console.error(' node query.js --from-airport --line 1|2');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const fromAirportFlag = args.includes('--from-airport');
|
||||
const lineFlag = args.includes('--line') ? args[args.indexOf('--line') + 1] : null;
|
||||
const toOnly = args.includes('--to');
|
||||
const fromOnly = args.includes('--from');
|
||||
const stopQuery = args.find(a => !a.startsWith('--') && a !== lineFlag) || null;
|
||||
|
||||
// ── Helper ──────────────────────────────────────────────────────────────────
|
||||
|
||||
function pad(s, n) {
|
||||
return String(s).padEnd(n);
|
||||
}
|
||||
|
||||
function header(title) {
|
||||
console.log(`\n${title}`);
|
||||
console.log('─'.repeat(title.length));
|
||||
}
|
||||
|
||||
// ── From-airport by line (--from-airport --line N) ──────────────────────────
|
||||
|
||||
if (fromAirportFlag && lineFlag) {
|
||||
const line = parseInt(lineFlag);
|
||||
if (line !== 1 && line !== 2) {
|
||||
console.error('--line must be 1 or 2'); process.exit(1);
|
||||
}
|
||||
// Line 1 = pages 3–4, Line 2 = pages 5–6
|
||||
const pages = line === 1 ? [3, 4] : [5, 6];
|
||||
const termLabels = { 3: 'Domestic', 4: 'International', 5: 'Domestic', 6: 'International' };
|
||||
const dest = line === 1 ? 'Haeundae/Gijang' : 'Seomyeon/Bujeon';
|
||||
|
||||
header(`[From Airport] Line ${line}: Gimhae Airport → ${dest}`);
|
||||
console.log(`${'Airport dep'.padEnd(14)} ${'Est. arrival'.padEnd(14)} Terminal`);
|
||||
console.log(`${'─'.repeat(14)} ${'─'.repeat(14)} ─────────────`);
|
||||
|
||||
for (const page of pages) {
|
||||
const pageTrips = trips.filter(t => t.page === page).sort((a, b) => {
|
||||
const [ah, am] = a.departure.time.split(':').map(Number);
|
||||
const [bh, bm] = b.departure.time.split(':').map(Number);
|
||||
return (ah * 60 + am) - (bh * 60 + bm);
|
||||
});
|
||||
for (const t of pageTrips) {
|
||||
console.log(`${pad(t.departure.time, 14)} ${pad(t.arrival.time, 14)} ${termLabels[page]}`);
|
||||
}
|
||||
}
|
||||
console.log('\n(arrival times estimated — see arrival_note in schedule.jsonl)');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// ── Stop lookup ──────────────────────────────────────────────────────────────
|
||||
|
||||
if (!stopQuery) {
|
||||
console.error('Provide a stop name or use --from-airport --line 1|2');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Find all to-airport trips where the stop appears (partial match)
|
||||
const matchedTrips = trips.filter(t =>
|
||||
t.direction === 'to_airport' &&
|
||||
t.all_stops.some(s => s.stop.includes(stopQuery))
|
||||
);
|
||||
|
||||
if (matchedTrips.length === 0) {
|
||||
console.error(`No stops found matching "${stopQuery}"`);
|
||||
console.error('Line 1 stops: 반얀트리 아난티코브 오시리아 장산역 해운대온천사거리 해운대해수욕장 동백섬입구 한화리조트해운대 파크하얏트부산 요트경기장 벡스코 신세계센텀시티 상수도남부사업소');
|
||||
console.error('Line 2 stops: 부전시장 부전역 서면/롯데호텔백화점 동의대역 주례역');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Determine which line this stop belongs to
|
||||
const line = matchedTrips[0].page === 1 ? 1 : 2;
|
||||
const dest = line === 1 ? 'Haeundae/Gijang' : 'Seomyeon/Bujeon';
|
||||
|
||||
// Find the canonical matched stop name
|
||||
const matchedStopName = matchedTrips[0].all_stops.find(s => s.stop.includes(stopQuery)).stop;
|
||||
|
||||
// ── To-airport section ───────────────────────────────────────────────────────
|
||||
|
||||
if (!fromOnly) {
|
||||
const sorted = [...matchedTrips].sort((a, b) => {
|
||||
const sa = a.all_stops.find(s => s.stop.includes(stopQuery));
|
||||
const sb = b.all_stops.find(s => s.stop.includes(stopQuery));
|
||||
const [ah, am] = sa.time.split(':').map(Number);
|
||||
const [bh, bm] = sb.time.split(':').map(Number);
|
||||
return (ah * 60 + am) - (bh * 60 + bm);
|
||||
});
|
||||
|
||||
header(`[To Airport] Line ${line}: ${matchedStopName} → Gimhae Airport`);
|
||||
console.log(`${'Dep'.padEnd(10)} ${'Airport arr (est)'.padEnd(18)}`);
|
||||
console.log(`${'─'.repeat(10)} ${'─'.repeat(18)}`);
|
||||
|
||||
for (const t of sorted) {
|
||||
const stopEntry = t.all_stops.find(s => s.stop.includes(stopQuery));
|
||||
console.log(`${pad(stopEntry.time, 10)} ${t.arrival.time}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ── From-airport section ─────────────────────────────────────────────────────
|
||||
|
||||
if (!toOnly) {
|
||||
const pages = line === 1 ? [3, 4] : [5, 6];
|
||||
const termLabels = { 3: 'Dom', 4: 'Int\'l', 5: 'Dom', 6: 'Int\'l' };
|
||||
|
||||
header(`[From Airport] Line ${line}: Gimhae Airport → ${dest}`);
|
||||
console.log(`${'Airport dep'.padEnd(14)} ${'Est. arrival'.padEnd(14)} Terminal`);
|
||||
console.log(`${'─'.repeat(14)} ${'─'.repeat(14)} ────────`);
|
||||
|
||||
const fromTrips = trips
|
||||
.filter(t => pages.includes(t.page))
|
||||
.sort((a, b) => {
|
||||
const [ah, am] = a.departure.time.split(':').map(Number);
|
||||
const [bh, bm] = b.departure.time.split(':').map(Number);
|
||||
return (ah * 60 + am) - (bh * 60 + bm);
|
||||
});
|
||||
|
||||
for (const t of fromTrips) {
|
||||
console.log(`${pad(t.departure.time, 14)} ${pad(t.arrival.time, 14)} ${termLabels[t.page]}`);
|
||||
}
|
||||
|
||||
console.log('\n(arrival times estimated)');
|
||||
}
|
||||
Reference in New Issue
Block a user