@dodo-planet/cli 0.1.5 → 0.1.7

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.
Files changed (3) hide show
  1. package/README.md +2 -1
  2. package/dist/index.js +327 -22
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -63,7 +63,8 @@ dodo completion fish > ~/.config/fish/completions/dodo.fish
63
63
  - `baby` — list/info/add/update/status/note/delete
64
64
  - `flight` / `hotel` / `activity` / `transfer` — search
65
65
  - `place` — search/search-text/details
66
- - `directions` / `weather` / `flight-status` / `web`single
66
+ - `directions` — show/briefing (briefing은 한국 자동차 경로 턴바이턴 브리핑 카카오모빌리티)
67
+ - `weather` / `flight-status` / `web` — single
67
68
  - `family` / `friend` / `invite`
68
69
  - `chat` — AI 자연어 (서버 SSE 프록시)
69
70
  - `raw <function_name> --data '{...}'` — escape hatch
package/dist/index.js CHANGED
@@ -225,7 +225,8 @@ async function executeFunction(name, args = {}, options = {}) {
225
225
  name,
226
226
  args,
227
227
  tripId: options.tripId,
228
- locale: options.locale
228
+ locale: options.locale,
229
+ userLocation: options.userLocation
229
230
  },
230
231
  headers: options.confirmDestructive ? { "x-dodo-confirm": "yes" } : void 0
231
232
  });
@@ -423,14 +424,17 @@ var init_function_catalog_shared = __esm({
423
424
  "src/lib/function-catalog-shared.ts"() {
424
425
  "use strict";
425
426
  FUNCTION_CATALOG = [
426
- // ── 외부 검색 / 정보 조회 (read-only, 11개)
427
+ // ── 외부 검색 / 정보 조회 (read-only, 14개)
427
428
  { name: "get_weather", category: "weather", verb: "show", requiresTrip: false, isWrite: false, isDestructive: false },
428
429
  { name: "get_flight_status", category: "flight", verb: "status", requiresTrip: false, isWrite: false, isDestructive: false },
429
430
  { name: "search_nearby_places", category: "place", verb: "search", requiresTrip: false, isWrite: false, isDestructive: false },
430
431
  { name: "search_places_text", category: "place", verb: "search-text", requiresTrip: false, isWrite: false, isDestructive: false },
431
432
  { name: "get_place_details", category: "place", verb: "details", requiresTrip: false, isWrite: false, isDestructive: false },
433
+ { name: "get_place_overview", category: "place", verb: "overview", requiresTrip: false, isWrite: false, isDestructive: false },
432
434
  { name: "get_directions", category: "directions", verb: "show", requiresTrip: false, isWrite: false, isDestructive: false },
435
+ { name: "get_car_route_briefing", category: "directions", verb: "briefing", requiresTrip: false, isWrite: false, isDestructive: false },
433
436
  { name: "search_flights", category: "flight", verb: "search", requiresTrip: false, isWrite: false, isDestructive: false },
437
+ { name: "find_cheapest_flight_dates", category: "flight", verb: "cheapest-dates", requiresTrip: false, isWrite: false, isDestructive: false },
434
438
  { name: "search_hotels", category: "hotel", verb: "search", requiresTrip: true, isWrite: false, isDestructive: false },
435
439
  { name: "search_transfers", category: "transfer", verb: "search", requiresTrip: true, isWrite: false, isDestructive: false },
436
440
  { name: "search_activities", category: "activity", verb: "search", requiresTrip: true, isWrite: false, isDestructive: false },
@@ -478,7 +482,19 @@ var init_function_catalog_shared = __esm({
478
482
  { name: "get_travel_profile", category: "profile", verb: "show", requiresTrip: false, isWrite: false, isDestructive: false },
479
483
  { name: "update_travel_profile_section", category: "profile", verb: "update", requiresTrip: false, isWrite: true, isDestructive: false },
480
484
  { name: "finalize_travel_profile", category: "profile", verb: "finalize", requiresTrip: false, isWrite: false, isDestructive: false, isBuilderOnly: true },
481
- { name: "clear_travel_profile", category: "profile", verb: "clear", requiresTrip: false, isWrite: true, isDestructive: true }
485
+ { name: "clear_travel_profile", category: "profile", verb: "clear", requiresTrip: false, isWrite: true, isDestructive: true },
486
+ // ── 한국 로컬 (Phase C+D, 10개 — koreaSignal 래치 + 키 게이트로 노출)
487
+ { name: "get_subway_arrivals", category: "korea", verb: "subway-arrivals", requiresTrip: false, isWrite: false, isDestructive: false },
488
+ { name: "get_bus_arrivals", category: "korea", verb: "bus-arrivals", requiresTrip: false, isWrite: false, isDestructive: false },
489
+ { name: "get_station_info", category: "korea", verb: "station-info", requiresTrip: false, isWrite: false, isDestructive: false },
490
+ { name: "get_air_quality", category: "korea", verb: "air-quality", requiresTrip: false, isWrite: false, isDestructive: false },
491
+ { name: "get_night_clinics", category: "korea", verb: "night-clinics", requiresTrip: false, isWrite: false, isDestructive: false },
492
+ { name: "get_kids_places", category: "korea", verb: "kids-places", requiresTrip: false, isWrite: false, isDestructive: false },
493
+ { name: "get_surroundings", category: "korea", verb: "surroundings", requiresTrip: false, isWrite: false, isDestructive: false },
494
+ { name: "get_barrier_free_info", category: "korea", verb: "barrier-free", requiresTrip: false, isWrite: false, isDestructive: false },
495
+ { name: "get_bike_stations", category: "korea", verb: "bike-stations", requiresTrip: false, isWrite: false, isDestructive: false },
496
+ { name: "where_am_i", category: "korea", verb: "where-am-i", requiresTrip: false, isWrite: false, isDestructive: false },
497
+ { name: "get_transit_route", category: "korea", verb: "transit-route", requiresTrip: false, isWrite: false, isDestructive: false }
482
498
  ];
483
499
  CATALOG_BY_NAME = new Map(
484
500
  FUNCTION_CATALOG.map((meta) => [meta.name, meta])
@@ -545,7 +561,8 @@ async function runFunctionCommand(opts) {
545
561
  const result = await executeFunction(opts.function, opts.args, {
546
562
  tripId,
547
563
  locale,
548
- confirmDestructive: meta.isDestructive
564
+ confirmDestructive: meta.isDestructive,
565
+ userLocation: opts.userLocation
549
566
  });
550
567
  if (ctx.mode === "json") {
551
568
  emitJsonOk(result);
@@ -589,7 +606,7 @@ var init_command_helpers = __esm({
589
606
  });
590
607
 
591
608
  // src/index.ts
592
- import { defineCommand as defineCommand17, runMain } from "citty";
609
+ import { defineCommand as defineCommand18, runMain } from "citty";
593
610
 
594
611
  // src/commands/auth.ts
595
612
  init_credentials();
@@ -2198,9 +2215,48 @@ var transferSearch = defineCommand8({
2198
2215
  });
2199
2216
  }
2200
2217
  });
2218
+ var flightCheapestDates = defineCommand8({
2219
+ meta: { name: "cheapest-dates", description: "\uB178\uC120 \uCD5C\uC800\uAC00 \uB0A0\uC9DC \uCC3E\uAE30 (\uCE90\uC2DC \uAC00\uACA9). --return-month\uB85C \uC655\uBCF5 \uC870\uD569." },
2220
+ args: {
2221
+ from: { type: "positional", required: true, description: "\uCD9C\uBC1C IATA (\uC608: ICN)" },
2222
+ to: { type: "positional", required: true, description: "\uB3C4\uCC29 IATA (\uC608: NRT)" },
2223
+ "depart-month": { type: "string", description: "\uCD9C\uBC1C \uC6D4 YYYY-MM (\uAE30\uBCF8 \uB2E4\uC74C \uB2EC)" },
2224
+ "return-month": { type: "string", description: "\uADC0\uAD6D \uC6D4 YYYY-MM (\uC9C0\uC815 \uC2DC \uC655\uBCF5 \uCD5C\uC800\uAC00 \uC870\uD569)" },
2225
+ locale: { type: "string", description: "ko|en|es|fr" },
2226
+ output: { type: "string", description: "pretty | json" }
2227
+ },
2228
+ async run({ args }) {
2229
+ await runFunctionCommand({
2230
+ function: "find_cheapest_flight_dates",
2231
+ args: {
2232
+ origin: args.from,
2233
+ destination: args.to,
2234
+ departure_month: args["depart-month"],
2235
+ return_month: args["return-month"]
2236
+ },
2237
+ outputFlag: args.output,
2238
+ localeFlag: args.locale,
2239
+ noTripContext: true,
2240
+ formatResponse: (data, ctx) => {
2241
+ const c = colorize(ctx);
2242
+ const err = unwrap(data, "error");
2243
+ if (err) return printLine(c.dim(err));
2244
+ const message = unwrap(data, "message");
2245
+ if (message) printLine(message);
2246
+ const items = unwrap(data, "trips") ?? unwrap(data, "dates") ?? [];
2247
+ if (!items.length) return printLine(c.dim("\uACB0\uACFC \uC5C6\uC74C."));
2248
+ for (const d of items.slice(0, 12)) {
2249
+ const label = [d.departDate ?? d.date, d.returnDate].filter(Boolean).join(" \u2192 ");
2250
+ const price = d.price != null ? ` \xB7 ${d.price}` : "";
2251
+ printLine(` ${label}${price}`);
2252
+ }
2253
+ }
2254
+ });
2255
+ }
2256
+ });
2201
2257
  var flightCommand = defineCommand8({
2202
- meta: { name: "flight", description: "\uD56D\uACF5\uD3B8 \uAC80\uC0C9 / \uC0C1\uD0DC \uC870\uD68C." },
2203
- subCommands: { search: flightSearch }
2258
+ meta: { name: "flight", description: "\uD56D\uACF5\uD3B8 \uAC80\uC0C9 / \uCD5C\uC800\uAC00 \uB0A0\uC9DC / \uC0C1\uD0DC \uC870\uD68C." },
2259
+ subCommands: { search: flightSearch, "cheapest-dates": flightCheapestDates }
2204
2260
  });
2205
2261
  var hotelCommand = defineCommand8({
2206
2262
  meta: { name: "hotel", description: "\uD638\uD154 \uAC80\uC0C9." },
@@ -2295,18 +2351,47 @@ var placeDetails = defineCommand9({
2295
2351
  });
2296
2352
  }
2297
2353
  });
2354
+ var placeOverview = defineCommand9({
2355
+ meta: { name: "overview", description: "\uD55C\uAD6D \uAD00\uAD11\uC9C0 \uACF5\uC2DD \uC18C\uAC1C\uBB38 (TourAPI, \uC5ED\uC0AC\xB7\uD2B9\uC9D5\xB7\uC774\uC6A9\uC548\uB0B4)." },
2356
+ args: {
2357
+ placeName: { type: "positional", required: true, description: "\uC7A5\uC18C \uC774\uB984 (\uC608: \uACBD\uBCF5\uAD81, \uAD6D\uB9BD\uC911\uC559\uBC15\uBB3C\uAD00)" },
2358
+ locale: { type: "string", description: "ko|en|es|fr|it" },
2359
+ output: { type: "string", description: "pretty | json" }
2360
+ },
2361
+ async run({ args }) {
2362
+ await runFunctionCommand({
2363
+ function: "get_place_overview",
2364
+ args: { place_name: args.placeName },
2365
+ outputFlag: args.output,
2366
+ localeFlag: args.locale,
2367
+ noTripContext: true,
2368
+ formatResponse: (data, ctx) => {
2369
+ const c = colorize(ctx);
2370
+ const err = unwrap(data, "error");
2371
+ if (err) return printLine(c.dim(err));
2372
+ const d = data.data ?? data;
2373
+ printLine(c.bold(String(d.name ?? args.placeName)));
2374
+ const meta = [d.category, d.address].filter(Boolean).join(" \xB7 ");
2375
+ if (meta) printLine(c.dim(meta));
2376
+ if (d.overview) printLine(String(d.overview));
2377
+ else printLine(c.dim("\uB4F1\uB85D\uB41C \uACF5\uC2DD \uC18C\uAC1C\uBB38\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
2378
+ if (d.homepage) printLine(c.dim(String(d.homepage)));
2379
+ }
2380
+ });
2381
+ }
2382
+ });
2298
2383
  var placeCommand = defineCommand9({
2299
- meta: { name: "place", description: "\uC7A5\uC18C \uAC80\uC0C9/\uC0C1\uC138." },
2300
- subCommands: { search: placeSearch, "search-text": placeSearchText, details: placeDetails }
2384
+ meta: { name: "place", description: "\uC7A5\uC18C \uAC80\uC0C9/\uC0C1\uC138/\uC18C\uAC1C." },
2385
+ subCommands: { search: placeSearch, "search-text": placeSearchText, details: placeDetails, overview: placeOverview }
2301
2386
  });
2302
- var directionsCommand = defineCommand9({
2303
- meta: { name: "directions", description: "\uACBD\uB85C \uC548\uB0B4." },
2387
+ var directionsShow = defineCommand9({
2388
+ meta: { name: "show", description: "\uB300\uC911\uAD50\uD1B5/\uC790\uB3D9\uCC28/\uB3C4\uBCF4 \uACBD\uB85C \uC548\uB0B4 (Google Maps)." },
2304
2389
  args: {
2305
2390
  from: { type: "string", required: true, description: "\uCD9C\uBC1C\uC9C0" },
2306
2391
  to: { type: "string", required: true, description: "\uB3C4\uCC29\uC9C0" },
2307
2392
  mode: { type: "string", description: "transit|driving|walking|bicycling" },
2308
2393
  avoid: { type: "string", description: "tolls,highways (\uCF64\uB9C8)" },
2309
- locale: { type: "string", description: "ko|en|es|fr" },
2394
+ locale: { type: "string", description: "ko|en|es|fr|it" },
2310
2395
  output: { type: "string", description: "pretty | json" }
2311
2396
  },
2312
2397
  async run({ args }) {
@@ -2327,6 +2412,38 @@ var directionsCommand = defineCommand9({
2327
2412
  });
2328
2413
  }
2329
2414
  });
2415
+ var directionsBriefing = defineCommand9({
2416
+ meta: { name: "briefing", description: "\uD55C\uAD6D \uC790\uB3D9\uCC28 \uACBD\uB85C \uD134\uBC14\uC774\uD134 \uBE0C\uB9AC\uD551 (\uCE74\uCE74\uC624\uBAA8\uBE4C\uB9AC\uD2F0)." },
2417
+ args: {
2418
+ destination: { type: "positional", required: true, description: "\uBAA9\uC801\uC9C0 \uC7A5\uC18C\uBA85/\uC8FC\uC18C" },
2419
+ origin: { type: "string", description: "\uCD9C\uBC1C\uC9C0 \uC7A5\uC18C\uBA85/\uC8FC\uC18C" },
2420
+ locale: { type: "string", description: "ko|en|es|fr|it" },
2421
+ output: { type: "string", description: "pretty | json" }
2422
+ },
2423
+ async run({ args }) {
2424
+ await runFunctionCommand({
2425
+ function: "get_car_route_briefing",
2426
+ args: { origin: args.origin, destination: args.destination },
2427
+ outputFlag: args.output,
2428
+ localeFlag: args.locale,
2429
+ noTripContext: true,
2430
+ formatResponse: (data, ctx) => {
2431
+ const c = colorize(ctx);
2432
+ const summary = unwrap(data, "summary");
2433
+ const guides = unwrap(data, "guides") ?? [];
2434
+ const err = unwrap(data, "error");
2435
+ if (err) return printLine(c.dim(err));
2436
+ if (!summary) return printLine(c.dim("\uACBD\uB85C \uC5C6\uC74C."));
2437
+ printLine(`${summary.distanceText} \xB7 \uC57D ${summary.durationMinutes}\uBD84 \xB7 \uC608\uC0C1 \uD0DD\uC2DC\uBE44 ${summary.taxiFare?.toLocaleString()}\uC6D0`);
2438
+ for (const g of guides) printLine(` - ${g.guidance} (${g.distanceText})`);
2439
+ }
2440
+ });
2441
+ }
2442
+ });
2443
+ var directionsCommand = defineCommand9({
2444
+ meta: { name: "directions", description: "\uACBD\uB85C \uC548\uB0B4." },
2445
+ subCommands: { show: directionsShow, briefing: directionsBriefing }
2446
+ });
2330
2447
  var weatherCommand = defineCommand9({
2331
2448
  meta: { name: "weather", description: "\uB0A0\uC528 \uC870\uD68C." },
2332
2449
  args: {
@@ -2813,10 +2930,183 @@ var webCommand = defineCommand13({
2813
2930
  }
2814
2931
  });
2815
2932
 
2816
- // src/commands/raw.ts
2933
+ // src/commands/korea.ts
2817
2934
  init_command_helpers();
2818
2935
  import { defineCommand as defineCommand14 } from "citty";
2819
- var rawCommand = defineCommand14({
2936
+ function formatKorea(data, ctx) {
2937
+ const c = colorize(ctx);
2938
+ const err = unwrap(data, "error");
2939
+ if (err) {
2940
+ printLine(c.dim(err));
2941
+ return;
2942
+ }
2943
+ const message = unwrap(data, "message");
2944
+ if (message) printLine(message);
2945
+ const base = unwrap(data, "basePlace");
2946
+ const count = unwrap(data, "count");
2947
+ if (base) printLine(c.dim(base));
2948
+ if (typeof count === "number") printLine(c.dim(`${count}\uAC74`));
2949
+ if (count === 0) {
2950
+ printLine(c.dim("\uACB0\uACFC \uC5C6\uC74C."));
2951
+ return;
2952
+ }
2953
+ const body = data.data ?? data;
2954
+ const rest = { ...body };
2955
+ for (const k of ["error", "message", "basePlace", "count"]) delete rest[k];
2956
+ if (Object.keys(rest).length) printLine(c.dim(JSON.stringify(rest, null, 2)));
2957
+ }
2958
+ function coords(lat, lng) {
2959
+ if (lat == null || lng == null) return void 0;
2960
+ const la = Number(lat);
2961
+ const ln = Number(lng);
2962
+ if (!Number.isFinite(la) || !Number.isFinite(ln)) return void 0;
2963
+ return { lat: la, lng: ln };
2964
+ }
2965
+ function placeBasedCommand(opts) {
2966
+ return defineCommand14({
2967
+ meta: { name: opts.name, description: opts.description },
2968
+ args: {
2969
+ place: { type: "positional", required: false, description: "\uAE30\uC900 \uC9C0\uBA85\xB7\uC7A5\uC18C (\uBE44\uC6B0\uBA74 --lat/--lng \uC88C\uD45C \uAE30\uC900)" },
2970
+ lat: { type: "string", description: "\uC704\uB3C4 (place \uC5C6\uC744 \uB54C \uD604\uC7AC \uC704\uCE58 \uB300\uCCB4)" },
2971
+ lng: { type: "string", description: "\uACBD\uB3C4 (place \uC5C6\uC744 \uB54C \uD604\uC7AC \uC704\uCE58 \uB300\uCCB4)" },
2972
+ locale: { type: "string", description: "ko|en|es|fr|it" },
2973
+ output: { type: "string", description: "pretty | json" }
2974
+ },
2975
+ async run({ args }) {
2976
+ await runFunctionCommand({
2977
+ function: opts.fn,
2978
+ args: { place: args.place },
2979
+ outputFlag: args.output,
2980
+ localeFlag: args.locale,
2981
+ noTripContext: true,
2982
+ userLocation: coords(args.lat, args.lng),
2983
+ formatResponse: formatKorea
2984
+ });
2985
+ }
2986
+ });
2987
+ }
2988
+ var subwayArrivals = placeBasedCommand({
2989
+ name: "subway-arrivals",
2990
+ fn: "get_subway_arrivals",
2991
+ description: "\uC9C0\uD558\uCCA0 \uC2E4\uC2DC\uAC04 \uB3C4\uCC29 (\uAE30\uC900 \uC9C0\uBA85 \uC8FC\uBCC0 \uCD5C\uB300 3\uC5ED)."
2992
+ });
2993
+ var busArrivals = placeBasedCommand({
2994
+ name: "bus-arrivals",
2995
+ fn: "get_bus_arrivals",
2996
+ description: "\uC2DC\uB0B4\uBC84\uC2A4 \uB3C4\uCC29 \uC815\uBCF4 (\uAE30\uC900 \uC9C0\uBA85 \uC8FC\uBCC0 \uCD5C\uB300 5\uC815\uB958\uC18C)."
2997
+ });
2998
+ var airQuality = placeBasedCommand({
2999
+ name: "air-quality",
3000
+ fn: "get_air_quality",
3001
+ description: "\uC2E4\uC2DC\uAC04 \uACF5\uAE30\uC9C8 (\uD1B5\uD569\uB300\uAE30\uD658\uACBD\uC9C0\uC218\xB7PM10\xB7PM2.5)."
3002
+ });
3003
+ var nightClinics = placeBasedCommand({
3004
+ name: "night-clinics",
3005
+ fn: "get_night_clinics",
3006
+ description: "\uC18C\uC544 \uC57C\uAC04\xB7\uD734\uC77C \uC9C4\uB8CC(\uB2EC\uBE5B\uC5B4\uB9B0\uC774\uBCD1\uC6D0) + \uD604\uC7AC \uC9C4\uB8CC \uC0C1\uD0DC."
3007
+ });
3008
+ var kidsPlaces = placeBasedCommand({
3009
+ name: "kids-places",
3010
+ fn: "get_kids_places",
3011
+ description: "\uC544\uC774 \uB180 \uACF3(\uD0A4\uC988\uCE74\uD398\xB7\uB180\uC774\uD130\xB7\uC5B4\uB9B0\uC774\uACF5\uC6D0, \uC2E4\uB0B4/\uC2E4\uC678)."
3012
+ });
3013
+ var surroundings = placeBasedCommand({
3014
+ name: "surroundings",
3015
+ fn: "get_surroundings",
3016
+ description: "\uC8FC\uBCC0 \uB458\uB7EC\uBCF4\uAE30 (\uBC18\uACBD 500m \uD3B8\uC758\uC2DC\uC124\xB7\uAC70\uB9AC\xB7\uBC29\uC704)."
3017
+ });
3018
+ var barrierFree = placeBasedCommand({
3019
+ name: "barrier-free",
3020
+ fn: "get_barrier_free_info",
3021
+ description: "\uBB34\uC7A5\uC560(\uBC30\uB9AC\uC5B4\uD504\uB9AC) \uAD00\uAD11 \uD3B8\uC758\uC2DC\uC124 \uC815\uBCF4."
3022
+ });
3023
+ var bikeStations = placeBasedCommand({
3024
+ name: "bike-stations",
3025
+ fn: "get_bike_stations",
3026
+ description: "\uC11C\uC6B8 \uB530\uB989\uC774 \uB300\uC5EC\uC18C \uC2E4\uC2DC\uAC04 \uB300\uC5EC \uAC00\uB2A5 \uC218 (\uC11C\uC6B8\uB9CC)."
3027
+ });
3028
+ var stationInfo = defineCommand14({
3029
+ meta: { name: "station-info", description: "\uC9C0\uD558\uCCA0\uC5ED \uC885\uD569 \uC815\uBCF4(\uB178\uC120\xB7\uD658\uC2B9\xB7\uAD50\uD1B5\uC57D\uC790 \uD3B8\uC758\uC2DC\uC124)." },
3030
+ args: {
3031
+ station: { type: "positional", required: true, description: "\uC5ED \uC774\uB984 (\uC608: \uAC15\uB0A8, \uC11C\uC6B8\uC5ED)" },
3032
+ locale: { type: "string", description: "ko|en|es|fr|it" },
3033
+ output: { type: "string", description: "pretty | json" }
3034
+ },
3035
+ async run({ args }) {
3036
+ await runFunctionCommand({
3037
+ function: "get_station_info",
3038
+ args: { station_name: args.station },
3039
+ outputFlag: args.output,
3040
+ localeFlag: args.locale,
3041
+ noTripContext: true,
3042
+ formatResponse: formatKorea
3043
+ });
3044
+ }
3045
+ });
3046
+ var whereAmI = defineCommand14({
3047
+ meta: { name: "where-am-i", description: "\uC88C\uD45C \uAE30\uC900 \uC704\uCE58 \uC815\uBCF4(\uD589\uC815\uB3D9\xB7\uB3C4\uB85C\uBA85\xB7\uAC00\uAE4C\uC6B4 \uC5ED\xB7\uB79C\uB4DC\uB9C8\uD06C). --lat/--lng \uD544\uC694." },
3048
+ args: {
3049
+ lat: { type: "string", description: "\uC704\uB3C4 (\uD544\uC218, CLI\uB294 GPS \uBBF8\uC9C0\uC6D0)" },
3050
+ lng: { type: "string", description: "\uACBD\uB3C4 (\uD544\uC218, CLI\uB294 GPS \uBBF8\uC9C0\uC6D0)" },
3051
+ locale: { type: "string", description: "ko|en|es|fr|it" },
3052
+ output: { type: "string", description: "pretty | json" }
3053
+ },
3054
+ async run({ args }) {
3055
+ await runFunctionCommand({
3056
+ function: "where_am_i",
3057
+ args: {},
3058
+ outputFlag: args.output,
3059
+ localeFlag: args.locale,
3060
+ noTripContext: true,
3061
+ userLocation: coords(args.lat, args.lng),
3062
+ formatResponse: formatKorea
3063
+ });
3064
+ }
3065
+ });
3066
+ var transitRoute = defineCommand14({
3067
+ meta: { name: "transit-route", description: "\uB300\uC911\uAD50\uD1B5 \uACBD\uB85C(\uBC84\uC2A4\xB7\uC9C0\uD558\uCCA0 \uD658\uC2B9, ODsay): \uC18C\uC694\xB7\uC694\uAE08\xB7\uD658\uC2B9." },
3068
+ args: {
3069
+ destination: { type: "positional", required: true, description: "\uBAA9\uC801\uC9C0 \uC7A5\uC18C\uBA85/\uC8FC\uC18C" },
3070
+ from: { type: "string", description: "\uCD9C\uBC1C\uC9C0 \uC7A5\uC18C\uBA85/\uC8FC\uC18C" },
3071
+ current: { type: "boolean", default: false, description: "\uCD9C\uBC1C\uC9C0\uB97C --lat/--lng \uC88C\uD45C\uB85C \uC0AC\uC6A9" },
3072
+ lat: { type: "string", description: "\uCD9C\uBC1C \uC704\uB3C4 (--current\uC640 \uD568\uAED8)" },
3073
+ lng: { type: "string", description: "\uCD9C\uBC1C \uACBD\uB3C4 (--current\uC640 \uD568\uAED8)" },
3074
+ locale: { type: "string", description: "ko|en|es|fr|it" },
3075
+ output: { type: "string", description: "pretty | json" }
3076
+ },
3077
+ async run({ args }) {
3078
+ await runFunctionCommand({
3079
+ function: "get_transit_route",
3080
+ args: { origin: args.from, destination: args.destination, useCurrentLocation: args.current || void 0 },
3081
+ outputFlag: args.output,
3082
+ localeFlag: args.locale,
3083
+ noTripContext: true,
3084
+ userLocation: coords(args.lat, args.lng),
3085
+ formatResponse: formatKorea
3086
+ });
3087
+ }
3088
+ });
3089
+ var koreaCommand = defineCommand14({
3090
+ meta: { name: "korea", description: "\uD55C\uAD6D \uB85C\uCEEC \uC870\uD68C (\uC9C0\uD558\uCCA0\xB7\uBC84\uC2A4\xB7\uACF5\uAE30\uC9C8\xB7\uBB34\uC7A5\uC560\xB7\uB530\uB989\uC774 \uB4F1)." },
3091
+ subCommands: {
3092
+ "subway-arrivals": subwayArrivals,
3093
+ "bus-arrivals": busArrivals,
3094
+ "station-info": stationInfo,
3095
+ "air-quality": airQuality,
3096
+ "night-clinics": nightClinics,
3097
+ "kids-places": kidsPlaces,
3098
+ surroundings,
3099
+ "barrier-free": barrierFree,
3100
+ "bike-stations": bikeStations,
3101
+ "where-am-i": whereAmI,
3102
+ "transit-route": transitRoute
3103
+ }
3104
+ });
3105
+
3106
+ // src/commands/raw.ts
3107
+ init_command_helpers();
3108
+ import { defineCommand as defineCommand15 } from "citty";
3109
+ var rawCommand = defineCommand15({
2820
3110
  meta: {
2821
3111
  name: "raw",
2822
3112
  description: "\uD568\uC218\uB97C \uC774\uB984\uC73C\uB85C \uC9C1\uC811 \uD638\uCD9C (escape hatch)."
@@ -2861,7 +3151,7 @@ init_config();
2861
3151
  init_output();
2862
3152
  init_exit_codes();
2863
3153
  init_prompt();
2864
- import { defineCommand as defineCommand15 } from "citty";
3154
+ import { defineCommand as defineCommand16 } from "citty";
2865
3155
  async function* parseSseStream2(response) {
2866
3156
  if (!response.body) return;
2867
3157
  const reader = response.body.getReader();
@@ -2940,7 +3230,7 @@ async function streamChatTurn(history, options) {
2940
3230
  if (options.mode === "pretty") process.stdout.write("\n");
2941
3231
  return { reply, toolCalls };
2942
3232
  }
2943
- var chatCommand = defineCommand15({
3233
+ var chatCommand = defineCommand16({
2944
3234
  meta: { name: "chat", description: "AI \uCC57 (\uC790\uC5F0\uC5B4 \u2192 \uD568\uC218 \uD638\uCD9C). \uC778\uC790 \uC788\uC73C\uBA74 single-shot." },
2945
3235
  args: {
2946
3236
  prompt: { type: "positional", required: false, description: "\uC9C8\uBB38 (\uC0DD\uB7B5 \uC2DC \uBA40\uD2F0\uD134 REPL)" },
@@ -2991,7 +3281,7 @@ var chatCommand = defineCommand15({
2991
3281
  });
2992
3282
 
2993
3283
  // src/commands/completion.ts
2994
- import { defineCommand as defineCommand16 } from "citty";
3284
+ import { defineCommand as defineCommand17 } from "citty";
2995
3285
  var COMMAND_TREE = {
2996
3286
  auth: ["login", "logout", "whoami", "tokens"],
2997
3287
  config: ["get", "set", "path"],
@@ -3001,18 +3291,31 @@ var COMMAND_TREE = {
3001
3291
  itinerary: ["show", "add", "remove", "reorder"],
3002
3292
  feed: ["list", "post", "delete"],
3003
3293
  baby: ["list", "info", "add", "update", "status", "note", "delete"],
3004
- flight: ["search"],
3294
+ flight: ["search", "cheapest-dates"],
3005
3295
  hotel: ["search"],
3006
3296
  activity: ["search"],
3007
3297
  transfer: ["search"],
3008
- place: ["search", "search-text", "details"],
3298
+ place: ["search", "search-text", "details", "overview"],
3299
+ directions: ["show", "briefing"],
3300
+ korea: [
3301
+ "subway-arrivals",
3302
+ "bus-arrivals",
3303
+ "station-info",
3304
+ "air-quality",
3305
+ "night-clinics",
3306
+ "kids-places",
3307
+ "surroundings",
3308
+ "barrier-free",
3309
+ "bike-stations",
3310
+ "where-am-i",
3311
+ "transit-route"
3312
+ ],
3009
3313
  family: ["list", "add-to-trip"],
3010
3314
  friend: ["list", "add"],
3011
3315
  invite: ["list", "create"]
3012
3316
  };
3013
3317
  var TOP_LEVEL = [
3014
3318
  ...Object.keys(COMMAND_TREE),
3015
- "directions",
3016
3319
  "weather",
3017
3320
  "flight-status",
3018
3321
  "web",
@@ -3089,7 +3392,7 @@ function fishCompletion() {
3089
3392
  }
3090
3393
  return lines.join("\n") + "\n";
3091
3394
  }
3092
- var completionCommand = defineCommand16({
3395
+ var completionCommand = defineCommand17({
3093
3396
  meta: { name: "completion", description: "\uC178 \uC790\uB3D9\uC644\uC131 \uC2A4\uD06C\uB9BD\uD2B8 \uCD9C\uB825 (bash|zsh|fish)." },
3094
3397
  args: {
3095
3398
  shell: { type: "positional", required: true, description: "bash | zsh | fish" }
@@ -3116,7 +3419,7 @@ var completionCommand = defineCommand16({
3116
3419
  });
3117
3420
 
3118
3421
  // src/index.ts
3119
- var main = defineCommand17({
3422
+ var main = defineCommand18({
3120
3423
  meta: {
3121
3424
  name: "dodo",
3122
3425
  version: "0.1.0",
@@ -3144,6 +3447,8 @@ var main = defineCommand17({
3144
3447
  weather: weatherCommand,
3145
3448
  "flight-status": flightStatusCommand,
3146
3449
  web: webCommand,
3450
+ // 한국 로컬
3451
+ korea: koreaCommand,
3147
3452
  // 사회
3148
3453
  family: familyCommand,
3149
3454
  friend: friendCommand,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dodo-planet/cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Dodo Planet CLI — terminal access to family trip data via dodo command",
5
5
  "type": "module",
6
6
  "bin": {