@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,302 @@
1
+ #!/usr/bin/env python3
2
+ """Read-only Bank of Korea ECOS economic statistics helper (stdlib only).
3
+
4
+ Site-dependent access path (discovered live 2026-07-21):
5
+
6
+ GET https://ecos.bok.or.kr/api/<Service>/<key>/json/kr/<start>/<end>/<segments...>
7
+
8
+ - Positional URL segments, no query string.
9
+ - The published demo key ``sample`` works without registration but caps each
10
+ call at 10 rows (exceeding it returns ERROR-301).
11
+ - Invalid keys return HTTP 200 with {"RESULT": {"CODE": "INFO-100", ...}}.
12
+ - Empty results return {"RESULT": {"CODE": "INFO-200", "MESSAGE": "해당하는 데이터가 없습니다."}}.
13
+
14
+ Services used:
15
+ - StatisticSearch/<stat>/<cycle>/<start>/<end>[/<item1>] — time series cells
16
+ - StatisticTableList — table catalog
17
+ - StatisticItemList/<stat> — items of one table
18
+ - KeyStatisticList — 100+ headline indicators (환율/금리/물가 등)
19
+ - StatisticWord/<keyword> — glossary
20
+
21
+ Because the demo key works without registration, this skill calls upstream
22
+ directly (no k-skill-proxy route). Users may set KSKILL_BOK_ECOS_API_KEY for
23
+ larger row limits.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import argparse
29
+ import json
30
+ import os
31
+ import pathlib
32
+ import re
33
+ import sys
34
+ import urllib.error
35
+ import urllib.parse
36
+ import urllib.request
37
+ from typing import Any, Dict, List, Optional
38
+
39
+ ECOS_BASE_URL = "https://ecos.bok.or.kr/api"
40
+ ECOS_DEMO_KEY = "sample"
41
+ SAMPLE_MAX_ROWS = 10
42
+ DEFAULT_SECRETS_PATH = pathlib.Path("~/.config/k-skill/secrets.env").expanduser()
43
+ USER_AGENT = "k-skill-bok-ecos/0.1 (+https://github.com/NomaDamas/k-skill)"
44
+
45
+ # 자주 쓰는 지표 alias → (stat_code, cycle, item_code)
46
+ ALIASES = {
47
+ "기준금리": ("722Y001", "D", "0101000"),
48
+ "원달러환율": ("731Y001", "D", "0000001"),
49
+ "원/달러환율": ("731Y001", "D", "0000001"),
50
+ "소비자물가지수": ("901Y009", "M", "0"),
51
+ "cpi": ("901Y009", "M", "0"),
52
+ "m2": ("101Y004", "M", "BBHA00"),
53
+ "통화량": ("101Y004", "M", "BBHA00"),
54
+ "국고채3년": ("817Y002", "D", "010200000"),
55
+ }
56
+
57
+ SEGMENT_PATTERN = re.compile(r"^[A-Za-z0-9_.\-]+$")
58
+
59
+ ERROR_HINTS = {
60
+ "INFO-100": "인증키가 유효하지 않습니다. KSKILL_BOK_ECOS_API_KEY를 확인하거나 https://ecos.bok.or.kr/api 에서 키를 발급받으세요.",
61
+ "ERROR-301": "sample 키는 최대 10건까지만 조회할 수 있습니다. 더 많은 행이 필요하면 개인 키를 발급받아 KSKILL_BOK_ECOS_API_KEY로 지정하세요.",
62
+ }
63
+
64
+ EMPTY_CODES = {"INFO-200"}
65
+
66
+
67
+ class HelperError(RuntimeError):
68
+ pass
69
+
70
+
71
+ def load_secrets(path: pathlib.Path) -> Dict[str, str]:
72
+ values: Dict[str, str] = {}
73
+ try:
74
+ lines = path.read_text(encoding="utf-8").splitlines()
75
+ except OSError:
76
+ return values
77
+ for raw in lines:
78
+ line = raw.strip()
79
+ if not line or line.startswith("#") or "=" not in line:
80
+ continue
81
+ key, value = line.split("=", 1)
82
+ values[key.strip()] = value.strip().strip('"').strip("'")
83
+ return values
84
+
85
+
86
+ def resolve_api_key(secrets_path: str) -> Optional[str]:
87
+ env_value = os.environ.get("KSKILL_BOK_ECOS_API_KEY")
88
+ if env_value and env_value.strip():
89
+ return env_value.strip()
90
+ secrets = load_secrets(pathlib.Path(secrets_path).expanduser())
91
+ value = secrets.get("KSKILL_BOK_ECOS_API_KEY")
92
+ return value.strip() if value and value.strip() else None
93
+
94
+
95
+ def _check_segment(value: str, label: str) -> str:
96
+ if not SEGMENT_PATTERN.match(value or ""):
97
+ raise HelperError(f"올바른 {label} 값이 아닙니다: {value!r}")
98
+ return value
99
+
100
+
101
+ def _resolve_series(args: argparse.Namespace) -> tuple[str, str, Optional[str]]:
102
+ if args.alias:
103
+ needle = args.alias.strip().lower()
104
+ if needle not in ALIASES:
105
+ known = ", ".join(sorted(ALIASES))
106
+ raise HelperError(f"알 수 없는 alias 입니다: {args.alias!r} (지원: {known})")
107
+ stat_code, cycle, item_code = ALIASES[needle]
108
+ return stat_code, cycle, item_code
109
+ if not args.stat_code:
110
+ raise HelperError("--stat-code 또는 --alias 중 하나가 필요합니다.")
111
+ if not args.cycle:
112
+ raise HelperError("--stat-code 사용 시 --cycle(A/S/Q/M/SM/D)이 필요합니다.")
113
+ return (
114
+ _check_segment(args.stat_code, "stat-code"),
115
+ _check_segment(args.cycle, "cycle"),
116
+ _check_segment(args.item_code, "item-code") if args.item_code else None,
117
+ )
118
+
119
+
120
+ def build_url(args: argparse.Namespace, api_key: Optional[str]) -> str:
121
+ key = api_key or ECOS_DEMO_KEY
122
+ limit = max(1, args.limit)
123
+ if key == ECOS_DEMO_KEY:
124
+ limit = min(limit, SAMPLE_MAX_ROWS)
125
+
126
+ if args.command == "search":
127
+ stat_code, cycle, item_code = _resolve_series(args)
128
+ start = _check_segment(args.start, "start")
129
+ end = _check_segment(args.end, "end")
130
+ segments = [ECOS_BASE_URL, "StatisticSearch", key, "json", "kr", "1", str(limit), stat_code, cycle, start, end]
131
+ if item_code:
132
+ segments.append(item_code)
133
+ return "/".join(segments)
134
+ if args.command == "tables":
135
+ return "/".join([ECOS_BASE_URL, "StatisticTableList", key, "json", "kr", "1", str(limit)]) + "/"
136
+ if args.command == "items":
137
+ stat_code = _check_segment(args.stat_code, "stat-code")
138
+ return "/".join([ECOS_BASE_URL, "StatisticItemList", key, "json", "kr", "1", str(limit), stat_code])
139
+ if args.command == "key":
140
+ return "/".join([ECOS_BASE_URL, "KeyStatisticList", key, "json", "kr", "1", str(limit)]) + "/"
141
+ # word
142
+ query = (args.query or "").strip()
143
+ if not query:
144
+ raise HelperError("--query 검색어가 필요합니다.")
145
+ encoded = urllib.parse.quote(query, safe="")
146
+ return "/".join([ECOS_BASE_URL, "StatisticWord", key, "json", "kr", "1", str(limit), encoded])
147
+
148
+
149
+ def http_get_json(url: str, timeout: int) -> Dict[str, Any]:
150
+ request = urllib.request.Request(url, headers={"User-Agent": USER_AGENT})
151
+ try:
152
+ with urllib.request.urlopen(request, timeout=timeout) as response:
153
+ body = response.read().decode("utf-8", "replace")
154
+ except urllib.error.HTTPError as exc:
155
+ raise HelperError(f"ECOS HTTP 오류: {exc.code}") from exc
156
+ except urllib.error.URLError as exc:
157
+ raise HelperError(f"ECOS 접속 실패: {exc.reason}") from exc
158
+ try:
159
+ return json.loads(body)
160
+ except json.JSONDecodeError as exc:
161
+ raise HelperError("ECOS 응답이 JSON이 아닙니다 (차단 또는 점검 가능성).") from exc
162
+
163
+
164
+ def normalize_payload(payload: Dict[str, Any], service: str) -> List[Dict[str, Any]]:
165
+ if not isinstance(payload, dict):
166
+ raise HelperError("ECOS 응답 형식이 올바르지 않습니다.")
167
+ result = payload.get("RESULT")
168
+ if isinstance(result, dict):
169
+ code = str(result.get("CODE") or "")
170
+ if code in EMPTY_CODES:
171
+ return []
172
+ message = ERROR_HINTS.get(code) or f"ECOS 오류 [{code}]: {result.get('MESSAGE', '')}"
173
+ raise HelperError(message)
174
+ body = payload.get(service)
175
+ if not isinstance(body, dict) or not isinstance(body.get("row"), list):
176
+ raise HelperError("ECOS 응답에서 데이터 행을 찾지 못했습니다 (서비스명/파라미터 확인).")
177
+ return [row for row in body["row"] if isinstance(row, dict)]
178
+
179
+
180
+ def _project(rows: List[Dict[str, Any]], mapping: Dict[str, str]) -> List[Dict[str, Any]]:
181
+ return [{out: row.get(src) for out, src in mapping.items()} for row in rows]
182
+
183
+
184
+ PROJECTIONS = {
185
+ "search": {
186
+ "stat_code": "STAT_CODE",
187
+ "stat_name": "STAT_NAME",
188
+ "item_name": "ITEM_NAME1",
189
+ "unit": "UNIT_NAME",
190
+ "time": "TIME",
191
+ "value": "DATA_VALUE",
192
+ },
193
+ "tables": {
194
+ "stat_code": "STAT_CODE",
195
+ "stat_name": "STAT_NAME",
196
+ "cycle": "CYCLE",
197
+ "searchable": "SRCH_YN",
198
+ "org": "ORG_NAME",
199
+ },
200
+ "items": {
201
+ "stat_code": "STAT_CODE",
202
+ "item_code": "ITEM_CODE",
203
+ "item_name": "ITEM_NAME",
204
+ "cycle": "CYCLE",
205
+ "start_time": "START_TIME",
206
+ "end_time": "END_TIME",
207
+ },
208
+ "key": {
209
+ "class_name": "CLASS_NAME",
210
+ "name": "KEYSTAT_NAME",
211
+ "value": "DATA_VALUE",
212
+ "cycle": "CYCLE",
213
+ "unit": "UNIT_NAME",
214
+ },
215
+ "word": {
216
+ "word": "WORD",
217
+ "content": "CONTENT",
218
+ },
219
+ }
220
+
221
+ SERVICES = {
222
+ "search": "StatisticSearch",
223
+ "tables": "StatisticTableList",
224
+ "items": "StatisticItemList",
225
+ "key": "KeyStatisticList",
226
+ "word": "StatisticWord",
227
+ }
228
+
229
+
230
+ def render_text(command: str, rows: List[Dict[str, Any]]) -> str:
231
+ if not rows:
232
+ return "조건에 맞는 데이터가 없습니다."
233
+ lines = []
234
+ for row in rows:
235
+ if command == "search":
236
+ lines.append(f"{row['time']} · {row['item_name']}: {row['value']} {row['unit'] or ''}".rstrip())
237
+ elif command == "key":
238
+ lines.append(f"[{row['class_name']}] {row['name']}: {row['value']} {row['unit'] or ''} ({row['cycle']})")
239
+ elif command == "tables":
240
+ lines.append(f"{row['stat_code']} · {row['stat_name']} (주기 {row['cycle'] or '-'})")
241
+ elif command == "items":
242
+ lines.append(f"{row['item_code']} · {row['item_name']} ({row['cycle']}, {row['start_time']}~{row['end_time']})")
243
+ else:
244
+ lines.append(f"{row['word']}: {row['content']}")
245
+ return "\n".join(lines)
246
+
247
+
248
+ def parse_args(argv: List[str]) -> argparse.Namespace:
249
+ common = argparse.ArgumentParser(add_help=False)
250
+ common.add_argument("--secrets-path", default=str(DEFAULT_SECRETS_PATH))
251
+ common.add_argument("--timeout", type=int, default=30)
252
+ common.add_argument("--limit", type=int, default=10, help="조회 행 수 (sample 키는 최대 10)")
253
+ common.add_argument("--text", action="store_true", help="사람용 요약 출력")
254
+
255
+ parser = argparse.ArgumentParser(description="한국은행 ECOS 경제통계 조회")
256
+ subparsers = parser.add_subparsers(dest="command", required=True)
257
+
258
+ search = subparsers.add_parser("search", parents=[common], help="통계코드/alias 기반 시계열 조회")
259
+ search.add_argument("--stat-code", help="통계표 코드 (예: 722Y001)")
260
+ search.add_argument("--cycle", help="주기: A/S/Q/M/SM/D")
261
+ search.add_argument("--item-code", help="통계항목 코드 (선택)")
262
+ search.add_argument("--alias", help="자주 쓰는 지표 별칭 (기준금리/원달러환율/소비자물가지수/M2/국고채3년)")
263
+ search.add_argument("--start", required=True, help="시작 시점 (주기 형식에 맞춤, 예: 20260101, 202601, 2026)")
264
+ search.add_argument("--end", required=True, help="종료 시점")
265
+
266
+ subparsers.add_parser("tables", parents=[common], help="통계표 목록")
267
+
268
+ items = subparsers.add_parser("items", parents=[common], help="통계표의 항목 목록")
269
+ items.add_argument("--stat-code", required=True)
270
+
271
+ subparsers.add_parser("key", parents=[common], help="100대 핵심 지표 (환율/금리/물가 등)")
272
+
273
+ word = subparsers.add_parser("word", parents=[common], help="통계 용어 사전 검색")
274
+ word.add_argument("--query", required=True)
275
+
276
+ return parser.parse_args(argv)
277
+
278
+
279
+ def run(argv: List[str]) -> int:
280
+ args = parse_args(argv)
281
+ try:
282
+ api_key = resolve_api_key(args.secrets_path)
283
+ url = build_url(args, api_key)
284
+ payload = http_get_json(url, args.timeout)
285
+ raw_rows = normalize_payload(payload, SERVICES[args.command])
286
+ rows = _project(raw_rows, PROJECTIONS[args.command])
287
+ if args.text:
288
+ print(render_text(args.command, rows))
289
+ else:
290
+ print(json.dumps({
291
+ "result": "ok" if rows else "empty",
292
+ "rows": rows,
293
+ "source": "ecos.bok.or.kr Open API",
294
+ }, ensure_ascii=False, indent=2))
295
+ return 0
296
+ except HelperError as exc:
297
+ print(str(exc), file=sys.stderr)
298
+ return 1
299
+
300
+
301
+ if __name__ == "__main__":
302
+ sys.exit(run(sys.argv[1:]))
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "bok-ecos-stats",
3
+ "description": "한국은행 ECOS Open API로 기준금리, 환율, 소비자물가지수, 통화량 등 중앙은행 경제통계 시계열과 100대 핵심지표를 조회한다. Use when the user asks 기준금리, 환율 추이, 물가지수, M2, 국고채 금리, 거시경제 통계. Not for 주식 시세(korean-stock-search) or KOSIS 일반 통계(kosis-stats).",
4
+ "profiles": [
5
+ "proxy",
6
+ "vault",
7
+ "lookup"
8
+ ],
9
+ "frontmatter": "name: bok-ecos-stats\ndescription: 한국은행 ECOS Open API로 기준금리, 환율, 소비자물가지수, 통화량 등 중앙은행 경제통계 시계열과 100대 핵심지표를 조회한다. Use when the user asks 기준금리, 환율 추이, 물가지수, M2, 국고채 금리, 거시경제 통계. Not for 주식 시세(korean-stock-search) or KOSIS 일반 통계(kosis-stats).\nlicense: MIT\nmetadata:\n category: data\n locale: ko-KR\n phase: v1"
10
+ }
@@ -0,0 +1,69 @@
1
+ # Building Register Search
2
+
3
+ ## What this skill does
4
+
5
+ 국토교통부 건축물대장정보 서비스의 표제부(`getBrTitleInfo`)를 조회한다. 주소, 19자리 PNU, 또는 법정동 코드와 지번을 입력받아 주용도, 연면적, 지상/지하 층수, 사용승인일, 관리번호와 주소 식별 필드를 반환한다.
6
+
7
+ 이 스킬은 건축물의 행정대장 정보만 조회한다. 소유권, 근저당, 가압류 등 권리관계는 확인하지 않으며, 그 목적에는 별도 `iros-registry-automation` 스킬을 사용한다.
8
+
9
+ ## Official access path
10
+
11
+ 1. 공공데이터포털 데이터셋 `15134735`
12
+ 2. 공식 endpoint `https://apis.data.go.kr/1613000/BldRgstHubService/getBrTitleInfo`
13
+ 3. portable XML 응답을 프록시가 파싱해 JSON으로 정규화
14
+ 4. 주소 입력 시 hosted/self-host proxy의 `/v1/kakao-local/geocode?q=...`로 법정동 `b_code`와 지번을 확정한 뒤 `/v1/building-register/title` 호출
15
+
16
+ 공식 API가 기본 경로이며 화면 scraping이나 비공식 endpoint로 우회하지 않는다.
17
+
18
+ ## Commands
19
+
20
+ ```bash
21
+ python3 scripts/building_register.py title --address '서울 강남구 역삼동 123-4'
22
+ python3 scripts/building_register.py title --pnu 1168010100101230004
23
+ python3 scripts/building_register.py title --sigungu-cd 11680 --bjdong-cd 10100 --plat-gb-cd 0 --bun 123 --ji 4
24
+ python3 scripts/building_register.py title --pnu 1168010100101230004 --json
25
+ ```
26
+
27
+ PNU는 `sigunguCd(5) + bjdongCd(5) + 토지구분(1) + bun(4) + ji(4)`의 19자리다. PNU 토지구분 `1`(일반 토지)은 건축물대장 API `platGbCd=0`, `2`(산)는 `platGbCd=1`로 변환한다. 개별 필드나 주소 결과로 PNU를 구성할 때도 API 값 `0`은 PNU `1`, API 값 `1`은 PNU `2`로 역변환한다. `--plat-gb-cd`를 직접 입력할 때는 PNU 값이 아니라 건축물대장 API 값이며 공식 값 `0`, `1`, `2`를 허용한다. API 값 `2`는 그대로 조회에 전달하되 대응하는 표준 PNU 토지구분이 없으므로 PNU를 구성하지 않는다. 개별 입력의 `bun`, `ji`는 4자리로 왼쪽 zero-padding되며 `ji` 생략 시 `0000`이다. `pageNo` 기본값은 1, `numOfRows` 기본값은 10이고 최대 100이다.
28
+
29
+ 주소 입력은 proxy mode 전용이다. Kakao 응답에서 정확히 하나의 주소, 10자리 법정동 `b_code`, 본번, 산 여부를 얻어야 한다. 결과가 여러 개이거나 장소명 fallback만 있거나 필지 정보가 빠졌으면 추정하지 않고 중단한다.
30
+
31
+ ## Direct mode
32
+
33
+ ```bash
34
+ python3 scripts/building_register.py title --pnu 1168010100101230004 --direct
35
+ python3 scripts/building_register.py title --pnu 1168010100101230004 --direct --dry-run
36
+ ```
37
+
38
+ `--direct`는 주소를 받지 않는다. `KSKILL_BUILDING_REGISTER_API_KEY`, 그다음 `DATA_GO_KR_API_KEY`, 마지막으로 `~/.config/k-skill/secrets.env`의 같은 키 순서로 찾는다. Kakao direct credential은 사용하지 않는다. `--dry-run`은 실제 키를 `REDACTED`로 가린다.
39
+
40
+ hosted proxy 사용자는 키가 필요 없다. self-host 운영자 또는 direct 사용자는 공공데이터포털 키 발급과 별개로 데이터셋 `15134735`에 **별도 활용신청**해야 한다. 이 데이터셋은 자동승인 대상이지만 활성화 전 호출은 인증 오류가 될 수 있다.
41
+
42
+ ## Output
43
+
44
+ 기본 출력은 한국어 요약이고 `--json`은 정규화된 payload를 출력한다. 주요 필드는 `mgmBldrgstPk`, `regstrKindCdNm`, `platPlc`, `newPlatPlc`, `sigunguCd`, `bjdongCd`, `platGbCd`, `bun`, `ji`, `mainPurpsCdNm`, `totArea`, `grndFlrCnt`, `ugrndFlrCnt`, `useAprDay`다. API가 제공한 그 밖의 유용한 표제부 원문 필드와 데이터셋/operation/upstream/XML source metadata도 보존한다.
45
+
46
+ ## Fallback order
47
+
48
+ 1. PNU가 있으면 바로 건축물대장 route를 호출한다.
49
+ 2. 법정동 코드와 필지가 있으면 건축물대장 API 의미의 개별 필드로 같은 route를 호출한다.
50
+ 3. 주소만 있으면 proxy Kakao geocode로 법정동 코드와 필지를 확정한 뒤 building route를 호출한다.
51
+ 4. 주소가 모호하거나 필지가 없으면 사용자에게 더 정확한 지번 주소 또는 PNU를 요청한다.
52
+ 5. official API 장애, 인증/쿼터 오류에는 비공식 데이터로 대체하지 않는다.
53
+
54
+ ## Failure modes
55
+
56
+ - empty result: 해당 필지에 표제부가 없거나 입력 코드/지번이 맞지 않음
57
+ - ambiguous address: Kakao 결과가 하나로 확정되지 않음
58
+ - missing parcel or `b_code`: 장소명/도로명만으로 필지를 확정할 수 없음
59
+ - `upstream_not_configured`: self-host proxy에 `DATA_GO_KR_API_KEY`가 없음
60
+ - HTTP 401/403 or semantic auth XML: 데이터셋 `15134735` 활용신청/활성화 확인
61
+ - quota/service limit: 공공데이터포털 이용량과 서비스 상태 확인 후 재시도
62
+ - empty/invalid XML: upstream 응답 오류로 처리하며 캐시하지 않음
63
+ - proxy down: 잠시 후 재시도하거나 self-host 운영자에게 문의
64
+
65
+ ## Done when
66
+
67
+ - 주소 또는 PNU/법정동+필지 입력이 하나의 조회 필지로 정규화됐다.
68
+ - 표제부 결과와 source metadata를 제공했거나 명시적 실패 모드로 중단했다.
69
+ - 건축물대장 정보와 등기부 권리관계를 혼동하지 않았다.