@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,113 @@
1
+ # Gangnam Unni Clinic Search
2
+
3
+ ## What this skill does
4
+
5
+ 강남언니(Gangnam Unni) 웹 검색 페이지의 **비로그인 공개 Next.js payload**를 읽어 병원 후보를 조회한다.
6
+
7
+ - 키워드로 병원 후보를 검색한다.
8
+ - 공개 검색 결과에 포함된 평점, 평점 수, 리뷰 수, 지원 언어, 공개 이미지, 병원 링크를 정리한다.
9
+ - 예약, 상담, 결제, 리뷰 작성, 앱 로그인 등 사용자 계정이 필요한 액션은 하지 않는다.
10
+
11
+ ## When to use
12
+
13
+ - "강남언니에서 강남 성형외과 찾아줘"
14
+ - "강남언니 병원 평점이랑 리뷰 수 봐줘"
15
+ - "코성형 병원 후보를 강남언니 기준으로 몇 개만 보여줘"
16
+ - "성형외과/피부과 병원 공개 링크를 찾아줘"
17
+
18
+ ## When not to use
19
+
20
+ - 상담 신청, 예약, 결제, 병원 채팅, 찜 같은 계정 기반 액션이 필요한 경우
21
+ - 로그인 사용자에게만 보이는 이벤트, 가격, 개인화 추천을 확정해야 하는 경우
22
+ - 의료적 판단, 시술 적합성, 안전성 보증을 대신해야 하는 경우
23
+
24
+ ## Prerequisites
25
+
26
+ - 인터넷 연결
27
+ - Node.js 18+
28
+ - 이 저장소의 `gangnamunni-clinic-search` package 또는 동일 로직
29
+
30
+ ## Required inputs
31
+
32
+ ### 1. Ask for a search keyword if it is missing
33
+
34
+ 검색어가 없으면 먼저 확인한다.
35
+
36
+ - 권장 질문: `강남언니에서 찾을 병원/시술/지역 키워드를 알려주세요. 예: 강남 성형외과, 코성형, 피부과`
37
+ - 너무 넓으면: `검색어가 넓어요. 지역이나 시술명을 같이 주시면 후보를 더 좁힐 수 있어요.`
38
+
39
+ ### 2. Keep the answer conservative
40
+
41
+ 강남언니 공개 페이지 기준으로 확인한 후보임을 분명히 말한다. 병원 선택, 의료 조언, 수술 권유처럼 해석될 수 있는 표현은 피한다.
42
+
43
+ ## Public Gangnam Unni surface
44
+
45
+ - search list: `https://www.gangnamunni.com/search?q=<keyword>`
46
+ - parsed payload: `<script id="__NEXT_DATA__" type="application/json">...props.pageProps.hospitals...</script>`
47
+ - public hospital URL: `https://www.gangnamunni.com/hospitals/<id>`
48
+
49
+ Discovery result: `curl`/Node fetch로 비로그인 검색 HTML이 200으로 응답하고, 병원 후보는 server-rendered `__NEXT_DATA__`의 `props.pageProps.hospitals` 배열에 포함된다. 이 경로는 공개 read-only endpoint이므로 `k-skill-proxy`를 사용하지 않는다.
50
+
51
+ ## Workflow
52
+
53
+ ### 1. Search by keyword
54
+
55
+ ```js
56
+ const { searchClinics } = require("gangnamunni-clinic-search")
57
+
58
+ const result = await searchClinics({ query: "강남 성형외과", limit: 5 })
59
+ console.log(result.items)
60
+ ```
61
+
62
+ CLI:
63
+
64
+ ```bash
65
+ npx gangnamunni-clinic-search "강남 성형외과" --limit 5
66
+ ```
67
+
68
+ ### 2. Interpret returned fields
69
+
70
+ 우선 아래 필드를 본다.
71
+
72
+ - `name`: 병원명
73
+ - `rating`, `ratingCount`, `reviewCount`: 공개 검색 페이지에 포함된 평점/리뷰 지표
74
+ - `languages`: 공개 지원 언어
75
+ - `url`: 강남언니 공개 병원 페이지
76
+ - `profileImage`, `mainImage`: 공개 이미지 URL
77
+
78
+ ### 3. Fallback order
79
+
80
+ 1. 기본: `https://www.gangnamunni.com/search?q=<keyword>`의 `__NEXT_DATA__` payload를 파싱한다.
81
+ 2. payload가 없으면 로그인벽, CAPTCHA, 차단, 빈 shell 페이지를 실패 모드로 분류한다.
82
+ 3. 검색 결과가 너무 적거나 앱 전용 정보가 필요하면 자동화를 멈추고 사용자가 공식 앱/웹에서 직접 확인하도록 안내한다.
83
+
84
+ ### 4. Respond safely
85
+
86
+ 응답은 짧고 보수적으로 정리한다.
87
+
88
+ - 병원명
89
+ - 공개 평점/리뷰 수
90
+ - 지원 언어
91
+ - 강남언니 공개 링크
92
+ - `조회 시점 공개 검색 결과 기준이며, 의료 판단이나 실제 예약 가능 여부는 병원/공식 앱에서 확인해야 합니다.` 라고 명시한다.
93
+
94
+ ## Done when
95
+
96
+ - 검색 키워드를 확인했다.
97
+ - 공개 검색 결과에서 병원 후보를 반환했거나, 실패 모드를 명확히 설명했다.
98
+ - 계정 기반 액션과 의료 판단은 하지 않았다.
99
+
100
+ ## Failure modes
101
+
102
+ - 검색어가 너무 넓거나 강남언니가 병원 후보를 공개 payload에 일부만 넣을 수 있다.
103
+ - 강남언니 웹 구조가 바뀌면 `__NEXT_DATA__` 경로가 깨질 수 있다.
104
+ - 로그인 필요, CAPTCHA, 접근 차단, 빈 HTML shell은 자동 우회하지 않고 실패로 보고한다.
105
+ - 평점, 리뷰 수, 노출 순서는 시점에 따라 달라진다.
106
+ - 앱 전용/로그인 전용 정보는 비로그인 공개 조회만으로 확정할 수 없다.
107
+
108
+ ## Notes
109
+
110
+ - 조회형 스킬이다.
111
+ - 비로그인 공개 표면 우선 원칙을 유지한다.
112
+ - 프록시와 API key는 사용하지 않는다.
113
+ - 의료 조언이나 병원 추천 보증이 아니라 공개 후보 정리로만 답한다.
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "gangnamunni-clinic-search",
3
+ "description": "강남언니 공개 검색 페이지에서 성형외과·피부과 병원 후보, 평점, 리뷰 수, 지원 언어, 공개 병원 링크를 조회한다. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.",
4
+ "profiles": [
5
+ "proxy",
6
+ "action:booking"
7
+ ],
8
+ "frontmatter": "name: gangnamunni-clinic-search\ndescription: 강남언니 공개 검색 페이지에서 성형외과·피부과 병원 후보, 평점, 리뷰 수, 지원 언어, 공개 병원 링크를 조회한다. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.\nlicense: MIT\nmetadata:\n category: beauty\n locale: ko-KR\n phase: v1"
9
+ }
@@ -0,0 +1,69 @@
1
+ # GeekNews Search
2
+
3
+ ## What this skill does
4
+
5
+ GeekNews 공개 RSS/Atom 피드(`https://feeds.feedburner.com/geeknews-feed`)를 사용해 최신 글을 읽기 전용으로 조회한다.
6
+
7
+ - 최신 글 목록 조회
8
+ - 제목/요약/작성자 기준 검색
9
+ - 항목 id/link 기준 상세 확인
10
+
11
+ ## When to use
12
+
13
+ - "긱뉴스 오늘 뭐 올라왔어?"
14
+ - "긱뉴스에서 Claude 관련 글 찾아줘"
15
+ - "이 GeekNews 글 요약/링크 확인해줘"
16
+
17
+ ## Inputs
18
+
19
+ - 기본: 별도 인증 없이 public feed만 사용
20
+ - 목록 조회: `limit`
21
+ - 검색: `query`, 선택 `limit`
22
+ - 상세 조회: `id` 또는 링크/토픽 번호 일부
23
+
24
+ ## Official surface
25
+
26
+ - GeekNews RSS/Atom feed: `https://feeds.feedburner.com/geeknews-feed`
27
+ - GeekNews home: `https://news.hada.io`
28
+
29
+ ## Workflow
30
+
31
+ ### 1) List recent entries
32
+
33
+ ```bash
34
+ python3 scripts/geeknews_search.py list --limit 10
35
+ ```
36
+
37
+ ### 2) Search the feed conservatively
38
+
39
+ ```bash
40
+ python3 scripts/geeknews_search.py search --query Claude --limit 5
41
+ ```
42
+
43
+ 검색은 제목, 요약, 작성자, 링크/id 기준으로만 동작한다.
44
+
45
+ ### 3) Inspect a specific item
46
+
47
+ ```bash
48
+ python3 scripts/geeknews_search.py detail --id 28439
49
+ ```
50
+
51
+ 상세 조회는 RSS 피드에 포함된 `content`/요약과 원문 링크를 함께 돌려준다.
52
+
53
+ ## Done when
54
+
55
+ - 최신 GeekNews 글 목록을 바로 보여줄 수 있다.
56
+ - 키워드 검색 결과에서 제목/링크/작성자/요약을 정리할 수 있다.
57
+ - 특정 항목의 RSS 기반 내용을 보수적으로 확인하고 원문 링크를 함께 제시할 수 있다.
58
+
59
+ ## Failure modes
60
+
61
+ - FeedBurner/GeekNews feed가 일시적으로 응답하지 않을 수 있다.
62
+ - RSS 피드가 제공하는 범위를 넘는 전체 본문/댓글/투표 정보는 포함되지 않는다.
63
+ - HTML 요약은 feed 원문 기준이라 일부가 잘릴 수 있다.
64
+
65
+ ## Notes
66
+
67
+ - v1은 RSS-first, read-only 범위다.
68
+ - 비공식 API나 로그인 세션에 의존하지 않는다.
69
+ - 테스트/오프라인 검증 시 `--feed-file` 로 저장된 Atom XML을 넣을 수 있다.
@@ -0,0 +1,296 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import re
8
+ import urllib.request
9
+ from dataclasses import asdict, dataclass
10
+ from html import unescape
11
+ from html.parser import HTMLParser
12
+ from pathlib import Path
13
+
14
+ GEEKNEWS_FEED_URL = "https://feeds.feedburner.com/geeknews-feed"
15
+
16
+
17
+ class _TextExtractor(HTMLParser):
18
+ def __init__(self) -> None:
19
+ super().__init__()
20
+ self.parts: list[str] = []
21
+
22
+ def handle_data(self, data: str) -> None:
23
+ self.parts.append(data)
24
+
25
+ def text(self) -> str:
26
+ return " ".join(part.strip() for part in self.parts if part.strip())
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class GeekNewsItem:
31
+ id: str
32
+ title: str
33
+ link: str
34
+ published: str | None
35
+ updated: str | None
36
+ author_name: str | None
37
+ author_url: str | None
38
+ summary: str
39
+ content_html: str
40
+
41
+ def to_dict(self) -> dict[str, object]:
42
+ return asdict(self)
43
+
44
+
45
+ @dataclass(frozen=True)
46
+ class GeekNewsFeed:
47
+ title: str
48
+ source_id: str | None
49
+ updated: str | None
50
+ home_url: str | None
51
+ feed_url: str | None
52
+ category: str | None
53
+ items: list[GeekNewsItem]
54
+
55
+ def source_dict(self) -> dict[str, object]:
56
+ return {
57
+ "title": self.title,
58
+ "id": self.source_id,
59
+ "updated": self.updated,
60
+ "home_url": self.home_url,
61
+ "feed_url": self.feed_url,
62
+ "category": self.category,
63
+ }
64
+
65
+
66
+ def _strip_cdata(value: str | None) -> str:
67
+ if not value:
68
+ return ""
69
+ stripped = value.strip()
70
+ if stripped.startswith("<![CDATA[") and stripped.endswith("]]>"):
71
+ return stripped[9:-3]
72
+ return stripped
73
+
74
+
75
+ def _collapse_whitespace(value: str) -> str:
76
+ return re.sub(r"\s+", " ", value).strip()
77
+
78
+
79
+ def _clean_xml_text(value: str | None) -> str:
80
+ return _collapse_whitespace(unescape(_strip_cdata(value)))
81
+
82
+
83
+ def _html_to_text(html: str) -> str:
84
+ parser = _TextExtractor()
85
+ parser.feed(html)
86
+ parser.close()
87
+ return _collapse_whitespace(unescape(parser.text()))
88
+
89
+
90
+ def _first_tag(block: str, tag: str) -> str | None:
91
+ match = re.search(rf"<{tag}\b[^>]*>(.*?)</{tag}>", block, re.DOTALL)
92
+ if not match:
93
+ return None
94
+ return _clean_xml_text(match.group(1))
95
+
96
+
97
+ def _first_raw_tag(block: str, tag: str) -> str | None:
98
+ match = re.search(rf"<{tag}\b[^>]*>(.*?)</{tag}>", block, re.DOTALL)
99
+ if not match:
100
+ return None
101
+ return _strip_cdata(match.group(1)).strip()
102
+
103
+
104
+ def _first_link_href(block: str) -> str | None:
105
+ patterns = (
106
+ r"<link\b[^>]*rel=['\"]alternate['\"][^>]*href=['\"]([^'\"]+)['\"]",
107
+ r"<link\b[^>]*href=['\"]([^'\"]+)['\"]",
108
+ )
109
+ for pattern in patterns:
110
+ match = re.search(pattern, block)
111
+ if match:
112
+ return unescape(match.group(1).strip())
113
+ return None
114
+
115
+
116
+ def _link_href(block: str, *, rel: str | None = None) -> str | None:
117
+ if rel:
118
+ match = re.search(
119
+ rf"<link\b[^>]*(?:rel|ref)=['\"]{re.escape(rel)}['\"][^>]*href=['\"]([^'\"]+)['\"]",
120
+ block,
121
+ )
122
+ if match:
123
+ return unescape(match.group(1).strip())
124
+ return _first_link_href(block)
125
+
126
+
127
+ def _feed_prefix(xml_text: str) -> str:
128
+ if "<entry" not in xml_text:
129
+ return xml_text
130
+ return xml_text.split("<entry", 1)[0]
131
+
132
+
133
+ def _entry_blocks(xml_text: str) -> list[str]:
134
+ return re.findall(r"<entry\b[^>]*>(.*?)</entry>", xml_text, re.DOTALL)
135
+
136
+
137
+ def _validate_limit(limit: int) -> int:
138
+ if limit <= 0:
139
+ raise ValueError("limit must be positive")
140
+ return limit
141
+
142
+
143
+ def load_feed(xml_text: str) -> GeekNewsFeed:
144
+ prefix = _feed_prefix(xml_text)
145
+ items = []
146
+ for entry in _entry_blocks(xml_text):
147
+ author_block_match = re.search(r"<author\b[^>]*>(.*?)</author>", entry, re.DOTALL)
148
+ author_block = author_block_match.group(1) if author_block_match else ""
149
+ content_html = (_first_raw_tag(entry, "content") or "").strip()
150
+ items.append(
151
+ GeekNewsItem(
152
+ id=_first_tag(entry, "id") or "",
153
+ title=_first_tag(entry, "title") or "",
154
+ link=_first_link_href(entry) or (_first_tag(entry, "id") or ""),
155
+ published=_first_tag(entry, "published") or _first_tag(entry, "updated"),
156
+ updated=_first_tag(entry, "updated"),
157
+ author_name=_first_tag(author_block, "name"),
158
+ author_url=_first_tag(author_block, "uri"),
159
+ summary=_html_to_text(content_html),
160
+ content_html=content_html,
161
+ )
162
+ )
163
+
164
+ category_match = re.search(r"<category\b[^>]*term=['\"]([^'\"]+)['\"]", prefix)
165
+ return GeekNewsFeed(
166
+ title=_first_tag(prefix, "title") or "GeekNews",
167
+ source_id=_first_tag(prefix, "id"),
168
+ updated=_first_tag(prefix, "updated"),
169
+ home_url=_link_href(prefix, rel="alternate"),
170
+ feed_url=_link_href(prefix, rel="self") or _first_tag(prefix, "id"),
171
+ category=category_match.group(1) if category_match else None,
172
+ items=items,
173
+ )
174
+
175
+
176
+ def list_items(feed: GeekNewsFeed, limit: int = 10) -> list[GeekNewsItem]:
177
+ return feed.items[:_validate_limit(limit)]
178
+
179
+
180
+ def search_items(feed: GeekNewsFeed, query: str, limit: int = 10) -> list[GeekNewsItem]:
181
+ if not query.strip():
182
+ raise ValueError("query is required")
183
+ limit = _validate_limit(limit)
184
+ needle = query.casefold()
185
+ matches = []
186
+ for item in feed.items:
187
+ haystack = "\n".join(
188
+ part
189
+ for part in (
190
+ item.title,
191
+ item.summary,
192
+ item.author_name or "",
193
+ item.author_url or "",
194
+ item.id,
195
+ item.link,
196
+ )
197
+ if part
198
+ ).casefold()
199
+ if needle in haystack:
200
+ matches.append(item)
201
+ if len(matches) >= limit:
202
+ break
203
+ return matches
204
+
205
+
206
+ def get_item_detail(feed: GeekNewsFeed, lookup: str) -> GeekNewsItem:
207
+ normalized_lookup = lookup.strip().casefold()
208
+ if not normalized_lookup:
209
+ raise ValueError("lookup is required")
210
+ for item in feed.items:
211
+ candidates = [item.id, item.link, item.title]
212
+ lowered = [candidate.casefold() for candidate in candidates if candidate]
213
+ if normalized_lookup in lowered or any(normalized_lookup in candidate for candidate in lowered):
214
+ return item
215
+ raise LookupError(f"No GeekNews entry matched: {lookup}")
216
+
217
+
218
+ def _serialize_items(items: list[GeekNewsItem]) -> list[dict[str, object]]:
219
+ return [item.to_dict() for item in items]
220
+
221
+
222
+ def build_list_payload(feed: GeekNewsFeed, limit: int = 10) -> dict[str, object]:
223
+ items = list_items(feed, limit=limit)
224
+ return {"source": feed.source_dict(), "count": len(items), "items": _serialize_items(items)}
225
+
226
+
227
+ def build_search_payload(feed: GeekNewsFeed, query: str, limit: int = 10) -> dict[str, object]:
228
+ items = search_items(feed, query=query, limit=limit)
229
+ return {
230
+ "source": feed.source_dict(),
231
+ "query": query,
232
+ "count": len(items),
233
+ "items": _serialize_items(items),
234
+ }
235
+
236
+
237
+ def build_detail_payload(feed: GeekNewsFeed, lookup: str) -> dict[str, object]:
238
+ item = get_item_detail(feed, lookup)
239
+ return {"source": feed.source_dict(), "item": item.to_dict()}
240
+
241
+
242
+ def fetch_feed(url: str = GEEKNEWS_FEED_URL, timeout: int = 20) -> str:
243
+ request = urllib.request.Request(url, headers={"User-Agent": "k-skill-geeknews/1.0"})
244
+ with urllib.request.urlopen(request, timeout=timeout) as response:
245
+ charset = response.headers.get_content_charset() or "utf-8"
246
+ return response.read().decode(charset, errors="replace")
247
+
248
+
249
+ def _add_feed_source_args(parser: argparse.ArgumentParser) -> None:
250
+ parser.add_argument("--feed-url", default=GEEKNEWS_FEED_URL, help="기본값: GeekNews public feed URL")
251
+ parser.add_argument("--feed-file", help="테스트/오프라인 검증용 로컬 Atom XML 파일")
252
+
253
+
254
+ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
255
+ parser = argparse.ArgumentParser(description="Read GeekNews entries from the public RSS/Atom feed.")
256
+
257
+ subparsers = parser.add_subparsers(dest="command", required=True)
258
+
259
+ list_parser = subparsers.add_parser("list", help="최신 GeekNews 항목 목록")
260
+ _add_feed_source_args(list_parser)
261
+ list_parser.add_argument("--limit", type=int, default=10)
262
+
263
+ search_parser = subparsers.add_parser("search", help="제목/요약/작성자 기준 검색")
264
+ _add_feed_source_args(search_parser)
265
+ search_parser.add_argument("--query", required=True)
266
+ search_parser.add_argument("--limit", type=int, default=10)
267
+
268
+ detail_parser = subparsers.add_parser("detail", help="항목 상세 확인")
269
+ _add_feed_source_args(detail_parser)
270
+ detail_parser.add_argument("--id", required=True, help="entry id/link/topic id 일부")
271
+
272
+ return parser.parse_args(argv)
273
+
274
+
275
+ def _load_feed_text(args: argparse.Namespace) -> str:
276
+ if args.feed_file:
277
+ return Path(args.feed_file).read_text(encoding="utf-8")
278
+ return fetch_feed(url=args.feed_url)
279
+
280
+
281
+ def main(argv: list[str] | None = None) -> None:
282
+ args = parse_args(argv)
283
+ feed = load_feed(_load_feed_text(args))
284
+
285
+ if args.command == "list":
286
+ payload = build_list_payload(feed, limit=args.limit)
287
+ elif args.command == "search":
288
+ payload = build_search_payload(feed, query=args.query, limit=args.limit)
289
+ else:
290
+ payload = build_detail_payload(feed, lookup=args.id)
291
+
292
+ print(json.dumps(payload, ensure_ascii=False, indent=2))
293
+
294
+
295
+ if __name__ == "__main__":
296
+ main()
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "geeknews-search",
3
+ "description": "GeekNews public RSS/Atom feed로 긱뉴스 게시물을 조회, 검색, 상세 확인하는 읽기 전용 스킬.",
4
+ "profiles": [
5
+ "lookup"
6
+ ],
7
+ "frontmatter": "name: geeknews-search\ndescription: GeekNews public RSS/Atom feed로 긱뉴스 게시물을 조회, 검색, 상세 확인하는 읽기 전용 스킬.\nlicense: MIT\nmetadata:\n category: news\n locale: ko-KR\n source: geeknews-rss"
8
+ }
@@ -0,0 +1,128 @@
1
+ # 개별공시지가 조회
2
+
3
+ ## What this skill does
4
+
5
+ 한국 국토교통부 부동산공시가격알리미(realtyprice.kr)에서 특정 필지의 **개별공시지가**(원/㎡)를 조회한다. 다년도 추이(최근 5년 이내)와 전년 대비 변동률을 정규화된 JSON으로 반환한다.
6
+
7
+ 공시지가는 매년 1월 1일 기준, 4~5월 공시. 세금(재산세, 종합부동산세, 양도소득세) 산정의 법적 기준 단가다.
8
+
9
+ ## When to use
10
+
11
+ - "서울 강남구 역삼동 736 공시지가 알려줘"
12
+ - "전라남도 무안군 청계면 청천리 100번지 개별공시지가"
13
+ - "서초동 산 1-2 공시지가 추이"
14
+ - 세무 계산에서 토지 공시 단가가 필요할 때
15
+
16
+ ## When NOT to use
17
+
18
+ - 시세, 실거래가, 매매가, 호가 → 다른 데이터 소스 필요
19
+ - 공동주택가격, 표준지공시지가, 단독주택가격 → 별도 스킬
20
+ - 토지이용계획 → eum.go.kr 별도 스킬
21
+
22
+ ## Prerequisites
23
+
24
+ - 인터넷 연결
25
+ - `curl` (또는 HTTP 호출 도구)
26
+
27
+ 사용자에게 필요한 시크릿 없음 (공개 데이터).
28
+
29
+ ## Default path
30
+
31
+ `gongsijiga-search` npm 패키지를 직접 호출한다. realtyprice.kr는 API 키가 필요 없는 공개 엔드포인트이므로 `k-skill-proxy`를 경유하지 않는다.
32
+
33
+ 설치:
34
+
35
+ ```bash
36
+ npm install gongsijiga-search
37
+ ```
38
+
39
+ 호출:
40
+
41
+ ```bash
42
+ node -e "
43
+ const { lookupGongsijiga } = require('gongsijiga-search');
44
+ lookupGongsijiga('서울 강남구 역삼동 736').then(console.log).catch(console.error);
45
+ "
46
+ ```
47
+
48
+ ## Workflow
49
+
50
+ ### 1. 사용자 입력 수집
51
+
52
+ 사용자에게 **시도 + 시군구 + 읍면동 + 지번**이 포함된 주소를 요청한다.
53
+
54
+ - 최소 필수: 시도, 시군구, 읍면동, 본번
55
+ - **세종특별자치시**는 시군구가 없으므로 "세종 [읍면동] [지번]" 형식
56
+ - 산 지번이면 "산" 키워드 포함
57
+ - 부번이 있으면 "100-5" 형식
58
+
59
+ 예시: "서울 강남구 역삼동 736", "전남 무안군 청계면 청천리 산 1-2", "세종 고용동 100"
60
+
61
+ 시도가 누락된 주소(예: "역삼동 736")는 조회 불가 — 시도를 물어본다.
62
+
63
+ ### 2. 직접 호출
64
+
65
+ `gongsijiga-search` 모듈을 사용해 realtyprice.kr를 직접 호출한다 (API 키 불필요, 프록시 경유 안 함):
66
+
67
+ ```javascript
68
+ const { lookupGongsijiga } = require('gongsijiga-search');
69
+
70
+ const result = await lookupGongsijiga('서울 강남구 역삼동 736');
71
+ ```
72
+
73
+ ### 3. 응답 해석 및 출력
74
+
75
+ 성공 응답 예시:
76
+
77
+ ```json
78
+ {
79
+ "address": "서울 강남구 역삼동 736",
80
+ "jibun": "736번지",
81
+ "san": false,
82
+ "latest": {
83
+ "year": 2026,
84
+ "price_per_sqm": 72340000,
85
+ "notice_date": "2026-04-30",
86
+ "base_date": "2026-01-01"
87
+ },
88
+ "history": [...],
89
+ "yoy_change_pct": 5.45,
90
+ "source_url": "https://www.realtyprice.kr/notice/gsindividual/search.htm"
91
+ }
92
+ ```
93
+
94
+ **출력 규칙:**
95
+
96
+ 1. 반드시 "공시지가" 단어 사용. "가격/시세/매매가" 단어 금지.
97
+ 2. 헤더: `[정부 공시] 개별공시지가 — {address}`
98
+ 3. 최신값: `{year}년 공시지가: {price_per_sqm:,}원/㎡ (전년 대비 +{yoy_change_pct}%)`
99
+ 4. 추이 표 (history 배열을 연도순 테이블로):
100
+
101
+ | 연도 | 공시지가 (원/㎡) | 공시일 |
102
+ |------|-----------------|--------|
103
+ | 2026 | 72,340,000 | 2026-04-30 |
104
+ | ... | ... | ... |
105
+
106
+ 5. 마지막 줄 disclaimer:
107
+ `본 단가는 세금 산정용 정부 공시 가격으로, 시세나 실거래가와 다릅니다.`
108
+
109
+ ### 4. 올해 미발표 안내
110
+
111
+ `latest.year`가 올해보다 작으면: "올해 공시지가는 아직 미발표 상태입니다. 최신 데이터는 {latest.year}년 기준입니다." 안내.
112
+
113
+ ## Failure modes
114
+
115
+ | error.code | 의미 | 행동 |
116
+ |---|---|---|
117
+ | `ADDRESS_PARSE_FAILED` | 주소 파싱 실패 | "행정구역 + 본번까지 포함된 주소가 필요합니다" + 예시 |
118
+ | `INVALID_BUNJI` | 본번 형식 오류 | 본번 입력 형식 재요청 |
119
+ | `REGION_NOT_FOUND` | 행정구역 매칭 실패 | candidates 배열이 있으면 제안, 없으면 오타 확인 요청 |
120
+ | `LAND_NOT_FOUND` | 해당 지번 미등재 | "본번/부번 오타이거나 도로/하천 등 미과세 토지" 설명 |
121
+ | `UPSTREAM_ERROR` | realtyprice.kr 장애 | "데이터 출처 일시 장애. 잠시 후 재시도" + source_url |
122
+ | `UPSTREAM_TIMEOUT` | 30초 초과 | UPSTREAM_ERROR와 동일 |
123
+
124
+ ## Notes
125
+
126
+ - 공시지가 ≠ 시세. 시세는 통상 공시지가의 1.5~3배.
127
+ - 매년 1월 1일 기준, 4~5월 발표. 1~4월은 전년도가 최신.
128
+ - realtyprice.kr는 API 키 불필요 (공개 데이터).
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "gongsijiga-search",
3
+ "description": "|",
4
+ "profiles": [
5
+ "proxy",
6
+ "lookup"
7
+ ],
8
+ "frontmatter": "name: gongsijiga-search\ndescription: |\n 대한민국 국토교통부가 매년 공시하는 \"개별공시지가\"(원/㎡) 조회.\n 지번 단위 토지의 정부 공시 단가로, 재산세·종부세·양도세 등\n 세금 산정의 법적 기준이다. **시세/실거래가가 아니다.**\n Use when the user asks for 공시지가, 개별공시지가, 토지 공시단가,\n 세무 계산용 토지 단가, or \"이 땅 공시지가 얼마야\".\n Do NOT use for 시세, 실거래가, 매매가, 호가, 공동주택가격\n (those need a different data source).\nlicense: MIT\nmetadata:\n category: real-estate\n locale: ko-KR\n phase: v1"
9
+ }