@nomadamas/k-skill 0.1.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.
Files changed (350) hide show
  1. package/bin/k-skill.js +60 -0
  2. package/package.json +37 -0
  3. package/skills/assembly-bill-vote-search/instruction.md +111 -0
  4. package/skills/assembly-bill-vote-search/skill.json +10 -0
  5. package/skills/biz-health-check/instruction.md +69 -0
  6. package/skills/biz-health-check/scripts/biz_health_check.py +163 -0
  7. package/skills/biz-health-check/skill.json +10 -0
  8. package/skills/bok-ecos-stats/instruction.md +95 -0
  9. package/skills/bok-ecos-stats/scripts/bok_ecos.py +302 -0
  10. package/skills/bok-ecos-stats/skill.json +10 -0
  11. package/skills/building-register-search/instruction.md +69 -0
  12. package/skills/building-register-search/scripts/building_register.py +309 -0
  13. package/skills/building-register-search/scripts/building_register_xml.py +32 -0
  14. package/skills/building-register-search/skill.json +9 -0
  15. package/skills/bunjang-search/instruction.md +154 -0
  16. package/skills/bunjang-search/skill.json +10 -0
  17. package/skills/catchtable-sniper/instruction.md +270 -0
  18. package/skills/catchtable-sniper/skill.json +9 -0
  19. package/skills/cheap-gas-nearby/instruction.md +107 -0
  20. package/skills/cheap-gas-nearby/skill.json +10 -0
  21. package/skills/corporate-registration-consulting/instruction.md +117 -0
  22. package/skills/corporate-registration-consulting/scripts/fill_official_hwp.py +106 -0
  23. package/skills/corporate-registration-consulting/skill.json +8 -0
  24. package/skills/coupang-product-search/instruction.md +219 -0
  25. package/skills/coupang-product-search/scripts/coupang_partners_mcp.py +146 -0
  26. package/skills/coupang-product-search/skill.json +10 -0
  27. package/skills/court-auction-notice-search/instruction.md +201 -0
  28. package/skills/court-auction-notice-search/skill.json +9 -0
  29. package/skills/court-payment-order-assistant/instruction.md +120 -0
  30. package/skills/court-payment-order-assistant/skill.json +10 -0
  31. package/skills/d2b-notice-search/instruction.md +117 -0
  32. package/skills/d2b-notice-search/skill.json +10 -0
  33. package/skills/daangn-cars-search/instruction.md +91 -0
  34. package/skills/daangn-cars-search/scripts/daangn_cars.py +72 -0
  35. package/skills/daangn-cars-search/skill.json +9 -0
  36. package/skills/daangn-jobs-search/instruction.md +90 -0
  37. package/skills/daangn-jobs-search/scripts/daangn_jobs.py +98 -0
  38. package/skills/daangn-jobs-search/skill.json +9 -0
  39. package/skills/daangn-realty-search/instruction.md +114 -0
  40. package/skills/daangn-realty-search/scripts/daangn_detail_ld.py +76 -0
  41. package/skills/daangn-realty-search/scripts/daangn_realty.py +216 -0
  42. package/skills/daangn-realty-search/scripts/daangn_relay_store.py +174 -0
  43. package/skills/daangn-realty-search/skill.json +8 -0
  44. package/skills/daangn-used-goods-search/instruction.md +90 -0
  45. package/skills/daangn-used-goods-search/scripts/daangn_used_goods.py +80 -0
  46. package/skills/daangn-used-goods-search/skill.json +9 -0
  47. package/skills/daishin-report-search/instruction.md +138 -0
  48. package/skills/daishin-report-search/skill.json +10 -0
  49. package/skills/daiso-product-search/instruction.md +172 -0
  50. package/skills/daiso-product-search/skill.json +8 -0
  51. package/skills/danawa-price-search/instruction.md +183 -0
  52. package/skills/danawa-price-search/scripts/danawa_search.py +354 -0
  53. package/skills/danawa-price-search/skill.json +8 -0
  54. package/skills/delivery-tracking/instruction.md +358 -0
  55. package/skills/delivery-tracking/skill.json +8 -0
  56. package/skills/donation-place-search/instruction.md +129 -0
  57. package/skills/donation-place-search/skill.json +9 -0
  58. package/skills/emergency-room-beds/instruction.md +82 -0
  59. package/skills/emergency-room-beds/skill.json +8 -0
  60. package/skills/ev-charger-nearby/instruction.md +80 -0
  61. package/skills/ev-charger-nearby/scripts/ev_charger.py +222 -0
  62. package/skills/ev-charger-nearby/skill.json +10 -0
  63. package/skills/ev-subsidy-status/instruction.md +165 -0
  64. package/skills/ev-subsidy-status/skill.json +10 -0
  65. package/skills/express-bus-booking/instruction.md +207 -0
  66. package/skills/express-bus-booking/references/kobus-http-flow.md +159 -0
  67. package/skills/express-bus-booking/scripts/kobus_express_booking.py +243 -0
  68. package/skills/express-bus-booking/skill.json +8 -0
  69. package/skills/fine-dust-location/instruction.md +89 -0
  70. package/skills/fine-dust-location/skill.json +9 -0
  71. package/skills/flight-ticket-search/instruction.md +237 -0
  72. package/skills/flight-ticket-search/scripts/flight_ticket_search.py +501 -0
  73. package/skills/flight-ticket-search/skill.json +9 -0
  74. package/skills/foresttrip-vacancy/instruction.md +167 -0
  75. package/skills/foresttrip-vacancy/scripts/run_foresttrip_vacancy.py +549 -0
  76. package/skills/foresttrip-vacancy/skill.json +10 -0
  77. package/skills/fsc-corporate-info/instruction.md +57 -0
  78. package/skills/fsc-corporate-info/scripts/fsc_corporate_info.py +113 -0
  79. package/skills/fsc-corporate-info/skill.json +10 -0
  80. package/skills/g2b-order-plan-search/instruction.md +131 -0
  81. package/skills/g2b-order-plan-search/scripts/g2b_order_plan.py +158 -0
  82. package/skills/g2b-order-plan-search/skill.json +10 -0
  83. package/skills/g2b-sanctioned-supplier/instruction.md +61 -0
  84. package/skills/g2b-sanctioned-supplier/scripts/g2b_sanctioned_supplier.py +114 -0
  85. package/skills/g2b-sanctioned-supplier/skill.json +10 -0
  86. package/skills/gangnamunni-clinic-search/instruction.md +113 -0
  87. package/skills/gangnamunni-clinic-search/skill.json +9 -0
  88. package/skills/geeknews-search/instruction.md +69 -0
  89. package/skills/geeknews-search/scripts/geeknews_search.py +296 -0
  90. package/skills/geeknews-search/skill.json +8 -0
  91. package/skills/gongsijiga-search/instruction.md +128 -0
  92. package/skills/gongsijiga-search/skill.json +9 -0
  93. package/skills/gov-overseas-trip-report/instruction.md +488 -0
  94. package/skills/gov-overseas-trip-report/scripts/gov_overseas_trip_report.py +1206 -0
  95. package/skills/gov-overseas-trip-report/skill.json +9 -0
  96. package/skills/han-river-water-level/instruction.md +83 -0
  97. package/skills/han-river-water-level/skill.json +10 -0
  98. package/skills/highway-traffic-status/instruction.md +88 -0
  99. package/skills/highway-traffic-status/scripts/highway_traffic.py +315 -0
  100. package/skills/highway-traffic-status/skill.json +11 -0
  101. package/skills/hipass-receipt/instruction.md +97 -0
  102. package/skills/hipass-receipt/skill.json +10 -0
  103. package/skills/hola-poke-yeoksam/instruction.md +247 -0
  104. package/skills/hola-poke-yeoksam/skill.json +8 -0
  105. package/skills/household-waste-info/instruction.md +117 -0
  106. package/skills/household-waste-info/skill.json +10 -0
  107. package/skills/housing-official-price/instruction.md +177 -0
  108. package/skills/housing-official-price/skill.json +10 -0
  109. package/skills/hwp/instruction.md +206 -0
  110. package/skills/hwp/skill.json +8 -0
  111. package/skills/intercity-bus-booking/instruction.md +189 -0
  112. package/skills/intercity-bus-booking/references/tmoney-intercity-http-flow.md +126 -0
  113. package/skills/intercity-bus-booking/scripts/intercity_bus_search.py +381 -0
  114. package/skills/intercity-bus-booking/skill.json +8 -0
  115. package/skills/iros-registry-automation/instruction.md +229 -0
  116. package/skills/iros-registry-automation/scripts/iros_pdf_summary.py +249 -0
  117. package/skills/iros-registry-automation/scripts/upstream.pin +1 -0
  118. package/skills/iros-registry-automation/skill.json +9 -0
  119. package/skills/job-posting-match/instruction.md +130 -0
  120. package/skills/job-posting-match/scripts/job_posting_match.py +396 -0
  121. package/skills/job-posting-match/scripts/test_job_posting_match.py +54 -0
  122. package/skills/job-posting-match/skill.json +8 -0
  123. package/skills/jobkorea-talent-search/instruction.md +118 -0
  124. package/skills/jobkorea-talent-search/scripts/jobkorea_talent_models.py +27 -0
  125. package/skills/jobkorea-talent-search/scripts/jobkorea_talent_parse.py +186 -0
  126. package/skills/jobkorea-talent-search/scripts/jobkorea_talent_search.py +94 -0
  127. package/skills/jobkorea-talent-search/scripts/jobkorea_talent_search_condition.py +136 -0
  128. package/skills/jobkorea-talent-search/scripts/test_jobkorea_talent_search.py +76 -0
  129. package/skills/jobkorea-talent-search/skill.json +9 -0
  130. package/skills/joseon-sillok-search/instruction.md +76 -0
  131. package/skills/joseon-sillok-search/scripts/sillok_search.py +552 -0
  132. package/skills/joseon-sillok-search/skill.json +8 -0
  133. package/skills/k-dart/instruction.md +406 -0
  134. package/skills/k-dart/skill.json +8 -0
  135. package/skills/k-schoollunch-menu/instruction.md +109 -0
  136. package/skills/k-schoollunch-menu/skill.json +9 -0
  137. package/skills/k-skill-cleaner/instruction.md +80 -0
  138. package/skills/k-skill-cleaner/scripts/k_skill_cleaner.py +410 -0
  139. package/skills/k-skill-cleaner/skill.json +8 -0
  140. package/skills/k-skill-setup/instruction.md +253 -0
  141. package/skills/k-skill-setup/skill.json +11 -0
  142. package/skills/kakao-bar-nearby/instruction.md +76 -0
  143. package/skills/kakao-bar-nearby/skill.json +8 -0
  144. package/skills/kakao-map/instruction.md +176 -0
  145. package/skills/kakao-map/skill.json +10 -0
  146. package/skills/kakaotalk-mac/instruction.md +189 -0
  147. package/skills/kakaotalk-mac/skill.json +8 -0
  148. package/skills/kbl-results/instruction.md +89 -0
  149. package/skills/kbl-results/skill.json +9 -0
  150. package/skills/kbo-results/instruction.md +82 -0
  151. package/skills/kbo-results/skill.json +8 -0
  152. package/skills/keris-academic-search/instruction.md +81 -0
  153. package/skills/keris-academic-search/scripts/keris_academic.py +210 -0
  154. package/skills/keris-academic-search/skill.json +10 -0
  155. package/skills/kleague-results/instruction.md +92 -0
  156. package/skills/kleague-results/skill.json +8 -0
  157. package/skills/kopis-performance-search/instruction.md +109 -0
  158. package/skills/kopis-performance-search/skill.json +10 -0
  159. package/skills/korea-weather/instruction.md +93 -0
  160. package/skills/korea-weather/skill.json +10 -0
  161. package/skills/korean-character-count/instruction.md +87 -0
  162. package/skills/korean-character-count/scripts/korean_character_count.js +268 -0
  163. package/skills/korean-character-count/skill.json +8 -0
  164. package/skills/korean-cinema-search/instruction.md +177 -0
  165. package/skills/korean-cinema-search/skill.json +8 -0
  166. package/skills/korean-heritage-search/instruction.md +106 -0
  167. package/skills/korean-heritage-search/scripts/korean_heritage_search.py +321 -0
  168. package/skills/korean-heritage-search/skill.json +8 -0
  169. package/skills/korean-holiday-calendar/instruction.md +97 -0
  170. package/skills/korean-holiday-calendar/skill.json +9 -0
  171. package/skills/korean-humanizer/instruction.md +389 -0
  172. package/skills/korean-humanizer/references/ai-tell-taxonomy.md +147 -0
  173. package/skills/korean-humanizer/skill.json +8 -0
  174. package/skills/korean-jangbu-for/instruction.md +133 -0
  175. package/skills/korean-jangbu-for/scripts/install.sh +237 -0
  176. package/skills/korean-jangbu-for/scripts/upstream.pin +1 -0
  177. package/skills/korean-jangbu-for/skill.json +8 -0
  178. package/skills/korean-law-search/instruction.md +126 -0
  179. package/skills/korean-law-search/skill.json +10 -0
  180. package/skills/korean-marathon-schedule/instruction.md +111 -0
  181. package/skills/korean-marathon-schedule/skill.json +9 -0
  182. package/skills/korean-middle-korean/instruction.md +79 -0
  183. package/skills/korean-middle-korean/scripts/korean_middle_korean.js +214 -0
  184. package/skills/korean-middle-korean/skill.json +8 -0
  185. package/skills/korean-patent-search/instruction.md +79 -0
  186. package/skills/korean-patent-search/scripts/patent_search.py +409 -0
  187. package/skills/korean-patent-search/skill.json +9 -0
  188. package/skills/korean-privacy-terms/instruction.md +128 -0
  189. package/skills/korean-privacy-terms/scripts/install.sh +108 -0
  190. package/skills/korean-privacy-terms/scripts/upstream.pin +1 -0
  191. package/skills/korean-privacy-terms/skill.json +8 -0
  192. package/skills/korean-scholarship-search/instruction.md +317 -0
  193. package/skills/korean-scholarship-search/references/report-format.md +40 -0
  194. package/skills/korean-scholarship-search/references/school-discovery.md +61 -0
  195. package/skills/korean-scholarship-search/references/search-clues.md +58 -0
  196. package/skills/korean-scholarship-search/references/source-patterns.md +67 -0
  197. package/skills/korean-scholarship-search/scripts/scholarship_filter.py +811 -0
  198. package/skills/korean-scholarship-search/scripts/test_scholarship_filter.py +224 -0
  199. package/skills/korean-scholarship-search/scripts/university_search_plan.py +148 -0
  200. package/skills/korean-scholarship-search/skill.json +8 -0
  201. package/skills/korean-slang-writing/instruction.md +181 -0
  202. package/skills/korean-slang-writing/scripts/_slang_http.py +91 -0
  203. package/skills/korean-slang-writing/scripts/slang_lookup.py +291 -0
  204. package/skills/korean-slang-writing/scripts/slang_search.py +284 -0
  205. package/skills/korean-slang-writing/skill.json +8 -0
  206. package/skills/korean-spell-check/instruction.md +105 -0
  207. package/skills/korean-spell-check/scripts/korean_spell_check.py +523 -0
  208. package/skills/korean-spell-check/skill.json +9 -0
  209. package/skills/korean-stock-search/instruction.md +194 -0
  210. package/skills/korean-stock-search/skill.json +10 -0
  211. package/skills/korean-transit-route/instruction.md +113 -0
  212. package/skills/korean-transit-route/skill.json +10 -0
  213. package/skills/kosis-stats/instruction.md +232 -0
  214. package/skills/kosis-stats/references/kosis-openapi-guide.md +171 -0
  215. package/skills/kosis-stats/scripts/run_kosis_stats.py +896 -0
  216. package/skills/kosis-stats/skill.json +9 -0
  217. package/skills/kr-whois-lookup/instruction.md +107 -0
  218. package/skills/kr-whois-lookup/skill.json +10 -0
  219. package/skills/kstartup-search/instruction.md +186 -0
  220. package/skills/kstartup-search/scripts/run_kstartup.py +424 -0
  221. package/skills/kstartup-search/skill.json +11 -0
  222. package/skills/ktx-booking/instruction.md +244 -0
  223. package/skills/ktx-booking/skill.json +10 -0
  224. package/skills/lck-analytics/instruction.md +192 -0
  225. package/skills/lck-analytics/scripts/_lib.js +103 -0
  226. package/skills/lck-analytics/scripts/analyze-live-game.js +52 -0
  227. package/skills/lck-analytics/scripts/build-match-report.js +44 -0
  228. package/skills/lck-analytics/scripts/sync-oracle.js +50 -0
  229. package/skills/lck-analytics/skill.json +9 -0
  230. package/skills/lh-notice-search/instruction.md +206 -0
  231. package/skills/lh-notice-search/skill.json +10 -0
  232. package/skills/library-book-search/instruction.md +139 -0
  233. package/skills/library-book-search/skill.json +9 -0
  234. package/skills/local-election-candidate-search/instruction.md +77 -0
  235. package/skills/local-election-candidate-search/skill.json +8 -0
  236. package/skills/localdata-business-status/instruction.md +64 -0
  237. package/skills/localdata-business-status/scripts/localdata_business_status.py +206 -0
  238. package/skills/localdata-business-status/skill.json +8 -0
  239. package/skills/lotto-results/instruction.md +80 -0
  240. package/skills/lotto-results/skill.json +8 -0
  241. package/skills/lovebug-report/instruction.md +185 -0
  242. package/skills/lovebug-report/skill.json +9 -0
  243. package/skills/market-kurly-search/instruction.md +125 -0
  244. package/skills/market-kurly-search/skill.json +8 -0
  245. package/skills/mfds-drug-safety/instruction.md +86 -0
  246. package/skills/mfds-drug-safety/scripts/mfds_drug_safety.py +184 -0
  247. package/skills/mfds-drug-safety/skill.json +10 -0
  248. package/skills/mfds-food-safety/instruction.md +126 -0
  249. package/skills/mfds-food-safety/scripts/mfds_food_safety.py +281 -0
  250. package/skills/mfds-food-safety/skill.json +10 -0
  251. package/skills/myrealtrip-search/instruction.md +239 -0
  252. package/skills/myrealtrip-search/scripts/myrealtrip_mcp.py +194 -0
  253. package/skills/myrealtrip-search/scripts/test_myrealtrip_mcp.py +99 -0
  254. package/skills/myrealtrip-search/skill.json +9 -0
  255. package/skills/naming-house/instruction.md +146 -0
  256. package/skills/naming-house/skill.json +8 -0
  257. package/skills/national-pension-workplace/instruction.md +64 -0
  258. package/skills/national-pension-workplace/scripts/national_pension_workplace.py +113 -0
  259. package/skills/national-pension-workplace/skill.json +10 -0
  260. package/skills/naver-ad-performance/instruction.md +108 -0
  261. package/skills/naver-ad-performance/scripts/naver_ad_performance.py +240 -0
  262. package/skills/naver-ad-performance/skill.json +9 -0
  263. package/skills/naver-blog-research/instruction.md +128 -0
  264. package/skills/naver-blog-research/scripts/_naver_http.py +58 -0
  265. package/skills/naver-blog-research/scripts/naver_download_images.py +233 -0
  266. package/skills/naver-blog-research/scripts/naver_read.py +256 -0
  267. package/skills/naver-blog-research/scripts/naver_search.py +192 -0
  268. package/skills/naver-blog-research/skill.json +8 -0
  269. package/skills/naver-news-search/instruction.md +103 -0
  270. package/skills/naver-news-search/skill.json +10 -0
  271. package/skills/naver-shopping-search/instruction.md +94 -0
  272. package/skills/naver-shopping-search/skill.json +11 -0
  273. package/skills/nhis-care-checkup-search/instruction.md +116 -0
  274. package/skills/nhis-care-checkup-search/skill.json +10 -0
  275. package/skills/nts-business-registration/instruction.md +115 -0
  276. package/skills/nts-business-registration/scripts/nts_business_registration.py +215 -0
  277. package/skills/nts-business-registration/skill.json +10 -0
  278. package/skills/nts-tax-delinquency/instruction.md +54 -0
  279. package/skills/nts-tax-delinquency/scripts/nts_tax_delinquency.py +150 -0
  280. package/skills/nts-tax-delinquency/skill.json +8 -0
  281. package/skills/ohou-today-deal/instruction.md +182 -0
  282. package/skills/ohou-today-deal/scripts/ohou_today_deal.py +369 -0
  283. package/skills/ohou-today-deal/skill.json +9 -0
  284. package/skills/olive-young-search/instruction.md +154 -0
  285. package/skills/olive-young-search/skill.json +8 -0
  286. package/skills/parking-lot-search/instruction.md +96 -0
  287. package/skills/parking-lot-search/skill.json +9 -0
  288. package/skills/popbill/instruction.md +146 -0
  289. package/skills/popbill/scripts/popbill_cli.py +284 -0
  290. package/skills/popbill/scripts/popbill_registry.py +54 -0
  291. package/skills/popbill/scripts/popbill_safety.py +37 -0
  292. package/skills/popbill/scripts/popbill_templates.py +71 -0
  293. package/skills/popbill/skill.json +9 -0
  294. package/skills/public-restroom-nearby/instruction.md +89 -0
  295. package/skills/public-restroom-nearby/skill.json +9 -0
  296. package/skills/real-estate-search/instruction.md +172 -0
  297. package/skills/real-estate-search/skill.json +10 -0
  298. package/skills/rhwp-advanced/instruction.md +145 -0
  299. package/skills/rhwp-advanced/skill.json +8 -0
  300. package/skills/rhwp-edit/instruction.md +153 -0
  301. package/skills/rhwp-edit/skill.json +8 -0
  302. package/skills/s2b-notice-search/instruction.md +66 -0
  303. package/skills/s2b-notice-search/skill.json +9 -0
  304. package/skills/saju-fortune/instruction.md +177 -0
  305. package/skills/saju-fortune/skill.json +8 -0
  306. package/skills/saramin-talent-search/instruction.md +119 -0
  307. package/skills/saramin-talent-search/skill.json +9 -0
  308. package/skills/seoul-bike/instruction.md +83 -0
  309. package/skills/seoul-bike/scripts/seoul_bike.py +247 -0
  310. package/skills/seoul-bike/skill.json +10 -0
  311. package/skills/seoul-density/instruction.md +109 -0
  312. package/skills/seoul-density/scripts/seoul_density.py +271 -0
  313. package/skills/seoul-density/skill.json +10 -0
  314. package/skills/seoul-subway-arrival/instruction.md +85 -0
  315. package/skills/seoul-subway-arrival/skill.json +9 -0
  316. package/skills/sh-notice-search/instruction.md +150 -0
  317. package/skills/sh-notice-search/skill.json +9 -0
  318. package/skills/srt-booking/instruction.md +181 -0
  319. package/skills/srt-booking/scripts/srt_booking.py +272 -0
  320. package/skills/srt-booking/scripts/srt_seats.py +156 -0
  321. package/skills/srt-booking/skill.json +20 -0
  322. package/skills/subway-lost-property/instruction.md +93 -0
  323. package/skills/subway-lost-property/scripts/subway_lost_property.py +244 -0
  324. package/skills/subway-lost-property/skill.json +8 -0
  325. package/skills/ticket-availability/instruction.md +175 -0
  326. package/skills/ticket-availability/scripts/ticket_availability.py +430 -0
  327. package/skills/ticket-availability/skill.json +9 -0
  328. package/skills/toss-securities/instruction.md +116 -0
  329. package/skills/toss-securities/skill.json +9 -0
  330. package/skills/used-car-price-search/instruction.md +109 -0
  331. package/skills/used-car-price-search/skill.json +8 -0
  332. package/skills/yebigun-training/instruction.md +177 -0
  333. package/skills/yebigun-training/skill.json +9 -0
  334. package/skills/zipcode-search/instruction.md +159 -0
  335. package/skills/zipcode-search/scripts/zipcode_search.py +150 -0
  336. package/skills/zipcode-search/skill.json +8 -0
  337. package/src/assemble.js +134 -0
  338. package/src/detect.js +18 -0
  339. package/templates/action-account.md +4 -0
  340. package/templates/action-booking.md +5 -0
  341. package/templates/action-commerce.md +5 -0
  342. package/templates/action-communication.md +5 -0
  343. package/templates/action-submission.md +5 -0
  344. package/templates/browser.md +4 -0
  345. package/templates/core.md +5 -0
  346. package/templates/hard-boundary.md +3 -0
  347. package/templates/local.md +2 -0
  348. package/templates/lookup.md +2 -0
  349. package/templates/proxy.md +2 -0
  350. package/templates/vault.md +4 -0
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import shlex
8
+ import subprocess
9
+ from dataclasses import asdict, dataclass
10
+ from datetime import date, timedelta
11
+ from typing import Callable
12
+
13
+ LOST112_LIST_URL = "https://www.lost112.go.kr/find/findList.do"
14
+ LOST112_REFERER_URL = "https://www.lost112.go.kr/"
15
+ LOST112_OUTPUT_FILE = "lost112-search-result.html"
16
+ LOST112_CURL_MAX_TIME = 60
17
+ SEOUL_METRO_LOST_CENTER_URL = "https://www.seoulmetro.co.kr/kr/page.do?menuIdx=541"
18
+ CURL_USER_AGENT = "Mozilla/5.0"
19
+
20
+ Runner = Callable[..., subprocess.CompletedProcess[str]]
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class SearchQuery:
25
+ station: str
26
+ item: str | None = None
27
+ line: str | None = None
28
+ start_date: date | None = None
29
+ end_date: date | None = None
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class SearchPlan:
34
+ query: SearchQuery
35
+ payload: dict[str, str]
36
+ suggested_keywords: list[str]
37
+ official_sources: list[dict[str, str]]
38
+ guidance: list[str]
39
+ cautions: list[str]
40
+ curl_example: str
41
+
42
+ def to_dict(self) -> dict[str, object]:
43
+ return {
44
+ "query": {
45
+ **asdict(self.query),
46
+ "start_date": self.query.start_date.isoformat() if self.query.start_date else None,
47
+ "end_date": self.query.end_date.isoformat() if self.query.end_date else None,
48
+ },
49
+ "payload": self.payload,
50
+ "suggested_keywords": self.suggested_keywords,
51
+ "official_sources": self.official_sources,
52
+ "guidance": self.guidance,
53
+ "cautions": self.cautions,
54
+ "curl_example": self.curl_example,
55
+ }
56
+
57
+
58
+ def normalize_station(station: str) -> str:
59
+ normalized = " ".join(station.split())
60
+ if not normalized:
61
+ raise ValueError("station is required")
62
+ return normalized
63
+
64
+
65
+ def expand_station_keywords(station: str) -> list[str]:
66
+ normalized = normalize_station(station)
67
+ keywords = [normalized]
68
+ if normalized.endswith("μ—­") and len(normalized) > 1:
69
+ keywords.append(normalized[:-1])
70
+ return list(dict.fromkeys(keyword for keyword in keywords if keyword))
71
+
72
+
73
+ def build_search_payload(query: SearchQuery) -> dict[str, str]:
74
+ station = normalize_station(query.station)
75
+ if not query.start_date or not query.end_date:
76
+ raise ValueError("start_date and end_date are required")
77
+
78
+ payload = {
79
+ "pageIndex": "1",
80
+ "START_YMD": query.start_date.strftime("%Y%m%d"),
81
+ "END_YMD": query.end_date.strftime("%Y%m%d"),
82
+ "PRDT_NM": (query.item or "").strip(),
83
+ "DEP_PLACE": station,
84
+ "SITE": "V",
85
+ "PLACE_SE_CD": "",
86
+ "FD_LCT_CD": "",
87
+ "FD_SIGUNGU": "",
88
+ "IN_NM": "",
89
+ "ATC_ID": "",
90
+ "F_ATC_ID": "",
91
+ "PRDT_CL_CD01": "",
92
+ "PRDT_CL_CD02": "",
93
+ "PRDT_CL_NM": "",
94
+ "MENU_NO": "",
95
+ }
96
+ return payload
97
+
98
+
99
+ def _base_curl_command(url: str | None, max_time: int, *, follow_redirects: bool = True) -> list[str]:
100
+ command = [
101
+ "curl",
102
+ "-fsS",
103
+ "--http1.1",
104
+ "--tls-max",
105
+ "1.2",
106
+ "--retry",
107
+ "1",
108
+ "--max-time",
109
+ str(max_time),
110
+ "-A",
111
+ CURL_USER_AGENT,
112
+ ]
113
+ if follow_redirects:
114
+ command.insert(2, "-L")
115
+ if url:
116
+ command.append(url)
117
+ return command
118
+
119
+
120
+ def build_curl_command(payload: dict[str, str]) -> str:
121
+ command = _base_curl_command("", LOST112_CURL_MAX_TIME, follow_redirects=False)
122
+ command.extend(["--referer", LOST112_REFERER_URL])
123
+ for key, value in payload.items():
124
+ if value:
125
+ command.extend(["--data-urlencode", f"{key}={value}"])
126
+ command.extend(["--output", LOST112_OUTPUT_FILE])
127
+ command.append(LOST112_LIST_URL)
128
+ return " ".join(shlex.quote(part) for part in command)
129
+
130
+
131
+ def probe_source(name: str, url: str, runner: Runner = subprocess.run) -> dict[str, str]:
132
+ command = _base_curl_command(url, 15)
133
+ try:
134
+ completed = runner(command, capture_output=True, text=True, check=True)
135
+ return {
136
+ "name": name,
137
+ "url": url,
138
+ "status": "reachable",
139
+ "detail": f"fetched {len(completed.stdout)} bytes",
140
+ }
141
+ except subprocess.CalledProcessError as error:
142
+ detail = (error.stderr or error.stdout or str(error)).strip() or "unknown error"
143
+ status = "timeout" if error.returncode == 28 or "timed out" in detail.lower() else "error"
144
+ return {"name": name, "url": url, "status": status, "detail": detail}
145
+
146
+
147
+ def build_search_plan(
148
+ station: str,
149
+ item: str | None = None,
150
+ line: str | None = None,
151
+ days: int = 30,
152
+ today: date | None = None,
153
+ verify_live: bool = False,
154
+ probe: Callable[[str, str], dict[str, str]] | None = None,
155
+ ) -> SearchPlan:
156
+ normalized_station = normalize_station(station)
157
+ if days <= 0:
158
+ raise ValueError("days must be positive")
159
+
160
+ today = today or date.today()
161
+ end_date = today
162
+ start_date = today - timedelta(days=days)
163
+ query = SearchQuery(
164
+ station=normalized_station,
165
+ item=(item or "").strip() or None,
166
+ line=(line or "").strip() or None,
167
+ start_date=start_date,
168
+ end_date=end_date,
169
+ )
170
+ payload = build_search_payload(query)
171
+ suggested_keywords = expand_station_keywords(normalized_station)
172
+ if query.line:
173
+ suggested_keywords.append(query.line)
174
+ suggested_keywords = list(dict.fromkeys(suggested_keywords))
175
+
176
+ default_sources = [
177
+ {
178
+ "name": "LOST112 μŠ΅λ“λ¬Ό λͺ©λ‘",
179
+ "url": LOST112_LIST_URL,
180
+ "purpose": "κ²½μ°° 이외 κΈ°κ΄€(μ§€ν•˜μ² Β·κ³΅ν•­ λ“±) μŠ΅λ“λ¬Ό 검색",
181
+ "status": "not_checked",
182
+ },
183
+ {
184
+ "name": "μ„œμšΈκ΅ν†΅κ³΅μ‚¬ μœ μ‹€λ¬Όμ„Όν„°",
185
+ "url": SEOUL_METRO_LOST_CENTER_URL,
186
+ "purpose": "μ„œμšΈ μ§€ν•˜μ²  곡식 μœ μ‹€λ¬Ό μ§„μž…μ /μΆ”κ°€ μ•ˆλ‚΄",
187
+ "status": "not_checked",
188
+ },
189
+ ]
190
+ if verify_live:
191
+ probe = probe or probe_source
192
+ default_sources = [
193
+ {**probe(source["name"], source["url"]), "purpose": source["purpose"]}
194
+ for source in default_sources
195
+ ]
196
+
197
+ item_hint = query.item or "λΆ„μ‹€λ¬Ό"
198
+ guidance = [
199
+ f"λ¨Όμ € LOST112μ—μ„œ 보관μž₯μ†Œλ₯Ό '{normalized_station}' 둜, λ¬Όν’ˆλͺ…은 '{item_hint}' 둜 κ²€μƒ‰ν•©λ‹ˆλ‹€.",
200
+ "검색 νΌμ—μ„œλŠ” SITE=V(κ²½μ°°μ΄μ™Έμ˜κΈ°κ΄€) κΈ°μ€€μœΌλ‘œ μ§€ν•˜μ² /곡항 λ“± κΈ°κ΄€ μŠ΅λ“λ¬Όμ„ μš°μ„  μ’νž™λ‹ˆλ‹€.",
201
+ "κ²°κ³Όκ°€ μ—†μœΌλ©΄ μ—­λͺ…μ—μ„œ 'μ—­'을 λΊ€ ν‚€μ›Œλ“œλ‚˜ ν˜Έμ„ λͺ…을 μΆ”κ°€λ‘œ κ²€μƒ‰ν•©λ‹ˆλ‹€.",
202
+ "μ„œμšΈκ΅ν†΅κ³΅μ‚¬ μ•ˆλ‚΄ νŽ˜μ΄μ§€λ₯Ό ν•¨κ»˜ μ—΄μ–΄ μš΄μ˜μ‚¬ μœ μ‹€λ¬Όμ„Όν„°/후속 절차λ₯Ό ν™•μΈν•©λ‹ˆλ‹€.",
203
+ ]
204
+ cautions = [
205
+ "v1은 곡식 μ›Ή 쑰회 경둜λ₯Ό κ΅¬μ‘°ν™”ν•˜λŠ” μ•ˆλ‚΄ν˜•/ν•˜μ΄λΈŒλ¦¬λ“œ μŠ€ν‚¬μ΄λ‹€.",
206
+ "곡개 APIκ°€ ν™•μΈλ˜μ§€ μ•Šμ•„ μžλ™ κ²°κ³Ό μˆ˜μ§‘μ€ 보μž₯ν•˜μ§€ μ•ŠλŠ”λ‹€.",
207
+ "곡식 μ‚¬μ΄νŠΈ 응닡 속도가 느리면 manual open으둜 μ „ν™˜ν•œλ‹€.",
208
+ ]
209
+
210
+ return SearchPlan(
211
+ query=query,
212
+ payload=payload,
213
+ suggested_keywords=suggested_keywords,
214
+ official_sources=default_sources,
215
+ guidance=guidance,
216
+ cautions=cautions,
217
+ curl_example=build_curl_command(payload),
218
+ )
219
+
220
+
221
+ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
222
+ parser = argparse.ArgumentParser(description="Generate official subway lost-property search guidance.")
223
+ parser.add_argument("--station", required=True, help="μ—­λͺ… λ˜λŠ” 보관μž₯μ†Œ ν‚€μ›Œλ“œ")
224
+ parser.add_argument("--item", help="예: μ§€κ°‘, 이어폰")
225
+ parser.add_argument("--line", help="예: 2ν˜Έμ„ ")
226
+ parser.add_argument("--days", type=int, default=30, help="검색 κΈ°κ°„(일), κΈ°λ³Έκ°’ 30")
227
+ parser.add_argument("--verify-live", action="store_true", help="곡식 νŽ˜μ΄μ§€ reachabilityλ₯Ό curl둜 확인")
228
+ return parser.parse_args(argv)
229
+
230
+
231
+ def main(argv: list[str] | None = None) -> None:
232
+ args = parse_args(argv)
233
+ plan = build_search_plan(
234
+ station=args.station,
235
+ item=args.item,
236
+ line=args.line,
237
+ days=args.days,
238
+ verify_live=args.verify_live,
239
+ )
240
+ print(json.dumps(plan.to_dict(), ensure_ascii=False, indent=2))
241
+
242
+
243
+ if __name__ == "__main__":
244
+ main()
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "subway-lost-property",
3
+ "description": "Use when the user asks how to look up μ§€ν•˜μ²  λΆ„μ‹€λ¬Ό or μœ μ‹€λ¬Ό by μ—­λͺ…/λ¬Όν’ˆλͺ…. v1 is an μ•ˆλ‚΄ν˜•/ν•˜μ΄λΈŒλ¦¬λ“œ skill that structures the official LOST112 + μ„œμšΈκ΅ν†΅κ³΅μ‚¬ flow conservatively. λŒμ‡ μ—μ„œλŠ” 곡식 ν‘œλ©΄μ„ ν†΅ν•œ 후속 μ•‘μ…˜κΉŒμ§€ μ§„ν–‰ν•œλ‹€.",
4
+ "profiles": [
5
+ "action:communication"
6
+ ],
7
+ "frontmatter": "name: subway-lost-property\ndescription: Use when the user asks how to look up μ§€ν•˜μ²  λΆ„μ‹€λ¬Ό or μœ μ‹€λ¬Ό by μ—­λͺ…/λ¬Όν’ˆλͺ…. v1 is an μ•ˆλ‚΄ν˜•/ν•˜μ΄λΈŒλ¦¬λ“œ skill that structures the official LOST112 + μ„œμšΈκ΅ν†΅κ³΅μ‚¬ flow conservatively. λŒμ‡ μ—μ„œλŠ” 곡식 ν‘œλ©΄μ„ ν†΅ν•œ 후속 μ•‘μ…˜κΉŒμ§€ μ§„ν–‰ν•œλ‹€.\nlicense: MIT\nmetadata:\n category: transit\n locale: ko-KR\n phase: v1"
8
+ }
@@ -0,0 +1,175 @@
1
+ # Ticket Availability
2
+
3
+ ## What this skill does
4
+
5
+ YES24 (`ticket.yes24.com`) 와 μΈν„°νŒŒν¬ (`tickets.interpark.com`) 의 곡개 BFF JSON / Ajax endpoint λ₯Ό 단일 HTTP μš”μ²­μœΌλ‘œ ν˜ΈμΆœν•΄ 곡연 일정과 등급별 μž”μ—¬μ„ 수λ₯Ό μ •κ·œν™”ν•œλ‹€.
6
+
7
+ - 곡연 URL λ˜λŠ” `platform:id` ν‘œκΈ°λ‘œ μž…λ ₯을 λ°›λŠ”λ‹€.
8
+ - 일정 (λ‚ μ§œΒ·μ‹œκ°„Β·νšŒμ°¨) 쑰회.
9
+ - 등급별 μž”μ—¬μ„ 수 쑰회 (λ“±κΈ‰λͺ…, μž”μ—¬μˆ˜, YES24의 경우 λ…ΈμΆœκ°€).
10
+ - μ’Œμ„λ§΅ / μ’Œμ„ 선택 / 예맀 / 결제 / 둜그인 μ„Έμ…˜ 접근은 ν•˜μ§€ μ•ŠλŠ”λ‹€.
11
+ - CloakBrowser, Playwright, fingerprint spoofing, CAPTCHA 우회λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€ (`httpx` only).
12
+
13
+ ## When to use
14
+
15
+ - "였늘 μΈν„°νŒŒν¬ β—‹β—‹ 곡연 μž”μ—¬μ„ μžˆμ–΄?"
16
+ - "YES24 μ½˜μ„œνŠΈ ID 58026 일정 μ•Œλ €μ€˜"
17
+ - "이 곡연 R석 λͺ‡ 자리 λ‚¨μ•˜μ–΄?"
18
+ - "곡연 URL μ€„κ²Œ, νšŒμ°¨λ³„ μž”μ—¬μ„ ν™•μΈν•΄μ€˜"
19
+
20
+ ## When not to use
21
+
22
+ - μ˜ˆλ§€Β·κ²°μ œΒ·μ·¨μ†ŒΒ·ν™˜λΆˆ 처리 β€” **곡연법 Β§4쑰의2 (2023.9 μ‹œν–‰) 맀크둜 μž…μž₯ꢌ λΆ€μ •κ΅¬λ§€Β·νŒλ§€ κΈˆμ§€** λŒ€μƒμ΄λ©° 이 μŠ€ν‚¬μ€ μ˜λ„μ μœΌλ‘œ 예맀λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠλŠ”λ‹€.
23
+ - μ’Œμ„ 선택, μ’Œμ„λ§΅ μ‹œκ°ν™”, νŠΉμ • μ’Œμ„ 번호 확인 β€” μž”μ—¬ *수* 만 λ…ΈμΆœν•œλ‹€.
24
+ - νšŒμ› 등급별 μš°μ„  예맀, 쿠폰가, μΉ΄λ“œμ‚¬ 할인가 β€” 곡개 endpoint 만 μ‚¬μš©ν•œλ‹€.
25
+ - 차단 우회, CAPTCHA 우회, headless 감지 우회 β€” `httpx` ν•œ 호좜둜 μ•ˆ 되면 μ‹€νŒ¨ λͺ¨λ“œλ‘œ μ²˜λ¦¬ν•˜κ³  μ’…λ£Œν•œλ‹€.
26
+
27
+ ## Required inputs
28
+
29
+ 곡연 URL λ˜λŠ” `platform:id` ν‘œκΈ°κ°€ μ—†μœΌλ©΄ λ¨Όμ € λ¬Όμ–΄λ³Έλ‹€.
30
+
31
+ ꢌμž₯ 질문:
32
+
33
+ > ν™•μΈν•˜μ‹€ κ³΅μ—°μ˜ YES24 λ˜λŠ” μΈν„°νŒŒν¬ URL을 μ•Œλ €μ£Όμ„Έμš”.
34
+ > 예: `https://tickets.interpark.com/goods/26000541`
35
+ > `https://ticket.yes24.com/Perf/58026`
36
+
37
+ ## Prerequisites
38
+
39
+ - Python 3.9+
40
+ - `httpx` (ν‘œμ€€ νŒ¨ν‚€μ§€)
41
+
42
+ μ„€μΉ˜:
43
+
44
+ ```bash
45
+ pip install httpx
46
+ ```
47
+
48
+ ## Workflow
49
+
50
+ ### 1. URL νŒŒμ‹±
51
+
52
+ | μž…λ ₯ | λ§€μΉ­ |
53
+ |---|---|
54
+ | `https://tickets.interpark.com/goods/<goods_code>` | platform=interpark |
55
+ | `https://ticket.yes24.com/Perf/<perf_id>` | platform=yes24 |
56
+ | `https://ticket.yes24.com/New/Perf/Detail/View/<perf_id>` | platform=yes24 |
57
+ | `yes24:<id>` / `interpark:<id>` | shorthand |
58
+
59
+ ### 2. 일정 쑰회 (`schedule`)
60
+
61
+ ```bash
62
+ python3 scripts/ticket_availability.py schedule "https://tickets.interpark.com/goods/26000541"
63
+ ```
64
+
65
+ 응닡 β€” Interpark:
66
+ ```json
67
+ {
68
+ "platform": "interpark",
69
+ "id": "26000541",
70
+ "schedule": [
71
+ {"date": "2026-05-13", "time": "14:30", "play_seq": "055"},
72
+ {"date": "2026-05-14", "time": "19:30", "play_seq": "057"}
73
+ ]
74
+ }
75
+ ```
76
+
77
+ 응닡 β€” YES24:
78
+ ```json
79
+ {
80
+ "platform": "yes24",
81
+ "id": "58026",
82
+ "schedule": [
83
+ {"date": "2026-05-16", "time_label": "1회", "id_time": "1432397"}
84
+ ]
85
+ }
86
+ ```
87
+
88
+ YES24 λŠ” κΈ°λ³Έ 3μ£Ό μœˆλ„μš°. 6κ°œμ›” μ „μ²΄λŠ” `--all-dates` μΆ”κ°€.
89
+
90
+ ### 3. μž”μ—¬μ„ 쑰회 (`seats`)
91
+
92
+ ```bash
93
+ python3 scripts/ticket_availability.py seats "interpark:26000541"
94
+ ```
95
+
96
+ 응닡:
97
+ ```json
98
+ {
99
+ "platform": "interpark",
100
+ "id": "26000541",
101
+ "seats": {
102
+ "2026-05-13|14:30|055": {
103
+ "date": "2026-05-13", "time": "14:30", "play_seq": "055",
104
+ "seats": [
105
+ {"grade": "VIP석", "remain": 150},
106
+ {"grade": "R석", "remain": 36},
107
+ {"grade": "S석", "remain": 82},
108
+ {"grade": "A석", "remain": 71}
109
+ ]
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ YES24 응닡은 등급별 `price` (λ…ΈμΆœκ°€) 도 포함:
116
+ ```json
117
+ {"grade": "전석", "price": "110,000원", "remain": 2}
118
+ ```
119
+
120
+ ### 4. ν—¬μŠ€μ²΄ν¬ (`health`)
121
+
122
+ ```bash
123
+ python3 scripts/ticket_availability.py health
124
+ ```
125
+
126
+ 응닡:
127
+ ```json
128
+ {"yes24": {"status": 200, "ok": true}, "interpark": {"status": 200, "ok": true}}
129
+ ```
130
+
131
+ ## Output format
132
+
133
+ κΈ°λ³Έ 좜λ ₯은 λ“€μ—¬μ“°κΈ° JSON. νŒŒμ΄ν”„/μŠ€ν¬λ¦½νŠΈμš©μ€ `--compact` μΆ”κ°€ (ν•œ 쀄 JSON).
134
+
135
+ ## Endpoints used
136
+
137
+ 이 μŠ€ν‚¬μ΄ ν˜ΈμΆœν•˜λŠ” 곡개 endpoint 만:
138
+
139
+ | Platform | Method | URL |
140
+ |---|---|---|
141
+ | YES24 | POST | `https://ticket.yes24.com/New/Perf/Sale/Ajax/axPerfDay.aspx` |
142
+ | YES24 | POST | `https://ticket.yes24.com/NEw/Perf/Detail/Ajax/axPerfPlayTime.aspx` |
143
+ | YES24 | POST | `https://ticket.yes24.com/New/Perf/Detail/Ajax/axPerfRemainSeat.aspx` |
144
+ | Interpark | GET | `https://api-ticketfront.interpark.com/v1/goods/<id>/playSeq` |
145
+ | Interpark | GET | `https://api-ticketfront.interpark.com/v1/goods/<id>/playSeq/PlaySeq/<seq>/REMAINSEAT` |
146
+
147
+ μ „λΆ€ λΉ„λ‘œκ·ΈμΈ / 무인증. ν—€λ”λŠ” `User-Agent` + `Referer` + JSON `Accept` 만.
148
+
149
+ ## Failure modes
150
+
151
+ - **YES24 `schedule` κ²°κ³Ό 빈 λ°°μ—΄**: 곡연 ID κ°€ μœ νš¨ν•˜μ§€λ§Œ ν–₯ν›„ 3μ£Ό(λ˜λŠ” 6κ°œμ›”) λ‚΄ 일정이 μ—†μŒ. ID μžμ²΄κ°€ 잘λͺ»λœ κ²½μš°μ™€ κ΅¬λΆ„λ˜μ§€ μ•ŠμœΌλ―€λ‘œ, μ‚¬μš©μžμ—κ²Œ `--all-dates` λ˜λŠ” λ‹€λ₯Έ ID 확인을 μ•ˆλ‚΄ν•œλ‹€.
152
+ - **Interpark `data: []`**: goods_code κ°€ μ§€λ‚˜κ°”κ±°λ‚˜ 아직 μ˜€ν”ˆ μ „ / λΉ„κ³΅κ°œ. λ‹€λ₯Έ ID 확인을 μ•ˆλ‚΄ν•œλ‹€.
153
+ - **HTTP 4xx/5xx**: 차단/μΌμ‹œ μž₯μ• . 우회 μ‹œλ„ν•˜μ§€ μ•Šκ³  `http error` 좜λ ₯ ν›„ μ’…λ£Œ.
154
+ - **JSON μŠ€ν‚€λ§ˆ λ³€κ²½**: YES24 axPerfRemainSeat λŠ” HTML 응닡을 μ •κ·œμ‹μœΌλ‘œ νŒŒμ‹± β€” μ‚¬μ΄νŠΈ κ°±μ‹  μ‹œ 영ν–₯ κ°€λŠ₯. `remain` 0 으둜 잘λͺ» 보고될 수 μžˆμ–΄ μ‚¬μš©μžμ—κ²Œ "쑰회 μ‹œκ° κΈ°μ€€" 이라고 ν‘œκΈ°.
155
+ - **곡연 λ§€μ§„**: API λŠ” `remain: 0` λ°˜ν™˜. λ§€μ§„ ν‘œμ‹œ.
156
+
157
+ ## Response style
158
+
159
+ - μž”μ—¬μ„μ€ "쑰회 μ‹œκ° κΈ°μ€€" 으둜 ν‘œν˜„ν•œλ‹€ (μ‹€μ‹œκ°„ 변동).
160
+ - "맀크둜", "선점", "μ˜€ν”ˆλŸ°", "μžλ™ 예맀" ν‘œν˜„ κΈˆμ§€ β€” 이 μŠ€ν‚¬μ€ 쑰회 μ „μš©.
161
+ - μž”μ—¬μ„ 수치 + λ“±κΈ‰λͺ… 만 인용. μ’Œμ„ 번호 / μ’Œμ„ μœ„μΉ˜λŠ” λ…ΈμΆœν•˜μ§€ μ•ŠλŠ”λ‹€.
162
+ - "μ§€κΈˆ 사라" 같은 ν–‰μœ„ μœ λ„ κΈˆμ§€ β€” μ‚¬μš©μžκ°€ 직접 νŽ˜μ΄μ§€μ—μ„œ 결제.
163
+
164
+ ## Notes
165
+
166
+ - λ³Έ μŠ€ν‚¬μ€ μ˜λ„μ μœΌλ‘œ **예맀 / 결제 / μ’Œμ„μ„ νƒ / 둜그인 μžλ™ν™”** λ₯Ό ν¬ν•¨ν•˜μ§€ μ•ŠλŠ”λ‹€. 맀크둜λ₯Ό ν†΅ν•œ μž…μž₯ꢌ λΆ€μ •κ΅¬λ§€Β·νŒλ§€λŠ” 곡연법 Β§4쑰의2 (2023.9.22 μ‹œν–‰) 에 μ˜ν•΄ ν˜•μ‚¬μ²˜λ²Œ λŒ€μƒ.
167
+ - μ‹œν¬λ¦Ώ / ν‚€ / 둜그인 μ„Έμ…˜ 일체 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€.
168
+ - Rate limit: `seats` λͺ…령은 νšŒμ°¨λ³„ 순차 호좜 β€” Interpark 0.3s, YES24 0.4s 간격. 100회차 짜리 곡연이면 μ•½ 30s ~ 40s μ†Œμš”. 짧은 λͺ¨λ‹ˆν„°λ§ 루프에 λ„£μ§€ 말 것.
169
+
170
+ ## Done when
171
+
172
+ - 곡연 URL λ˜λŠ” `platform:id` κ°€ ν™•μΈλ˜μ—ˆλ‹€.
173
+ - 일정 λ˜λŠ” μž”μ—¬μ„ κ²°κ³Ό JSON 을 λ°˜ν™˜ν•˜κ±°λ‚˜, 빈 κ²°κ³Ό μ‚¬μœ λ₯Ό μ„€λͺ…ν–ˆλ‹€.
174
+ - 예맀 / 결제 / μ’Œμ„ 선택 κΈ°λŠ₯을 μžλ™ν™”ν•˜μ§€ μ•Šμ•˜λ‹€.
175
+ - 쑰회 μ‹œκ° κΈ°μ€€μž„μ„ μ•ˆλ‚΄ν–ˆλ‹€.