@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,81 @@
1
+ # KERIS Academic Search
2
+
3
+ ## What this skill does
4
+
5
+ KERIS가 운영하는 RISS 검색 Open API에서 학위논문, 국내외 학술논문, 단행본, 연구보고서, 학술지 메타데이터를 조회한다. 제목, 저자, 발행처, 연도, RISS 상세 링크, API가 반환한 원문 유무/무료 표시를 요약한다.
6
+
7
+ 조회 전용이다. 기관 로그인, 구독 권한 우회, 복사·대출 신청, 유료 결제, 원문 다운로드는 자동화하지 않는다.
8
+
9
+ ## Official access path
10
+
11
+ 1. 기본 경로: 사용자 본인의 RISS 검색 API 키로 상류(`https://www.riss.kr/openApi`)를 직접 호출한다. 이 스킬은 `k-skill-proxy`를 사용하지 않는다.
12
+ 2. 상류 계약: `key`, `version=1.0`, `type`별 XML, `rsnum`, `rowcount(최대 100)`
13
+ 3. 공식 문서: RISS API 센터(<https://www.riss.kr/apicenter/apiMain.do>)의 학위논문/국내학술논문/해외학술논문/단행본/연구보고서/학술지 검색 API 정보
14
+
15
+ ### RISS API 키 발급
16
+
17
+ RISS 검색 Open API 키는 **공익 목적의 비영리 기관/대학에만** 무료로 발급된다(향후 민간 확대 예정). data.go.kr 키와 완전히 별개다.
18
+
19
+ 1. RISS(<https://www.riss.kr>)에 기관 소속으로 회원가입/로그인
20
+ 2. RISS API 센터 → **RISS 검색 API** 선택 → 이용신청(<https://riss.kr/openAPI/OpenApiRegisterFinal.do>)
21
+ 3. KERIS 담당자 심사·승인 후 인증키(`key` 파라미터) 발급
22
+ 4. 발급받은 키를 `KSKILL_RISS_API_KEY`(호환 `RISS_API_KEY`) 환경변수 또는 `~/.config/k-skill/secrets.env`에 설정
23
+
24
+ 공공데이터포털 데이터셋 `15071949`는 RISS 종합목록의 정적 파일/카탈로그 현황 관련 표면이다. 기사·논문 검색 API가 아니므로 검색 fallback으로 사용하지 않는다. 데이터셋 `3046254`는 관련 카탈로그 항목이지만 실제 검색 계약은 RISS API 센터와 `/openApi`를 기준으로 한다.
25
+
26
+ ## Commands
27
+
28
+ ```bash
29
+ python3 scripts/keris_academic.py search --keyword '인공지능 교육'
30
+ python3 scripts/keris_academic.py search --title '대학도서관' --author '김연구' --resource-type T
31
+ python3 scripts/keris_academic.py search --keyword '한국어 교육' --resource-type D --page 2 --page-size 20 --json
32
+ ```
33
+
34
+ 검색 필드는 `keyword`, `title`, `author`, `subject`, `publisher`이며 하나 이상 필요하다. `page`는 1 이상, `pageSize`는 1~100이다. RISS의 `rsnum`은 `(page-1)*pageSize+1`로 계산한다. 실제 호출에는 사용자 RISS 키가 필요하다.
35
+
36
+ 여러 upstream type을 합치는 `ALL`과 `A`는 첫 페이지에서 type별 결과를 round-robin으로 합친다. 정확한 후속 페이지가 필요하면 `T`, `D`, `B` 또는 실제 단일 자료유형 검색을 사용한다. 결합 검색은 upstream을 type 수만큼 호출한다.
37
+
38
+ 사용자 resource type alias:
39
+
40
+ - `ALL`: 공식 `T/A/O/U/F/S`를 모아 최대 `pageSize`건 반환
41
+ - `T`: 학위논문, 공식 `T`
42
+ - `A`: 국내+해외 학술논문, 공식 `A/O`
43
+ - `D`: 국내 학술논문(domestic article) 호환 alias, 공식 `A`
44
+ - `B`: 단행본(book) 호환 alias, 공식 `U`
45
+
46
+ 응답 item의 `resource_type`에는 alias가 아니라 실제 RISS 코드를 보존한다.
47
+
48
+ ## Credentials
49
+
50
+ ```bash
51
+ python3 scripts/keris_academic.py search --keyword '교육 데이터' --resource-type ALL --dry-run
52
+ ```
53
+
54
+ - RISS 키: `KSKILL_RISS_API_KEY`, 없으면 compatibility `RISS_API_KEY`, 이후 `~/.config/k-skill/secrets.env`
55
+ - `DATA_GO_KR_API_KEY`는 RISS 검색에 사용하지 않는다
56
+ - `--dry-run`은 키를 발급받기 전에도 호출 URL을 확인할 수 있으며 키를 `REDACTED`로 표시한다
57
+ - 키가 없으면 실행을 중단하고 RISS API 센터 발급 안내를 출력한다
58
+
59
+ ## Output and fallback order
60
+
61
+ 1. 검색 성공 결과를 제목, 저자, 발행처/학술지, 연도, 링크, 원문 상태로 요약한다.
62
+ 2. 키가 없으면 RISS API 센터에서 검색 API 키를 발급받도록 안내한다.
63
+ 3. RISS 장애/쿼터/파싱 오류를 웹 scraping이나 data.go.kr `15071949`로 대체하지 않는다.
64
+ 4. 빈 결과는 성공(`items: []`)으로 유지하고 검색어/자료유형을 조정한다.
65
+
66
+ ## Failure modes
67
+
68
+ - missing key: 실행 중단 + RISS API 센터 키 발급 안내(exit 1)
69
+ - invalid input: 입력 검증 오류 메시지(exit 1)
70
+ - RISS 인증 오류 또는 HTTP 401/403: 키/기관 권한 확인 안내(exit 1)
71
+ - 호출량/쿼터 초과 또는 HTTP 429: 쿼터 초과 안내(exit 1)
72
+ - upstream network/HTTP failure: 네트워크/HTTP 오류 메시지(exit 1)
73
+ - empty/malformed/unexpected XML: XML 파싱 오류 메시지(exit 1)
74
+ - empty result: 성공 응답과 빈 `items`
75
+ - login/licensed full text: 상세 링크만 제공하고 자동 다운로드하지 않음
76
+
77
+ ## Done when
78
+
79
+ - 검색 조건과 실제 RISS 자료유형이 명시됐다.
80
+ - 결과 또는 typed failure를 제공했다.
81
+ - 원문 유무 표시는 API 값으로만 설명했고 접근권한을 보장하거나 다운로드를 자동화하지 않았다.
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env python3
2
+ """Read-only KERIS/RISS academic metadata search helper using stdlib only.
3
+
4
+ RISS 검색 Open API는 기관/대학 전용 인증키를 요구하므로 k-skill-proxy를 거치지
5
+ 않고, 사용자가 직접 발급받은 RISS 키로 상류(``https://www.riss.kr/openApi``)를
6
+ 호출한다.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import json
13
+ import os
14
+ import pathlib
15
+ import sys
16
+ import urllib.error
17
+ import urllib.parse
18
+ import urllib.request
19
+ import xml.etree.ElementTree as ET
20
+ from typing import Any, Dict, List, Optional
21
+
22
+ DEFAULT_SECRETS_PATH = pathlib.Path("~/.config/k-skill/secrets.env").expanduser()
23
+ RISS_OPEN_API_URL = "https://www.riss.kr/openApi"
24
+ RESOURCE_TYPE_MAP = {"ALL": ["T", "A", "O", "U", "F", "S"], "T": ["T"], "A": ["A", "O"], "D": ["A"], "B": ["U"]}
25
+ MISSING_KEY_MSG = (
26
+ "RISS API 키가 없습니다. RISS API 센터(https://www.riss.kr/apicenter/apiMain.do)에서 "
27
+ "검색 API 키를 발급받아 KSKILL_RISS_API_KEY(호환 RISS_API_KEY) 환경변수 또는 "
28
+ "~/.config/k-skill/secrets.env 에 설정하세요. RISS 키는 비영리 기관/대학에 발급됩니다."
29
+ )
30
+
31
+
32
+ class HelperError(RuntimeError):
33
+ pass
34
+
35
+
36
+ def load_secrets(path: pathlib.Path) -> Dict[str, str]:
37
+ try:
38
+ lines = path.read_text(encoding="utf-8").splitlines()
39
+ except OSError:
40
+ return {}
41
+ values = {}
42
+ for raw in lines:
43
+ line = raw.strip()
44
+ if line and not line.startswith("#") and "=" in line:
45
+ key, value = line.split("=", 1)
46
+ values[key.strip()] = value.strip().strip('"').strip("'")
47
+ return values
48
+
49
+
50
+ def resolve_api_key(args: argparse.Namespace) -> Optional[str]:
51
+ for name in ("KSKILL_RISS_API_KEY", "RISS_API_KEY"):
52
+ value = os.environ.get(name)
53
+ if value and value.strip():
54
+ return value.strip()
55
+ secrets = load_secrets(pathlib.Path(args.secrets_path).expanduser())
56
+ value = secrets.get("KSKILL_RISS_API_KEY") or secrets.get("RISS_API_KEY")
57
+ return value.strip() if value and value.strip() else None
58
+
59
+
60
+ def build_query(args: argparse.Namespace) -> Dict[str, Any]:
61
+ query = {}
62
+ for field in ("keyword", "title", "author", "subject", "publisher"):
63
+ value = getattr(args, field)
64
+ if value and value.strip():
65
+ text = value.strip()
66
+ if len(text) > 200 or any(ord(char) < 32 or ord(char) == 127 for char in text):
67
+ raise HelperError(f"{field} 값은 1~200자의 일반 텍스트여야 합니다.")
68
+ query[field] = text
69
+ if not query:
70
+ raise HelperError("--keyword, --title, --author, --subject, --publisher 중 하나 이상을 입력하세요.")
71
+ if not 1 <= args.page <= 100000:
72
+ raise HelperError("page 값은 1~100000 범위여야 합니다.")
73
+ if not 1 <= args.page_size <= 100:
74
+ raise HelperError("pageSize 값은 1~100 범위여야 합니다.")
75
+ if len(RESOURCE_TYPE_MAP[args.resource_type]) > 1 and args.page > 1:
76
+ raise HelperError("Combined resourceType searches support page 1 only; later pages require a single resource type.")
77
+ query.update({"resourceType": args.resource_type, "page": args.page, "pageSize": args.page_size})
78
+ return query
79
+
80
+
81
+ def build_riss_urls(query: Dict[str, Any], api_key: str) -> List[str]:
82
+ rsnum = ((query["page"] - 1) * query["pageSize"]) + 1
83
+ urls = []
84
+ for upstream_type in RESOURCE_TYPE_MAP[query["resourceType"]]:
85
+ params = {key: value for key, value in query.items() if key not in {"resourceType", "page", "pageSize"}}
86
+ params.update({"key": api_key, "version": "1.0", "type": upstream_type, "rsnum": rsnum, "rowcount": query["pageSize"]})
87
+ urls.append(f"{RISS_OPEN_API_URL}?{urllib.parse.urlencode(params)}")
88
+ return urls
89
+
90
+
91
+ def parse_riss_xml(raw: bytes) -> Dict[str, Any]:
92
+ try:
93
+ root = ET.fromstring(raw)
94
+ except ET.ParseError as error:
95
+ raise HelperError("RISS API 응답 XML이 올바르지 않습니다.") from error
96
+ if root.tag != "record":
97
+ raise HelperError("RISS API 응답 envelope가 올바르지 않습니다.")
98
+ error_text = root.findtext("./head/Error")
99
+ if error_text is None or not error_text.strip():
100
+ raise HelperError("RISS API 응답에 상태 메타데이터가 없습니다.")
101
+ code = error_text.strip()
102
+ message = (root.findtext("./head/ErrorMessage") or "Unknown RISS error").strip()
103
+ if code not in {"0", "000"}:
104
+ raise HelperError(f"RISS API 오류 {code}: {message}")
105
+ items = []
106
+ for metadata in root.findall("./metadata"):
107
+ values: Dict[str, List[str]] = {}
108
+ for child in metadata:
109
+ value = "".join(child.itertext()).strip()
110
+ if value:
111
+ values.setdefault(child.tag.removeprefix("riss.").lower(), []).append(value)
112
+ first = lambda key: values.get(key, [None])[0]
113
+ image, charge = (first("image") or "").upper(), first("charge")
114
+ available = True if image == "Y" else False if image == "N" else None
115
+ access = "free" if available and charge == "1" else "paid_or_restricted" if available and charge == "0" else "available" if available else "none" if available is False else "unknown"
116
+ author = first("author") or ""
117
+ authors = [part.strip() for part in author.replace(";", ",").split(",") if part.strip()] or ([author] if author else [])
118
+ items.append({"resource_type": first("type"), "title": first("title"), "authors": authors, "publisher": first("publisher"), "year": first("pubdate"), "publication": first("stitle"), "material_type": first("mtype"), "link": first("url"), "full_text_available": available, "full_text_access": access, "holdings": values.get("holdings", [])})
119
+ total_text = root.findtext("./head/totalcount")
120
+ try:
121
+ total_count = int(total_text) if total_text is not None else len(items)
122
+ except ValueError as error:
123
+ raise HelperError("RISS API 응답 totalcount가 올바른 정수가 아닙니다.") from error
124
+ if total_count < 0:
125
+ raise HelperError("RISS API 응답 totalcount가 음수입니다.")
126
+ return {"total_count": total_count, "items": items}
127
+
128
+
129
+ def http_get_riss_xml(urls: List[str], timeout: int, page: int, page_size: int) -> Dict[str, Any]:
130
+ results = []
131
+ for url in urls:
132
+ request = urllib.request.Request(url, headers={"accept": "application/xml", "user-agent": "k-skill/keris-academic-search"})
133
+ try:
134
+ with urllib.request.urlopen(request, timeout=timeout) as response:
135
+ results.append(parse_riss_xml(response.read()))
136
+ except urllib.error.HTTPError as error:
137
+ if error.code in (401, 403):
138
+ raise HelperError("RISS API가 키를 거부했습니다(HTTP 403). 발급받은 RISS 검색 API 키와 기관 권한을 확인하세요.") from error
139
+ if error.code == 429:
140
+ raise HelperError("RISS API 호출량/쿼터를 초과했습니다(HTTP 429).") from error
141
+ raise HelperError(f"RISS API 요청 실패: HTTP {error.code} {error.reason}") from error
142
+ except urllib.error.URLError as error:
143
+ raise HelperError(f"RISS API 네트워크 오류: {error.reason}") from error
144
+ except TimeoutError as error:
145
+ raise HelperError("RISS API 요청 시간이 초과되었습니다.") from error
146
+ queues = [list(result["items"]) for result in results]
147
+ items = []
148
+ while len(items) < page_size and any(queues):
149
+ for queue in queues:
150
+ if queue:
151
+ items.append(queue.pop(0))
152
+ if len(items) >= page_size:
153
+ break
154
+ return {"page": page, "page_size": page_size, "total_count": sum(result["total_count"] for result in results), "items": items}
155
+
156
+
157
+ def format_text(payload: Dict[str, Any]) -> str:
158
+ items = payload.get("items") or []
159
+ lines = [f"RISS 학술자료 검색 결과: {payload.get('total_count', len(items))}건"]
160
+ labels = {"free": "원문 있음(무료 표시)", "paid_or_restricted": "원문 있음(유료/기관권한 가능)", "available": "원문 있음(접근조건 확인 필요)", "none": "원문 없음", "unknown": "원문 여부 미상"}
161
+ for item in items:
162
+ lines.append(f"- {item.get('title') or '제목 없음'} / {', '.join(item.get('authors') or []) or '저자 미상'} / {item.get('publisher') or item.get('publication') or '발행처 미상'} / {item.get('year') or '연도 미상'} / {labels.get(item.get('full_text_access'), '원문 여부 미상')}")
163
+ if item.get("link"):
164
+ lines.append(f" {item['link']}")
165
+ if not items:
166
+ lines.append("조건에 맞는 학술자료가 없습니다.")
167
+ return "\n".join(lines)
168
+
169
+
170
+ def build_parser() -> argparse.ArgumentParser:
171
+ parser = argparse.ArgumentParser(description="KERIS/RISS 학술자료 메타데이터 검색")
172
+ search = parser.add_subparsers(dest="command", required=True).add_parser("search")
173
+ for field in ("keyword", "title", "author", "subject", "publisher"):
174
+ search.add_argument(f"--{field}")
175
+ search.add_argument("--resource-type", choices=RESOURCE_TYPE_MAP, default="ALL")
176
+ search.add_argument("--page", type=int, default=1)
177
+ search.add_argument("--page-size", type=int, default=10)
178
+ search.add_argument("--secrets-path", default=str(DEFAULT_SECRETS_PATH))
179
+ search.add_argument("--timeout", type=int, default=20)
180
+ search.add_argument("--dry-run", action="store_true")
181
+ search.add_argument("--json", action="store_true")
182
+ return parser
183
+
184
+
185
+ def parse_args(argv: Optional[List[str]] = None) -> argparse.Namespace:
186
+ return build_parser().parse_args(argv)
187
+
188
+
189
+ def run(argv: Optional[List[str]] = None) -> int:
190
+ try:
191
+ args = parse_args(argv)
192
+ query = build_query(args)
193
+ if args.dry_run:
194
+ urls = build_riss_urls(query, "REDACTED")
195
+ print(json.dumps({"operation": "search", "urls": urls, "query": query}, ensure_ascii=False, indent=2))
196
+ return 0
197
+ api_key = resolve_api_key(args)
198
+ if not api_key:
199
+ raise HelperError(MISSING_KEY_MSG)
200
+ urls = build_riss_urls(query, api_key)
201
+ payload = http_get_riss_xml(urls, args.timeout, query["page"], query["pageSize"])
202
+ print(json.dumps(payload, ensure_ascii=False, indent=2) if args.json else format_text(payload))
203
+ return 0
204
+ except HelperError as error:
205
+ print(str(error), file=sys.stderr)
206
+ return 1
207
+
208
+
209
+ if __name__ == "__main__":
210
+ raise SystemExit(run())
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "keris-academic-search",
3
+ "description": "Use when the user asks to search Korean theses, academic articles, research reports, journals, or university-library catalog metadata through KERIS RISS. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.",
4
+ "profiles": [
5
+ "proxy",
6
+ "vault",
7
+ "action:booking"
8
+ ],
9
+ "frontmatter": "name: keris-academic-search\ndescription: Use when the user asks to search Korean theses, academic articles, research reports, journals, or university-library catalog metadata through KERIS RISS. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.\nlicense: MIT\nmetadata:\n category: research\n locale: ko-KR\n phase: v1"
10
+ }
@@ -0,0 +1,92 @@
1
+ # K League Results
2
+
3
+ ## What this skill does
4
+
5
+ 공식 K리그 JSON 표면으로 특정 날짜의 K리그1/K리그2 경기 결과를 조회하고, 필요하면 특정 팀(예: `FC서울`, `서울 이랜드`, 팀 코드 `K09`)만 필터링한 뒤 현재 순위까지 함께 정리한다.
6
+
7
+ ## When to use
8
+
9
+ - "오늘 K리그1 경기 결과 알려줘"
10
+ - "2026-03-22 FC서울 경기 결과랑 현재 순위 보여줘"
11
+ - "2026-03-22 K리그2 결과 정리해줘"
12
+
13
+ ## Prerequisites
14
+
15
+ - Node.js 18+
16
+ - `npm install -g kleague-results`
17
+
18
+ ## Inputs
19
+
20
+ - 날짜: `YYYY-MM-DD`
21
+ - 리그: `K리그1` 또는 `K리그2` (기본값은 `K리그1`)
22
+ - 선택 사항: 팀명, 풀네임, 팀 코드 (`서울`, `FC서울`, `K09` 등)
23
+
24
+ ## Workflow
25
+
26
+ ### 0. Install the package globally when missing
27
+
28
+ `npm root -g` 아래에 `kleague-results` 가 없으면 HTML scraping 으로 우회하지 말고 먼저 전역 Node 패키지 설치를 시도한다.
29
+
30
+ ```bash
31
+ npm install -g kleague-results
32
+ ```
33
+
34
+ ### 1. Fetch the official K League JSON
35
+
36
+ 이 스킬은 HTML 크롤링 대신 아래 공식 JSON 엔드포인트를 사용한다.
37
+
38
+ - 일정/결과: `https://www.kleague.com/getScheduleList.do`
39
+ - 팀 순위: `https://www.kleague.com/record/teamRank.do`
40
+
41
+ ```bash
42
+ GLOBAL_NPM_ROOT="$(npm root -g)" node --input-type=module - <<'JS'
43
+ import path from "node:path";
44
+ import { pathToFileURL } from "node:url";
45
+
46
+ const entry = pathToFileURL(
47
+ path.join(process.env.GLOBAL_NPM_ROOT, "kleague-results", "src", "index.js"),
48
+ ).href;
49
+ const { getKLeagueSummary } = await import(entry);
50
+
51
+ const summary = await getKLeagueSummary("2026-03-22", {
52
+ leagueId: "K리그1",
53
+ team: "FC서울",
54
+ includeStandings: true,
55
+ });
56
+
57
+ console.log(JSON.stringify(summary, null, 2));
58
+ JS
59
+ ```
60
+
61
+ ### 2. Normalize for humans
62
+
63
+ 원본 JSON을 그대로 던지지 말고 아래 기준으로 정리한다.
64
+
65
+ - 홈팀 vs 원정팀
66
+ - 경기 시간 / 경기 종료 여부
67
+ - 스코어
68
+ - 현재 순위
69
+ - 요청 팀이 있으면 해당 팀 경기만 필터링
70
+
71
+ ### 3. Keep the answer compact
72
+
73
+ 요청이 scoreboard 면 경기별 한 줄 요약부터 준다. 특정 팀 요청이면 그 팀 경기와 현재 순위만 먼저 보여준다.
74
+
75
+ ## Done when
76
+
77
+ - 날짜 기준 경기 요약이 있다
78
+ - 팀 요청이면 해당 팀 경기만 남아 있다
79
+ - 현재 순위가 같이 정리되어 있다
80
+
81
+ ## Failure modes
82
+
83
+ - K리그 사이트가 `getScheduleList.do` 또는 `teamRank.do` 응답 구조를 바꾸면 패키지 수정이 필요하다
84
+ - 경기 전 날짜면 결과 대신 예정 상태가 반환될 수 있다
85
+ - `서울` 처럼 짧은 이름만 주면 리그에 따라 `FC서울` / `서울 이랜드` 구분이 필요할 수 있다
86
+
87
+ ## Notes
88
+
89
+ - 이 스킬은 조회 전용이다
90
+ - 사용자의 "오늘/어제" 요청은 항상 절대 날짜(`YYYY-MM-DD`)로 변환해서 실행한다
91
+ - 패키지를 새로 추가한 상태라면 머지 후 npm publish(Changesets 기반)를 진행해야 전역 설치 흐름이 살아난다
92
+ - 자세한 사용 예시는 `docs/features/kleague-results.md` 와 `packages/kleague-results/README.md` 를 따른다
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "kleague-results",
3
+ "description": "케이리그 경기 결과와 현재 순위를 날짜/팀 기준으로 조회한다. 공식 JSON 엔드포인트와 kleague-results npm 패키지를 사용한다.",
4
+ "profiles": [
5
+ "lookup"
6
+ ],
7
+ "frontmatter": "name: kleague-results\ndescription: 케이리그 경기 결과와 현재 순위를 날짜/팀 기준으로 조회한다. 공식 JSON 엔드포인트와 kleague-results npm 패키지를 사용한다.\nlicense: MIT\nmetadata:\n category: sports\n locale: ko-KR\n phase: v1"
8
+ }
@@ -0,0 +1,109 @@
1
+ # KOPIS Performance Search
2
+
3
+ ## What this skill does
4
+
5
+ KOPIS 공연예술통합전산망 Open API `https://kopis.or.kr/openApi/restful` 을 `k-skill-proxy` 경유로 호출한다. `www.kopis.or.kr` redirect는 일부 요청을 차단할 수 있어 canonical host를 직접 사용한다.
6
+
7
+ 지원 endpoint:
8
+
9
+ - `GET /v1/kopis/performances` → `pblprfr` 공연 목록
10
+ - `GET /v1/kopis/performances/{id}` → `pblprfr/{mt20id}` 공연 상세
11
+ - `GET /v1/kopis/facilities` → `prfplc` 공연시설 목록
12
+ - `GET /v1/kopis/facilities/{id}` → `prfplc/{mt10id}` 공연시설 상세
13
+
14
+ 예매, 좌석 선점, 결제 자동화는 범위 밖이다.
15
+
16
+ ## When to use
17
+
18
+ - "이번 달 서울 공연 KOPIS에서 찾아줘"
19
+ - "공연 ID PF132236 상세 보여줘"
20
+ - "세종문화회관 KOPIS 시설 정보 찾아줘"
21
+
22
+ ## Prerequisites
23
+
24
+ - 인터넷 연결
25
+ - hosted/self-host `k-skill-proxy`의 `/v1/kopis/*` route 접근 가능
26
+
27
+ ## Credential requirements
28
+
29
+ - 사용자 측 필수 시크릿 없음.
30
+ - `KSKILL_PROXY_BASE_URL` — self-host·별도 프록시를 쓸 때만 설정. 비우면 기본 hosted `https://k-skill-proxy.nomadamas.org` 를 사용한다.
31
+ - `KOPIS_API_KEY` 또는 `KSKILL_KOPIS_API_KEY` 는 프록시 운영 서버 환경에만 둔다.
32
+
33
+ 키 발급: KOPIS Open API 안내 <https://www.kopis.or.kr/por/cs/openapi/openApiInfo.do?menuId=MNU_00074> 에서 회원가입/로그인 후 OpenAPI 이용신청으로 발급한다.
34
+
35
+ ## Inputs
36
+
37
+ 공연 목록:
38
+
39
+ - `start`/`stdate`: 시작일 `YYYYMMDD`
40
+ - `end`/`eddate`: 종료일 `YYYYMMDD`
41
+ - `genre`/`shcate`: 장르 코드
42
+ - `areaCode`/`signgucode`: 지역 코드
43
+ - `sigunguCode`/`signgucodesub`: 시군구 코드
44
+ - `prfstate`, `kidstate`, `openrun`, `afterdate`
45
+ - `page`/`cpage`, `limit`/`rows`
46
+
47
+ 시설 목록:
48
+
49
+ - `q`/`query`/`name`/`shprfnmfct`: 시설명
50
+ - `areaCode`/`signgucode`, `sigunguCode`/`signgucodesub`
51
+ - `fcltychartr`, `afterdate`
52
+ - `page`/`cpage`, `limit`/`rows`
53
+
54
+ ## Workflow
55
+
56
+ ### 1. Search a small list first
57
+
58
+ ```bash
59
+ BASE="${KSKILL_PROXY_BASE_URL:-https://k-skill-proxy.nomadamas.org}"
60
+ curl -fsS --get "$BASE/v1/kopis/performances" \
61
+ --data-urlencode "start=20260701" \
62
+ --data-urlencode "end=20260731" \
63
+ --data-urlencode "areaCode=11" \
64
+ --data-urlencode "limit=10"
65
+ ```
66
+
67
+ ### 2. Fetch details for a selected ID
68
+
69
+ ```bash
70
+ curl -fsS "$BASE/v1/kopis/performances/PF132236"
71
+ ```
72
+
73
+ 시설명으로 먼저 찾은 뒤 시설 ID가 필요하면 상세를 조회한다.
74
+
75
+ ```bash
76
+ curl -fsS --get "$BASE/v1/kopis/facilities" \
77
+ --data-urlencode "q=세종문화회관" \
78
+ --data-urlencode "limit=5"
79
+ ```
80
+
81
+ ## Failure modes
82
+
83
+ - `400 bad_request`: 날짜 형식, 페이지 크기, ID 형식이 잘못됨.
84
+ - `503 upstream_not_configured`: 프록시 서버에 `KOPIS_API_KEY`/`KSKILL_KOPIS_API_KEY` 없음.
85
+ - KOPIS upstream XML 에러/빈 결과: 검색 기간·지역·장르를 완화하거나 ID를 다시 확인한다.
86
+ - KOPIS 공식 가이드는 오류 XML 스키마를 명확히 열거하지 않는다. live 응답의 XML 본문을 그대로 확인한다.
87
+
88
+ ## Done when
89
+
90
+ - 목록 검색은 날짜 범위를 좁혀 수행했다.
91
+ - 상세 답변은 KOPIS `mt20id` 또는 `mt10id`를 함께 명시했다.
92
+ - 공연명, 기간, 장소, 상태, 출처 endpoint를 원문 필드 기준으로 요약했다.
93
+ - 예매/결제/좌석 자동화로 넘어가지 않았다.
94
+
95
+ ## Maintainer review notes
96
+
97
+ 키 없이 가능한 검증:
98
+
99
+ - `./scripts/validate-skills.sh`
100
+ - `node --test packages/k-skill-proxy/test/server.test.js`
101
+ - `curl -i --get "$KSKILL_PROXY_BASE_URL/v1/kopis/performances" --data-urlencode "start=20260701" --data-urlencode "end=20260731"` (키 미설정이면 503 확인)
102
+
103
+ Live smoke는 hosted/self-host proxy에 `KOPIS_API_KEY`가 설정된 뒤 수행한다.
104
+
105
+ ## Safety notes
106
+
107
+ - 조회 전용 스킬이다.
108
+ - 예매, 좌석 선점, 결제, 로그인 자동화는 하지 않는다.
109
+ - 인증키는 프록시 서버에서만 다루며 repo/GitHub Actions/public docs에 저장하지 않는다.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "kopis-performance-search",
3
+ "description": "KOPIS 공연 목록·상세·시설을 조회하고, 돌쇠에서는 공식 예매처의 좌석·예약·승인 기반 결제까지 이어간다.",
4
+ "profiles": [
5
+ "proxy",
6
+ "vault",
7
+ "action:booking"
8
+ ],
9
+ "frontmatter": "name: kopis-performance-search\ndescription: KOPIS 공연 목록·상세·시설을 조회하고, 돌쇠에서는 공식 예매처의 좌석·예약·승인 기반 결제까지 이어간다.\nlicense: MIT\nmetadata:\n category: culture\n locale: ko-KR\n phase: v1"
10
+ }
@@ -0,0 +1,93 @@
1
+ # Korea Weather
2
+
3
+ ## What this skill does
4
+
5
+ 기상청 단기예보 조회서비스를 `k-skill-proxy` 경유로 조회해서 한국 날씨를 요약한다.
6
+ 사용자는 개인 OpenAPI key를 직접 발급할 필요가 없고, proxy 서버에만 `KMA_OPEN_API_KEY` 를 둔다.
7
+
8
+ ## When to use
9
+
10
+ - "서울 시청 근처 지금 날씨 어때?"
11
+ - "부산 날씨 알려줘"
12
+ - "위도/경도 기준으로 한국 단기예보 보고 싶어"
13
+
14
+ ## Prerequisites
15
+
16
+ - optional: `jq`
17
+ - optional: `KSKILL_PROXY_BASE_URL` (self-host·별도 프록시를 쓸 때만 설정. 비우면 기본 hosted `https://k-skill-proxy.nomadamas.org` 를 사용한다.)
18
+
19
+ ## Required environment variables
20
+
21
+ - 없음. `KSKILL_PROXY_BASE_URL` 은 선택 사항이며, 비우면 기본 hosted `https://k-skill-proxy.nomadamas.org` 를 사용한다.
22
+
23
+ 사용자가 공공데이터포털 기상청 API key를 직접 다룰 필요는 없다. `/v1/korea-weather/forecast` route는 기본 hosted proxy에서 호출하고, upstream `KMA_OPEN_API_KEY` 는 proxy 서버에서만 관리한다. 별도 proxy를 쓰는 경우에만 `KSKILL_PROXY_BASE_URL` 을 설정한다.
24
+
25
+ ## Inputs
26
+
27
+ - 격자 좌표: `nx`, `ny`
28
+ - 또는 위도/경도: `lat`, `lon`
29
+ - 선택 사항: `baseDate`, `baseTime`
30
+
31
+ `baseDate` / `baseTime` 을 생략하면 proxy 가 KST 기준 최신 단기예보 발표 시각을 자동으로 고른다.
32
+
33
+ ## Workflow
34
+
35
+ ### 1. Resolve the proxy base URL
36
+
37
+ `KSKILL_PROXY_BASE_URL` 이 있으면 그 값을 사용하고, 없거나 비어 있으면 기본 hosted proxy `https://k-skill-proxy.nomadamas.org` 를 사용한다.
38
+
39
+ ### 2. Query the short-term forecast endpoint
40
+
41
+ 격자 좌표가 이미 있으면 그대로 넣고, 위도/경도만 있으면 proxy 에 그대로 넘긴다.
42
+
43
+ ```bash
44
+ BASE="${KSKILL_PROXY_BASE_URL:-https://k-skill-proxy.nomadamas.org}"
45
+ curl -fsS --get "${BASE}/v1/korea-weather/forecast" \
46
+ --data-urlencode 'lat=37.5665' \
47
+ --data-urlencode 'lon=126.9780'
48
+ ```
49
+
50
+ 격자 좌표 예시:
51
+
52
+ ```bash
53
+ BASE="${KSKILL_PROXY_BASE_URL:-https://k-skill-proxy.nomadamas.org}"
54
+ curl -fsS --get "${BASE}/v1/korea-weather/forecast" \
55
+ --data-urlencode 'nx=60' \
56
+ --data-urlencode 'ny=127' \
57
+ --data-urlencode 'baseDate=20260405' \
58
+ --data-urlencode 'baseTime=0500'
59
+ ```
60
+
61
+ ### 3. Summarize the response conservatively
62
+
63
+ 가능하면 아래 항목만 먼저 요약한다.
64
+
65
+ - `TMP`: 기온
66
+ - `SKY`: 하늘상태
67
+ - `PTY`: 강수형태
68
+ - `POP`: 강수확률
69
+ - `PCP`: 강수량
70
+ - `SNO`: 적설
71
+ - `REH`: 습도
72
+ - `WSD`: 풍속
73
+
74
+ 응답에는 조회 시점과 `baseDate` / `baseTime` 도 함께 적는다.
75
+
76
+ ## Done when
77
+
78
+ - 요청 위치의 단기예보 응답이 정리되어 있다
79
+ - 조회 시점과 예보 발표 시각이 명시되어 있다
80
+ - upstream key가 클라이언트에 노출되지 않았다
81
+
82
+ ## Failure modes
83
+
84
+ - proxy upstream key 미설정 또는 hosted/self-host route 장애
85
+ - `nx` / `ny` 또는 `lat` / `lon` 이 불완전한 경우
86
+ - 기상청 quota 초과 또는 upstream 장애
87
+ - 선택한 발표 시각에 아직 예보가 준비되지 않은 경우
88
+
89
+ ## Notes
90
+
91
+ - 공식 API는 `nx` / `ny` 격자를 쓰지만, proxy 는 `lat` / `lon` 도 받아 내부에서 격자로 변환한다.
92
+ - 단기예보 category 는 `TMP`, `SKY`, `PTY`, `POP`, `PCP`, `SNO`, `REH`, `WSD` 등을 중심으로 본다.
93
+ - proxy 운영/환경변수 설정은 `docs/features/k-skill-proxy.md` 를 참고한다.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "korea-weather",
3
+ "description": "한국 날씨를 기상청 단기예보 조회서비스와 프록시 경유로 조회해 요약한다.",
4
+ "profiles": [
5
+ "proxy",
6
+ "vault",
7
+ "lookup"
8
+ ],
9
+ "frontmatter": "name: korea-weather\ndescription: 한국 날씨를 기상청 단기예보 조회서비스와 프록시 경유로 조회해 요약한다.\nlicense: MIT\nmetadata:\n category: weather\n locale: ko-KR\n phase: v1"
10
+ }