@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,139 @@
1
+ # Library Book Search (Data4Library)
2
+
3
+ ## What this skill does
4
+
5
+ 국립중앙도서관의 **도서관 정보나루(Data4Library)** Open API를 `k-skill-proxy`가 중계하는 HTTP API로 조회한다.
6
+
7
+ - 키워드로 도서를 검색한다.
8
+ - ISBN으로 상세 서지·대출정보를 확인한다.
9
+ - ISBN + 지역코드로 해당 도서를 소장한 도서관 목록을 찾는다.
10
+ - 도서관 코드 + ISBN으로 특정 도서관의 소장/대출 가능 여부를 확인한다.
11
+
12
+ ## When to use
13
+
14
+ - "역사 관련 책 도서관 정보나루에서 찾아줘"
15
+ - "이 ISBN 소장한 서울 도서관 찾아줘"
16
+ - "정독도서관에 이 책 있는지 확인해줘"
17
+ - "도서관 도서 조회 가능해?"
18
+
19
+ ## Prerequisites
20
+
21
+ - 인터넷 연결
22
+ - `curl` 사용 가능 환경
23
+ - `k-skill-proxy`에 `DATA4LIBRARY_AUTH_KEY`가 설정된 배포(기본 hosted 또는 self-host)에 접근 가능할 것
24
+
25
+ ## Credential requirements
26
+
27
+ 사용자에게 필요한 시크릿은 없으며, `DATA4LIBRARY_AUTH_KEY`는 프록시 서버에서만 관리한다.
28
+
29
+ - 사용자 측 **필수 시크릿 없음**.
30
+ - `KSKILL_PROXY_BASE_URL` — self-host·별도 프록시를 쓸 때만 설정. 비우면 기본 hosted `https://k-skill-proxy.nomadamas.org` 를 사용한다.
31
+ - `DATA4LIBRARY_AUTH_KEY` 는 **프록시 서버** 환경에만 둔다. 사용자에게 인증키를 요구하거나 응답에 노출하지 않는다.
32
+
33
+ ## Proxy base URL
34
+
35
+ ```bash
36
+ BASE="${KSKILL_PROXY_BASE_URL:-https://k-skill-proxy.nomadamas.org}"
37
+ BASE="${BASE%/}"
38
+ ```
39
+
40
+ ## Workflow
41
+
42
+ ### 1) Collect the intent and minimal inputs
43
+
44
+ 사용자 요청에 따라 필요한 값만 묻는다.
45
+
46
+ - 키워드 도서 검색: `keyword`만 있으면 시작한다.
47
+ - 상세 조회: ISBN(10자리 또는 13자리)이 필요하다.
48
+ - 소장 도서관 조회: ISBN + 광역 지역코드(`region`)가 필요하다. 시군구 상세코드(`dtl_region`)가 있으면 같이 쓴다.
49
+ - 특정 도서관 소장 확인: 도서관 코드(`libraryCode`) + ISBN이 필요하다.
50
+
51
+ 도서관 코드나 지역코드가 없으면 먼저 `library-search`로 후보를 보거나, 사용자에게 알고 있는 도서관명·지역을 더 물어본다. 이름만으로 확정되지 않으면 임의로 하나를 고르지 않는다.
52
+
53
+ ### 2) Search books (`/v1/data4library/book-search`)
54
+
55
+ ```bash
56
+ curl -fsS --get "${BASE}/v1/data4library/book-search" \
57
+ --data-urlencode "keyword=역사" \
58
+ --data-urlencode "pageNo=1" \
59
+ --data-urlencode "pageSize=10"
60
+ ```
61
+
62
+ 별칭: `q`, `query`, `page`, `limit`도 허용된다.
63
+
64
+ 응답의 `response.docs[].doc`에서 주로 볼 필드:
65
+
66
+ - `bookname` — 도서명
67
+ - `authors` — 저자
68
+ - `publisher` — 출판사
69
+ - `publication_year` — 출판연도
70
+ - `isbn13` — 상세/소장 조회에 쓸 ISBN
71
+
72
+ ### 3) Fetch book detail (`/v1/data4library/book-detail`)
73
+
74
+ ```bash
75
+ curl -fsS --get "${BASE}/v1/data4library/book-detail" \
76
+ --data-urlencode "isbn13=9788971998557" \
77
+ --data-urlencode "loaninfoYN=Y"
78
+ ```
79
+
80
+ - `loaninfoYN=Y`를 주면 upstream이 제공하는 인기 대출 지역·연령·대출건수 같은 추가 정보를 함께 요청한다.
81
+ - 상세 응답이 비어 있으면 ISBN 오타, 미수집 도서, upstream 지연 가능성을 안내한다.
82
+
83
+ ### 4) Find libraries that hold a book (`/v1/data4library/libraries-by-book`)
84
+
85
+ ```bash
86
+ curl -fsS --get "${BASE}/v1/data4library/libraries-by-book" \
87
+ --data-urlencode "isbn=9788971998557" \
88
+ --data-urlencode "region=11" \
89
+ --data-urlencode "pageNo=1" \
90
+ --data-urlencode "pageSize=10"
91
+ ```
92
+
93
+ - `region`은 도서관 정보나루 지역코드다. 예: 서울특별시 코드가 필요한 경우 `11`처럼 숫자 코드를 사용한다.
94
+ - `dtl_region`이 있으면 더 좁힌다.
95
+ - 결과가 여러 개면 도서관명·주소·홈페이지·전화번호(응답에 있는 경우)를 요약해 보여 주고, 실시간 대출가능 여부는 별도 `book-exists`로 확인한다.
96
+
97
+ ### 5) Check one library's holding (`/v1/data4library/book-exists`)
98
+
99
+ ```bash
100
+ curl -fsS --get "${BASE}/v1/data4library/book-exists" \
101
+ --data-urlencode "libraryCode=111001" \
102
+ --data-urlencode "isbn13=9788971998557"
103
+ ```
104
+
105
+ - `hasBook`, `loanAvailable` 등 upstream 응답 필드를 그대로 해석한다.
106
+ - 대출 가능 여부는 도서관 시스템 동기화 지연이 있을 수 있으므로, 최종 방문 전 도서관 홈페이지/전화 확인을 권한다.
107
+
108
+ ### 6) Optional: library list (`/v1/data4library/library-search`)
109
+
110
+ ```bash
111
+ curl -fsS --get "${BASE}/v1/data4library/library-search" \
112
+ --data-urlencode "region=11" \
113
+ --data-urlencode "pageNo=1" \
114
+ --data-urlencode "pageSize=10"
115
+ ```
116
+
117
+ ## Summarize for the user
118
+
119
+ - 도서명, 저자, 출판사, 출판연도, ISBN을 먼저 정리한다.
120
+ - 소장 도서관 목록은 사용자의 지역·이동 가능성을 기준으로 상위 후보만 보여 준다.
121
+ - JSON 전체를 길게 붙이지 말고, 필요한 필드와 다음 단계(상세 조회/소장 확인/도서관 선택)를 제안한다.
122
+
123
+ ## Upstream reference
124
+
125
+ - 도서관 정보나루 Open API 활용방법: `https://www.data4library.kr/apiUtilization`
126
+
127
+ ## Failure modes
128
+
129
+ - 프록시에 `DATA4LIBRARY_AUTH_KEY` 미설정 → `503` / `upstream_not_configured`
130
+ - 키워드·ISBN·지역코드·도서관 코드 누락 → `400` / `bad_request`
131
+ - ISBN 자리수 오류 → 하이픈을 제외한 ISBN-10(마지막 X 허용) 또는 ISBN-13으로 다시 요청
132
+ - 도서관 코드/지역코드 불명확 — 사용자에게 후보를 보여 주고 선택 받기
133
+ - Data4Library API 일시 장애·호출 제한·데이터 미수집
134
+
135
+ ## Notes
136
+
137
+ - 기본 posture는 read-only 조회다. 예약, 대출, 개인정보 기반 도서관 로그인 자동화는 하지 않는다.
138
+ - `DATA4LIBRARY_AUTH_KEY`는 프록시 서버 전용이다. 사용자 측에는 시크릿이 없다.
139
+ - 프록시가 upstream `authKey`와 `format=json`을 주입하므로, 사용자가 넘긴 `authKey`/`format`은 신뢰하지 않는다.
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "library-book-search",
3
+ "description": "Use when the user asks to search Korean library books, book details, library holdings, or whether a Korean public library owns a book via k-skill-proxy Data4Library routes. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.",
4
+ "profiles": [
5
+ "proxy",
6
+ "action:booking"
7
+ ],
8
+ "frontmatter": "name: library-book-search\ndescription: Use when the user asks to search Korean library books, book details, library holdings, or whether a Korean public library owns a book via k-skill-proxy Data4Library routes. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.\nlicense: MIT\nmetadata:\n category: utility\n locale: ko-KR\n phase: v1"
9
+ }
@@ -0,0 +1,77 @@
1
+ # Local Election Candidate Search
2
+
3
+ ## What this skill does
4
+
5
+ 중앙선거관리위원회(NEC) 선거통계시스템의 공개 통합검색에서 후보자 이름을 조회하고, 지방선거 관련 후보자 이력만 기본으로 정리한다. 후보자명, 한자명, 생년월일/성별, 선거일, 선거명, 선거종류, 정당, 선거구, 득표, 직업, 학력, 경력 등을 반환한다.
6
+
7
+ ## When to use
8
+
9
+ - 사용자가 “지방선거 후보”, “시도지사 후보”, “기초의원 후보”, “교육감 후보” 등을 이름/지역/선거일 기준으로 찾아 달라고 할 때
10
+ - 중앙선관위 선거통계시스템에서 공개된 후보자 이력을 확인해야 할 때
11
+ - 동명이인이 있을 수 있어 후보자명 + 선거종류/지역/연도 필터가 필요한 때
12
+
13
+ ## Public access path
14
+
15
+ Chosen path: NEC integrated candidate search.
16
+
17
+ - Entry page: `https://info.nec.go.kr/search/searchCandidate.xhtml`
18
+ - Method: unauthenticated public `POST`
19
+ - Required form field: `searchKeyword=<정확한 후보자 성명>`
20
+ - Helper package: `local-election-candidate-search`
21
+
22
+ Why this path: the visible NEC UI explicitly exposes candidate-name integrated search across recent and historical elections, and it returns the candidate result cards in server-rendered HTML. It is more stable than scraping per-election menu pages because it does not require selecting every city/town/constituency combo first.
23
+
24
+ ## Workflow
25
+
26
+ 1. Use the package CLI from this repository or installed workspace:
27
+
28
+ ```bash
29
+ npx local-election-candidate-search 오세훈 --election 시도지사 --region 서울 --limit 5
30
+ ```
31
+
32
+ 2. Narrow ambiguous/homonym results:
33
+
34
+ ```bash
35
+ npx local-election-candidate-search 김동연 --date 2014 --election 기초의원 --region 동작
36
+ ```
37
+
38
+ 3. Include non-local races only when the user asks for all NEC integrated-search matches:
39
+
40
+ ```bash
41
+ npx local-election-candidate-search 이재명 --all --limit 20
42
+ ```
43
+
44
+ ## Inputs
45
+
46
+ - Candidate name: exact Korean name; required.
47
+ - `--election`: one of `시도지사`, `기초단체장`, `광역의원`, `기초의원`, `광역비례`, `기초비례`, `교육감`.
48
+ - `--date` / `--year`: `YYYY`, `YYYYMMDD`, or `YYYY.MM.DD`.
49
+ - `--region`: free text filter against parsed district/region text.
50
+ - `--limit`: max rows, capped at 100.
51
+ - `--all`: include non-local election results.
52
+
53
+ ## Outputs
54
+
55
+ Return concise JSON. Each `items[]` row may include:
56
+
57
+ - `name`, `hanja`, `birth_date`, `gender`
58
+ - `election_date`, `election_name`, `election_code`, `election_type`
59
+ - `party`, `district`, `votes`, `vote_share`, `elected`
60
+ - `job`, `education`, `career[]`
61
+ - upstream code fields such as `city_code`, `sgg_city_code`, `town_code`
62
+
63
+ `summary.upstream_result_limit` shows the NEC row count requested before local client-side filters. Filtered searches request up to 100 upstream rows first, then apply exact-name matching, local/election/date/region filters, deduplication, and the final `--limit`.
64
+
65
+ ## Failure modes
66
+
67
+ - `no candidate results`: NEC returned no matching card or filters removed all matches.
68
+ - `unexpected NEC search HTML`: upstream may be in maintenance, NetFunnel queue, login/blocked state, or markup changed.
69
+ - `NEC search page was capped`: filtered results are based on the maximum fetched page and may require upstream pagination for exhaustive coverage.
70
+ - Homonyms: the same name can appear across many elections; always show election date/type/district and apply user-provided filters.
71
+ - Future elections: candidate registration data may be incomplete until NEC publishes it.
72
+
73
+ ## Done when
74
+
75
+ - Results are sourced from `info.nec.go.kr` public HTML.
76
+ - Local-election filtering is applied unless the user requested `--all`.
77
+ - Any warnings/failure modes are shown instead of silently claiming no results.
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "local-election-candidate-search",
3
+ "description": "중앙선거관리위원회 선거통계시스템 공개 통합검색으로 한국 지방선거 후보자 정보를 이름/선거종류/지역 기준으로 조회한다.",
4
+ "profiles": [
5
+ "lookup"
6
+ ],
7
+ "frontmatter": "name: local-election-candidate-search\ndescription: 중앙선거관리위원회 선거통계시스템 공개 통합검색으로 한국 지방선거 후보자 정보를 이름/선거종류/지역 기준으로 조회한다.\nlicense: MIT\nmetadata:\n category: civic\n locale: ko-KR\n phase: v1"
8
+ }
@@ -0,0 +1,64 @@
1
+ # 지방행정 인허가 영업상태 조회 (동네 사업장)
2
+
3
+ ## What this skill does
4
+
5
+ 행정안전부 **지방행정 인허가데이터(LOCALDATA)**의 지역별 CSV를 `file.localdata.go.kr`에서 직접 받아, 동네 사업장의 영업상태를 조회한다.
6
+
7
+ - 영업상태(영업/휴업/폐업), 상세영업상태, 인허가일자(업력), 폐업일자, 업태구분, 도로명/지번 주소, 데이터갱신시점
8
+ - 인허가 업종 **208종 전체** 지원 — 한글명("약국", "숙박업", "일반음식점")으로 지정 가능
9
+
10
+ 전국 통파일이 업종당 수백 MB라 **시군구 단위 지역 지정**(`--region`)이 필요하다. 받은 파일은 1일 로컬 캐시한다.
11
+
12
+ 이 자료에는 **사업자등록번호가 수록되지 않는다.** 상호(사업장명) 문자열 일치 후보의 사실만 나열하며, 동명 상호 가능성은 사용자가 판단한다. 자료는 매일 갱신되며 2일 전 기준으로 현행화된다.
13
+
14
+ ## Design principles
15
+
16
+ - 점수·등급·해석 라벨을 만들지 않는다. 조회된 사실 + 출처 + 조회시각만 담는다.
17
+ - 인증 없이 동작하는 공개 파일 서버이므로 프록시를 거치지 않고 사용자 머신에서 직접 호출한다.
18
+
19
+ ## When to use
20
+
21
+ - "제주시 ○○호텔 지금 영업 중이야? 오래된 곳이야?" — 사업자번호를 몰라도 상호+시군구로 조회
22
+ - "이 동네 가게 폐업했어?", "이 식당 인허가가 언제야(업력)?"
23
+
24
+ ## Prerequisites
25
+
26
+ - 인터넷 연결, `python3` (stdlib만 사용 — 추가 의존성 없음)
27
+ - `scripts/localdata_business_status.py` helper
28
+ - `data/localdata_industries.json`(업종 208종), `data/localdata_orgcodes.json`(지자체 245종)
29
+
30
+ ## Credential requirements
31
+
32
+ - 없음. 무인증 공개 파일 다운로드다.
33
+
34
+ ## Inputs
35
+
36
+ - `--name`: 상호(사업장명) — 필수
37
+ - `--region`: 시군구 — 필수 (예: `제주제주시`, `서울종로구`, `경기수원시`)
38
+ - `--industry`: 업종 slug 또는 한글명 (여러 번 지정 가능). 생략 시 일반음식점·휴게음식점·숙박업
39
+
40
+ ## Privacy boundary
41
+
42
+ - 입력한 상호·지역은 LOCALDATA 파일 서버로 전송된다(다운로드 요청 파라미터).
43
+ - 자료에 사업자등록번호가 없어 상호 문자열 매칭이며 동일성을 단정하지 않는다.
44
+
45
+ ## CLI examples
46
+
47
+ ```bash
48
+ python3 localdata-business-status/scripts/localdata_business_status.py \
49
+ --name "호텔샬롬" --region 제주제주시 --industry 숙박업
50
+
51
+ # 업종 여러 개
52
+ python3 localdata-business-status/scripts/localdata_business_status.py \
53
+ --name "○○약국" --region 서울종로구 --industry 약국
54
+ ```
55
+
56
+ ## Failure modes
57
+
58
+ - `unavailable` + 안내: 상호/지역 미입력, 지역·업종 특정 실패(후보 나열), 다운로드 실패 — 수동 확인 URL 제공.
59
+ - 0건: 매치 없음 (`total_match_count: 0`).
60
+
61
+ ## Official surfaces
62
+
63
+ - 인허가 영업상태: `https://file.localdata.go.kr/file/download/<업종slug>/info?orgCode=<지자체코드>` (무인증, Referer 필요, CP949 CSV)
64
+ - 본체: <https://www.localdata.go.kr>
@@ -0,0 +1,206 @@
1
+ """LOCALDATA (지방행정 인허가) business operating-status lookup (unauthenticated).
2
+
3
+ 행정안전부 지방행정 인허가데이터를 file.localdata.go.kr 지역별 CSV로 직접 받아
4
+ 동네 사업장(식당·카페·숙박·약국 등 인허가 업종 208종)의 영업/휴업/폐업 상태를
5
+ 조회한다. 인증키가 필요 없는 공개 파일 서버이므로 프록시를 거치지 않는다.
6
+
7
+ The data does NOT contain business registration numbers, so this is a trade-name
8
+ (사업장명) string match only — it cannot assert identity against a given number.
9
+ 전국 통파일이 업종당 수백 MB라 시군구 단위 파일을 받으려면 --region 이 필요하다.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import argparse
15
+ import csv
16
+ import datetime as dt
17
+ import io
18
+ import json
19
+ import pathlib
20
+ import sys
21
+ import time
22
+ import urllib.error
23
+ import urllib.parse
24
+ import urllib.request
25
+ from typing import Any
26
+
27
+ BASE = "https://file.localdata.go.kr"
28
+ LANDING = f"{BASE}/file/general_restaurants/info"
29
+ SOURCE = ("지방행정 인허가데이터(LOCALDATA) 업종별 영업상태 — 행정안전부 "
30
+ "(file.localdata.go.kr 지역별 CSV, 매일 갱신·2일 전 기준 현행화)")
31
+ USER_AGENT = ("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
32
+ "(KHTML, like Gecko) Chrome/126.0 Safari/537.36")
33
+ KST = dt.timezone(dt.timedelta(hours=9))
34
+
35
+ _DATA_DIR = pathlib.Path(__file__).resolve().parent.parent / "data"
36
+ INDUSTRIES: dict = json.loads((_DATA_DIR / "localdata_industries.json").read_text(encoding="utf-8"))
37
+ DEFAULT_INDUSTRIES = ("general_restaurants", "rest_cafes", "lodgings")
38
+
39
+ RESULT_COLUMNS = ("사업장명", "영업상태명", "상세영업상태명", "인허가일자", "폐업일자",
40
+ "업태구분명", "도로명주소", "지번주소", "데이터갱신시점")
41
+
42
+ CACHE_DIR = pathlib.Path.home() / ".cache" / "k-skill" / "localdata-business-status"
43
+ CACHE_TTL_SECONDS = 24 * 3600 # 원천이 일 단위 갱신이므로 1일 캐시
44
+
45
+ IDENTITY_NOTE = ("인허가 자료에는 사업자등록번호가 수록되지 않아 입력 사업자번호와의 "
46
+ "동일성은 확인할 수 없다 — 상호(사업장명) 문자열 일치 후보의 사실만 "
47
+ "나열하며, 동명 상호 가능성은 사용자가 판단한다. 자료는 매일 갱신되며 "
48
+ "2일 전 기준으로 현행화된다.")
49
+
50
+
51
+ def _now_iso() -> str:
52
+ return dt.datetime.now(KST).isoformat(timespec="seconds")
53
+
54
+
55
+ def _envelope(status: str, *, result: dict | None = None, note: str | None = None) -> dict:
56
+ return {
57
+ "source": SOURCE,
58
+ "looked_up_at": _now_iso(),
59
+ "status": status,
60
+ "result": result,
61
+ "origin": "unauthenticated-public",
62
+ "note": note,
63
+ }
64
+
65
+
66
+ def org_codes() -> dict:
67
+ return json.loads((_DATA_DIR / "localdata_orgcodes.json").read_text(encoding="utf-8"))
68
+
69
+
70
+ def resolve_industry(token: str) -> tuple[str | None, list[str]]:
71
+ """업종 지정 해석 — slug 정확 일치 또는 한글명 일치. (slug, 후보들)."""
72
+ token = token.strip()
73
+ if token in INDUSTRIES:
74
+ return token, [INDUSTRIES[token]]
75
+ squeezed = token.replace(" ", "")
76
+ exact = [(slug, nm) for slug, nm in INDUSTRIES.items()
77
+ if nm.replace(" ", "") == squeezed
78
+ or nm.split("_", 1)[-1].replace(" ", "") == squeezed]
79
+ if len(exact) == 1:
80
+ return exact[0][0], [exact[0][1]]
81
+ hits = exact or [(slug, nm) for slug, nm in INDUSTRIES.items()
82
+ if squeezed in nm.replace(" ", "")]
83
+ if len(hits) == 1:
84
+ return hits[0][0], [hits[0][1]]
85
+ return None, [nm for _, nm in hits]
86
+
87
+
88
+ def _resolve_region(region: str) -> tuple[str | None, list[str]]:
89
+ table = org_codes()
90
+ region = region.strip()
91
+ if region in table:
92
+ return table[region], [region]
93
+ squeezed = region.replace(" ", "")
94
+ hits = [nm for nm in table if squeezed in nm.replace(" ", "")]
95
+ if len(hits) == 1:
96
+ return table[hits[0]], hits
97
+ return None, hits
98
+
99
+
100
+ def _fetch_csv(slug: str, org_code: str, *, opener: Any = None) -> str:
101
+ CACHE_DIR.mkdir(parents=True, exist_ok=True)
102
+ cache = CACHE_DIR / f"{slug}_{org_code}.csv"
103
+ if cache.exists() and time.time() - cache.stat().st_mtime < CACHE_TTL_SECONDS:
104
+ return cache.read_text(encoding="utf-8")
105
+ params = urllib.parse.urlencode({"orgCode": org_code})
106
+ request = urllib.request.Request(
107
+ f"{BASE}/file/download/{slug}/info?{params}",
108
+ headers={"User-Agent": USER_AGENT, "Referer": LANDING},
109
+ method="GET",
110
+ )
111
+ open_fn = opener or urllib.request.urlopen
112
+ with open_fn(request, timeout=120) as response:
113
+ status = getattr(response, "status", 200)
114
+ content_type = response.headers.get("Content-Type", "") if hasattr(response, "headers") else ""
115
+ if status != 200 or "csv" not in (content_type or ""):
116
+ raise RuntimeError(f"HTTP {status} ({content_type or '?'})")
117
+ text = response.read().decode("cp949", errors="replace")
118
+ cache.write_text(text, encoding="utf-8")
119
+ return text
120
+
121
+
122
+ def _search_rows(csv_text: str, name: str) -> list[dict]:
123
+ needle = name.replace(" ", "")
124
+ out = []
125
+ for row in csv.DictReader(io.StringIO(csv_text)):
126
+ biz_name = (row.get("사업장명") or "").strip()
127
+ if needle and needle in biz_name.replace(" ", ""):
128
+ out.append({col: (row.get(col) or "").strip() for col in RESULT_COLUMNS})
129
+ return out
130
+
131
+
132
+ def lookup(name: str, region: str, industries: list[str] | None = None, *, opener: Any = None) -> dict:
133
+ """인허가 영업상태 조회 — 상호+지역 필수 (자료에 사업자번호 없음)."""
134
+ if not (name or "").strip():
135
+ return _envelope("unavailable",
136
+ note="인허가 자료에 사업자등록번호가 수록되지 않아 상호 없이 검색할 수 "
137
+ "없습니다. --name 으로 상호를 지정하세요.")
138
+ if not (region or "").strip():
139
+ return _envelope("unavailable",
140
+ note="전국 통파일이 업종당 수백 MB라 시군구 지역 지정이 필요합니다. "
141
+ "--region 으로 지정하세요 (예: 제주제주시, 서울종로구, 경기수원시).")
142
+ name = name.strip()
143
+
144
+ code, hits = _resolve_region(region)
145
+ if code is None:
146
+ return _envelope("unavailable",
147
+ note=(f"지역 '{region}' 특정 실패 — "
148
+ + (f"후보 {len(hits)}곳: {', '.join(hits[:8])}. 하나로 지정하세요."
149
+ if hits else "등록 지자체명과 일치하지 않습니다 (예: 서울종로구).")))
150
+
151
+ selected, bad = [], []
152
+ for token in (industries or DEFAULT_INDUSTRIES):
153
+ slug, cand = resolve_industry(token)
154
+ if slug:
155
+ selected.append(slug)
156
+ else:
157
+ bad.append(f"'{token}'" + (f" (후보 {len(cand)}종: {', '.join(cand[:6])})" if cand
158
+ else " (일치 업종 없음)"))
159
+ if bad:
160
+ return _envelope("unavailable",
161
+ note=(f"업종 특정 실패: {'; '.join(bad)}. slug 또는 한글명(예: 약국, "
162
+ "일반음식점, 숙박업)으로 하나씩 지정하세요. 총 208종 지원."))
163
+
164
+ searched, failures = {}, []
165
+ try:
166
+ for slug in selected:
167
+ try:
168
+ rows = _search_rows(_fetch_csv(slug, code, opener=opener), name)
169
+ searched[slug] = {"industry": INDUSTRIES[slug], "match_count": len(rows), "matches": rows}
170
+ except (urllib.error.URLError, RuntimeError) as err:
171
+ failures.append(f"{INDUSTRIES[slug]}({type(err).__name__})")
172
+ except Exception as err: # 경계 계약: 어떤 오류든 강등
173
+ return _envelope("unavailable", note=f"예상 외 오류({type(err).__name__}).")
174
+
175
+ if not searched:
176
+ return _envelope("unavailable",
177
+ note=f"전 업종 다운로드 실패: {', '.join(failures)}. "
178
+ f"수동 확인: https://www.localdata.go.kr")
179
+
180
+ result = {
181
+ "query": {"name": name, "region": hits[0], "org_code": code},
182
+ "industries_searched": searched,
183
+ "total_match_count": sum(v["match_count"] for v in searched.values()),
184
+ "identity_note": IDENTITY_NOTE,
185
+ }
186
+ note = (f"일부 업종 다운로드 실패: {', '.join(failures)}" if failures else None)
187
+ return _envelope("ok", result=result, note=note)
188
+
189
+
190
+ def build_parser() -> argparse.ArgumentParser:
191
+ parser = argparse.ArgumentParser(description="지방행정 인허가 영업상태 조회 (무인증)")
192
+ parser.add_argument("--name", required=True, help="상호(사업장명) — 필수")
193
+ parser.add_argument("--region", required=True, help="시군구 (예: 제주제주시, 서울종로구)")
194
+ parser.add_argument("--industry", action="append", dest="industries",
195
+ help="업종 slug 또는 한글명(예: 약국, 숙박업). 여러 번 지정 가능. 생략 시 음식점·카페·숙박")
196
+ return parser
197
+
198
+
199
+ def main(argv: list[str] | None = None) -> int:
200
+ args = build_parser().parse_args(argv)
201
+ print(json.dumps(lookup(args.name, args.region, args.industries), ensure_ascii=False, indent=2))
202
+ return 0
203
+
204
+
205
+ if __name__ == "__main__":
206
+ raise SystemExit(main())
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "localdata-business-status",
3
+ "description": "지방행정 인허가데이터(LOCALDATA)로 동네 사업장(식당·카페·숙박·약국·미용실·학원 등 인허가 업종 208종)의 영업/휴업/폐업 상태, 인허가일자(업력), 폐업일자, 업태, 주소를 조회한다. 상호+시군구로 검색하며 인증키 불필요.",
4
+ "profiles": [
5
+ "lookup"
6
+ ],
7
+ "frontmatter": "name: localdata-business-status\ndescription: 지방행정 인허가데이터(LOCALDATA)로 동네 사업장(식당·카페·숙박·약국·미용실·학원 등 인허가 업종 208종)의 영업/휴업/폐업 상태, 인허가일자(업력), 폐업일자, 업태, 주소를 조회한다. 상호+시군구로 검색하며 인증키 불필요.\nlicense: MIT\nmetadata:\n category: business\n locale: ko-KR\n phase: v1"
8
+ }
@@ -0,0 +1,80 @@
1
+ # Lotto Results
2
+
3
+ ## What this skill does
4
+
5
+ `k-lotto` 패키지로 동행복권 로또 최신 회차, 특정 회차, 상세 당첨 결과, 번호 대조를 처리한다.
6
+
7
+ ## When to use
8
+
9
+ - "이번 주 로또 번호 뭐야"
10
+ - "1210회 당첨번호 알려줘"
11
+ - "내 번호가 몇 등인지 봐줘"
12
+
13
+ ## Prerequisites
14
+
15
+ - Node.js 18+
16
+ - 배포 후: `npm install -g k-lotto`
17
+ - 실행 전: `export NODE_PATH="$(npm root -g)"`
18
+ - 이 저장소에서 개발할 때: 루트에서 `npm install`
19
+
20
+ ## Inputs
21
+
22
+ - 회차 번호 또는 "latest"
23
+ - 선택 사항: 사용자가 가진 6개 번호
24
+
25
+ ## Workflow
26
+
27
+ ### 0. Install the package globally when missing
28
+
29
+ `node -e 'require("k-lotto")'` 가 실패하면 다른 구현으로 우회하지 말고 전역 Node 패키지 설치를 먼저 시도한다.
30
+
31
+ ```bash
32
+ npm install -g k-lotto
33
+ export NODE_PATH="$(npm root -g)"
34
+ ```
35
+
36
+ 패키지가 없다는 이유로 HTML 파서를 다시 짜거나 다른 비공식 소스를 찾지 않는다.
37
+
38
+ ### 1. Get the latest round when needed
39
+
40
+ ```bash
41
+ NODE_PATH="$(npm root -g)" node - <<'JS'
42
+ const lotto = require("k-lotto");
43
+ lotto.getLatestRound().then((round) => console.log(round));
44
+ JS
45
+ ```
46
+
47
+ ### 2. Fetch result or detailed payout data
48
+
49
+ ```bash
50
+ NODE_PATH="$(npm root -g)" node - <<'JS'
51
+ const lotto = require("k-lotto");
52
+ lotto.getDetailResult(1216).then((result) => console.log(JSON.stringify(result, null, 2)));
53
+ JS
54
+ ```
55
+
56
+ ### 3. Check user's numbers when provided
57
+
58
+ ```bash
59
+ NODE_PATH="$(npm root -g)" node - <<'JS'
60
+ const lotto = require("k-lotto");
61
+ lotto.checkNumber(1216, ["3", "10", "14", "15", "23", "24"])
62
+ .then((result) => console.log(JSON.stringify(result, null, 2)));
63
+ JS
64
+ ```
65
+
66
+ ## Done when
67
+
68
+ - 최신 또는 요청 회차의 번호가 확인되어 있다
69
+ - 상세 요청이면 추첨일과 당첨금 분포가 정리되어 있다
70
+ - 번호 대조 요청이면 일치 번호와 등수가 확인되어 있다
71
+
72
+ ## Failure modes
73
+
74
+ - 최신 회차는 결과 페이지 HTML에서 읽기 때문에 upstream HTML 변경의 영향을 받을 수 있다
75
+ - 상세 회차 정보는 동행복권 JSON 응답 스키마 변경의 영향을 받을 수 있다
76
+
77
+ ## Notes
78
+
79
+ - 사용자 번호를 받아도 영구 저장하지 않는다
80
+ - 조회 전용 스킬이다
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "lotto-results",
3
+ "description": "Check Korean Lotto draw results, latest rounds, and ticket matches with the k-lotto npm package. Use when the user asks for winning numbers, payout details, or whether their numbers matched.",
4
+ "profiles": [
5
+ "lookup"
6
+ ],
7
+ "frontmatter": "name: lotto-results\ndescription: Check Korean Lotto draw results, latest rounds, and ticket matches with the k-lotto npm package. Use when the user asks for winning numbers, payout details, or whether their numbers matched.\nlicense: MIT\nmetadata:\n category: utility\n locale: ko-KR\n phase: v1"
8
+ }