@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,120 @@
1
+ # Court Payment Order Assistant
2
+
3
+ ## What this skill does
4
+
5
+ 대한민국 법원 전자소송 포털에서 **지급명령(독촉) 신청**을 준비해야 할 때, 사용자가 제공한 채권자·채무자·청구내용·증빙 정보를 정리해 신청서 초안, 누락 질문, 첨부 체크리스트, 브라우저 handoff 절차를 만든다.
6
+
7
+ 이 스킬은 참고용 작성 보조다. 법률 자문, 승소 가능성 판단, 관할 확정, 최종 제출 대행을 하지 않는다.
8
+
9
+ ## When to use
10
+
11
+ - "떼인 돈 지급명령 신청 준비해줘"
12
+ - "전자소송에서 지급명령 신청서 입력 도와줘"
13
+ - "채무자 정보랑 증빙으로 지급명령 초안 만들어줘"
14
+ - "로그인은 내가 할 테니 입력할 내용 정리해줘"
15
+
16
+ ## Prerequisites
17
+
18
+ - Node.js 18+
19
+
20
+ - **실제 브라우저는 필수가 아니다.** 이 스킬의 핵심 산출물(지급명령/독촉 초안, 필요서류 체크리스트, 입력값 handoff)은 실제 브라우저를 띄우지 않고 생성된다. 브라우저는 사용자가 공식 포털에서 직접 로그인·확인·제출하는 수동 단계에서만 쓰이며, 그때 권장 순서는 BrowserOS/runtime CDP → 수동 브라우저다.
21
+ - BrowserOS/runtime CDP 우선 사용: 사용자가 직접 띄운 BrowserOS GUI 세션(`KSKILL_BROWSEROS_CDP_URL`, 기본 `http://127.0.0.1:9100`)에 attach한다. 스킬은 BrowserOS를 launch하거나 headless로 띄우지 않는다.
22
+ - 사용자가 직접 처리할 것: 전자소송 로그인, 공동/금융인증서 또는 간편인증, 보안 프로그램, 전자서명, 인지대/송달료 결제, 최종 제출
23
+
24
+ ## Public access path discovered
25
+
26
+ Official portal:
27
+
28
+ ```text
29
+ https://ecfs.scourt.go.kr/psp/index.on
30
+ ```
31
+
32
+ Observed public surface:
33
+
34
+ - 전자소송 포털은 공개 상태에서 로그인/사용자등록, `서류제출`, `민사 서류` 영역을 보여준다.
35
+ - 문서 작성은 로그인 이후 가능하다는 경계가 표시된다.
36
+ - 나홀로소송/도움말 영역에서 지급명령(독촉) 설명 진입점을 확인할 수 있다.
37
+ - `https://ecfs.scourt.go.kr/ecf/index.jsp`는 점검/오류 페이지로 redirect될 수 있어, 현재 안정 진입점은 `/psp/index.on`이다.
38
+
39
+ ## Workflow
40
+
41
+ ### 1. Ask for required facts
42
+
43
+ Use the package to normalize and validate intake:
44
+
45
+ ```js
46
+ const { buildRequiredQuestions, validateIntake } = require("court-payment-order-assistant")
47
+
48
+ const validation = validateIntake(input)
49
+ if (!validation.canDraft) {
50
+ console.log(buildRequiredQuestions(input))
51
+ }
52
+ ```
53
+
54
+ Required information:
55
+
56
+ | Area | Required facts |
57
+ | --- | --- |
58
+ | 채권자 | 성명/상호, 송달 주소, 연락처(가능하면) |
59
+ | 채무자 | 성명/상호, 송달 가능한 주소, 식별정보(가능하면) |
60
+ | 청구 | 원금, 변제기, 청구원인, 신청취지 |
61
+ | 증빙 | 계약서, 차용증, 송금내역, 세금계산서, 독촉 문자/이메일 등 |
62
+ | 법원 | 사용자가 최종 확인할 관할 법원 |
63
+
64
+ ### 2. Prepare a draft and checklist
65
+
66
+ ```js
67
+ const { buildPaymentOrderDraft } = require("court-payment-order-assistant")
68
+ const draft = buildPaymentOrderDraft(input)
69
+ ```
70
+
71
+ Return:
72
+
73
+ - parties
74
+ - claim statement
75
+ - cause statement
76
+ - evidence list
77
+ - missing fields
78
+ - warnings
79
+ - review checklist
80
+ - stop-before list
81
+
82
+ ### 3. Browser handoff
83
+
84
+ ```js
85
+ const { buildBrowserHandoff } = require("court-payment-order-assistant")
86
+ console.log(buildBrowserHandoff(input))
87
+ ```
88
+
89
+ Fallback order:
90
+
91
+ 1. BrowserOS/runtime CDP: attach to the user-launched BrowserOS GUI session for official portal inspection and reversible field entry after the user manually logs in.
92
+ 2. Manual browser: if BrowserOS CDP is unavailable or authentication, certificate, security module, CAPTCHA, or maintenance blocks automation, hand off exact field values for manual entry.
93
+
94
+ ## Stop rules
95
+
96
+ - Do not click final submit.
97
+ - Do not perform electronic signature.
98
+ - Do not pay 인지대 or 송달료.
99
+ - Do not bypass login, certificate, security module, CAPTCHA, or maintenance pages.
100
+ - Do not tell the user that filing is legally sufficient or guaranteed.
101
+
102
+ ## Done when
103
+
104
+ - Required facts were collected or missing questions were returned.
105
+ - A draft/checklist was generated for user review.
106
+ - Official portal entry and login-required boundary were confirmed through BrowserOS/runtime CDP or documented fallback.
107
+ - The browser handoff stops before signature, payment, and final submission.
108
+
109
+ ## Failure modes
110
+
111
+ - Electronic litigation portal maintenance or redirect.
112
+ - Login, certificate, security module, CAPTCHA, popup, or session timeout.
113
+ - Unknown debtor address or wrong jurisdiction.
114
+ - Missing evidence for claim cause or amount.
115
+ - User asks for legal judgment, guaranteed outcome, or final submission without review.
116
+
117
+ ## Notes
118
+
119
+ - No proxy, API key, or secret is used.
120
+ - This is not legal advice. For disputed facts, large amounts, limitation-period issues, business debt, or uncertain debtor address, recommend professional review.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "court-payment-order-assistant",
3
+ "description": "법원 전자소송 지급명령 신청을 위해 채권자·채무자·청구금액·청구원인·증빙 정보를 인터뷰하고, 신청서 초안과 공식 전자소송 브라우저 입력 handoff를 준비한다. 돌쇠에서는 가능한 가장 가까운 합법적 공식 단계까지 준비한다.",
4
+ "profiles": [
5
+ "vault",
6
+ "browser",
7
+ "hard-boundary"
8
+ ],
9
+ "frontmatter": "name: court-payment-order-assistant\ndescription: 법원 전자소송 지급명령 신청을 위해 채권자·채무자·청구금액·청구원인·증빙 정보를 인터뷰하고, 신청서 초안과 공식 전자소송 브라우저 입력 handoff를 준비한다. 돌쇠에서는 가능한 가장 가까운 합법적 공식 단계까지 준비한다.\nlicense: MIT\nmetadata:\n category: legal\n locale: ko-KR\n phase: v1"
10
+ }
@@ -0,0 +1,117 @@
1
+ # D2B Notice Search
2
+
3
+ ## What this skill does
4
+
5
+ 국방전자조달시스템(D2B, `www.d2b.go.kr`)의 공개 `입찰공고` 검색 화면을 브라우저로 읽어 국방 조달 공고 후보를 조회한다.
6
+
7
+ - 공고건명 키워드로 검색한다.
8
+ - 공고구분을 정상공고, 긴급공고, 정정공고, 취소공고, 연기공고, 재공고로 좁힌다.
9
+ - 개찰일자 또는 공고일자 기준 기간을 지정한다.
10
+ - G2B공고번호와 발주기관 조건을 함께 사용할 수 있다.
11
+ - 렌더링된 목록/최근 공고 링크의 제목, 공고번호, 업무구분, 게시일을 추출한다.
12
+
13
+ 입찰, 투찰, 서류 제출, 로그인, 공동인증서/보안 프로그램 조작, 결제는 하지 않는다.
14
+
15
+ ## When to use
16
+
17
+ - "국방전자조달 냉난방기 공고 찾아줘"
18
+ - "D2B 긴급 물품 공고 조회"
19
+ - "국방전자조달시스템에서 G2B공고번호로 찾아줘"
20
+ - "방위사업청 입찰공고 최신 목록 보여줘"
21
+
22
+ ## Prerequisites
23
+
24
+ - 인터넷 연결
25
+ - Node.js 18+
26
+ - 기본: Aside Browser
27
+ - fallback: 사용자가 띄운 BrowserOS 세션에 CDP로 붙거나(권장), 로컬 브라우저 사용
28
+
29
+ ## Public access path discovered
30
+
31
+ ### Primary source: official D2B rendered search form
32
+
33
+ Entry point:
34
+
35
+ ```text
36
+ https://www.d2b.go.kr/index.do
37
+ ```
38
+
39
+ Observed public `입찰공고` fields:
40
+
41
+ | Field | Meaning |
42
+ | --- | --- |
43
+ | `공고건명` | notice title keyword |
44
+ | `공고구분` | 정상공고 `A`, 긴급공고 `B`, 정정공고 `H`, 취소공고 `J`, 연기공고 `K`, 재공고 `D` |
45
+ | `공고/개찰일` | 개찰일자 `1`, 공고일자 `2` |
46
+ | 시작/마지막 날짜 | date range |
47
+ | `G2B공고번호` | G2B notice number |
48
+ | `발주기관` | ordering organization |
49
+
50
+ Discovery result: the home page renders a public search form and recent bid links without login. Direct probes to `https://www.d2b.go.kr/openapi/sealedBidAnnounceList.json` can return `400 Bad Request` / deceptive request routing HTML, so browser automation is the stable primary route.
51
+
52
+ No `k-skill-proxy` route is used because the public page does not require an API key. If a separate free API key route is later confirmed, it must be narrow, allowlisted, cache-backed, and documented before proxying.
53
+
54
+ ## Workflow
55
+
56
+ ### 1. Build a search recipe
57
+
58
+ ```js
59
+ const { buildBrowserAutomationInstructions } = require("d2b-notice-search")
60
+
61
+ const instructions = buildBrowserAutomationInstructions({
62
+ keyword: "냉난방기",
63
+ kind: "물품",
64
+ noticeType: "긴급공고",
65
+ dateType: "공고일자",
66
+ dateStart: "2026-07-01",
67
+ dateEnd: "2026-08-30",
68
+ organization: "해병"
69
+ })
70
+ ```
71
+
72
+ ### 2. Execute with Aside Browser first
73
+
74
+ 1. Open `https://www.d2b.go.kr/index.do`.
75
+ 2. Snapshot the `입찰공고` area.
76
+ 3. Fill 공고건명, 공고구분, 공고/개찰일, date range, G2B공고번호, and 발주기관 as needed.
77
+ 4. Click `검색`.
78
+ 5. Snapshot the resulting list or recent notice links and extract visible fields.
79
+
80
+ ### 3. Fallback order
81
+
82
+ 1. Aside Browser against the official rendered page.
83
+ 2. A user-launched BrowserOS session over CDP (or a local browser you own) with the same public form interactions.
84
+ 3. Direct HTTP best-effort only. Treat `400 Bad Request`, `deceptive request routing`, TouchEn/security, login, CAPTCHA, queue, or maintenance HTML as an explicit blocked state, not as empty results.
85
+
86
+ ## Supported aliases
87
+
88
+ | Input aliases | Normalized value |
89
+ | --- | --- |
90
+ | `물품`, `goods`, `pdb` | `PDB` |
91
+ | `용역`, `service`, `services`, `psb` | `PSB` |
92
+ | `공사`, `works`, `construction`, `pcb` | `PCB` |
93
+ | `국외`, `foreign`, `peb` | `PEB` |
94
+ | `정상공고`, `normal`, `A` | `A` |
95
+ | `긴급공고`, `urgent`, `B` | `B` |
96
+ | `정정공고`, `H` | `H` |
97
+ | `취소공고`, `J` | `J` |
98
+ | `연기공고`, `K` | `K` |
99
+ | `재공고`, `D` | `D` |
100
+ | `개찰일자`, `open`, `opening`, `1` | `1` |
101
+ | `공고일자`, `posted`, `notice`, `2` | `2` |
102
+
103
+ ## Done when
104
+
105
+ - The official D2B page was opened through Aside Browser or the documented browser fallback.
106
+ - The visible search form was filled with the requested conditions.
107
+ - Results or an explicit no-results/blocked state were captured from the rendered page.
108
+ - Direct HTTP failures were classified as blocked/security routing when they return 400/security HTML.
109
+ - No login, bidding, signature, payment, or security bypass was attempted.
110
+
111
+ ## Failure modes
112
+
113
+ - D2B may change Vue/component markup, placeholders, JavaScript action names, or the openapi route.
114
+ - Direct HTTP may return `400 Bad Request`, traffic/security routing HTML, or maintenance pages.
115
+ - Browser automation can be blocked by security software, certificate prompts, CAPTCHA, login walls, or site maintenance.
116
+ - Date ranges wider than 12 months are rejected by this package to keep user queries narrow.
117
+ - Rendered results can differ by current D2B service state; cite the official D2B URL and visible timestamp/context when answering.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "d2b-notice-search",
3
+ "description": "국방전자조달시스템(D2B) 공개 입찰공고 검색 화면에서 공고건명·공고구분·공고/개찰일·G2B공고번호·발주기관 조건으로 공고를 조회한다. 돌쇠에서는 가능한 가장 가까운 합법적 공식 단계까지 준비한다.",
4
+ "profiles": [
5
+ "proxy",
6
+ "browser",
7
+ "hard-boundary"
8
+ ],
9
+ "frontmatter": "name: d2b-notice-search\ndescription: 국방전자조달시스템(D2B) 공개 입찰공고 검색 화면에서 공고건명·공고구분·공고/개찰일·G2B공고번호·발주기관 조건으로 공고를 조회한다. 돌쇠에서는 가능한 가장 가까운 합법적 공식 단계까지 준비한다.\nlicense: MIT\nmetadata:\n category: procurement\n locale: ko-KR\n phase: v1"
10
+ }
@@ -0,0 +1,91 @@
1
+ # Daangn Cars Search
2
+
3
+ ## What this skill does
4
+
5
+ 당근중고차 공개 Remix `_data` JSON route를 사용해 차량 목록과 상세 정보를 읽기 전용으로 조회한다.
6
+
7
+ 최종 사용자는 자연어로 요청해도 되고, 필요하면 아래의 Python helper를 직접 실행한다. 외부 패키지나 k-skill-proxy 없이 Python 표준 라이브러리만 사용한다.
8
+
9
+ ## When to use
10
+
11
+ - "당근중고차 합정동 레이 찾아봐"
12
+ - "당근에서 천만원 이하 중고차 검색"
13
+ - "이 당근 중고차 URL 상세 봐줘"
14
+
15
+ ## When not to use
16
+
17
+ - 당근 계정 로그인이 필요한 작업
18
+ - 채팅, 찜, 거래 제안, 문의, 지원, 예약, 계약, 구매처럼 상대방 또는 계정에 영향을 주는 작업
19
+ - CAPTCHA/봇 차단/로그인벽 우회가 필요한 작업
20
+
21
+ ## Prerequisites
22
+
23
+ - 인터넷 연결
24
+ - Python 3.9+
25
+ - 이 저장소 루트에서 실행하거나, 스크립트 경로를 절대경로로 지정
26
+
27
+ ## Data surfaces
28
+
29
+ - Region resolver: `https://www.daangn.com/kr/api/v1/regions/keyword?keyword=<지역명>`
30
+ - Search `_data`: `/kr/cars/?in=<지역명>-<id>&onlyOnSale=1&_data=routes/kr.cars._index`
31
+ - Detail `_data`: `<car-url>?_data=routes%2Fkr.cars.%24car_post_id`
32
+
33
+ ## Workflow
34
+
35
+ 1. 사용자 요청에서 키워드, 지역명, 가격/거래 유형 같은 필터를 추출한다.
36
+ 2. 지역명이 있으면 region resolver로 내부 region id를 찾는다.
37
+ 3. 목록 검색은 category별 `_data` route를 호출한다.
38
+ 4. 상세 URL이 주어지면 category별 detail route 또는 공개 HTML 메타를 조회한다.
39
+ 5. 결과를 짧게 정리하되 source URL과 적용 지역을 보존한다.
40
+
41
+ ## Commands
42
+
43
+ ```bash
44
+ python3 daangn-cars-search/scripts/daangn_cars.py search "레이" --region "합정동" --limit 5
45
+ python3 daangn-cars-search/scripts/daangn_cars.py search --region "합정동" --price-max 10000000 --limit 5
46
+ python3 daangn-cars-search/scripts/daangn_cars.py detail "https://www.daangn.com/kr/cars/.../"
47
+ ```
48
+
49
+ ## Output fields
50
+
51
+ - title, price, price_text, region, status, driveDistance, carData, chatRoomCount, url
52
+ - detail: carPost 원문
53
+
54
+ ## Region handling
55
+
56
+ 지역 필터가 있으면 먼저 당근 지역 검색 API로 내부 지역 id를 해석한다.
57
+
58
+ ```text
59
+ https://www.daangn.com/kr/api/v1/regions/keyword?keyword=합정동
60
+ → 서울특별시 마포구 합정동, id=231
61
+ → in=합정동-231
62
+ ```
63
+
64
+ 동일한 지명이 여러 지역에 있으면 다음 우선순위로 선택한다.
65
+
66
+ 1. 사용자가 입력한 문자열이 `name`, `name1`, `name2`, `name3` 중 하나와 정확히 맞는 후보
67
+ 2. 서울 `depth=3` 동 단위 후보
68
+ 3. 첫 번째 후보
69
+
70
+ 응답에는 항상 `effective_region` 또는 실제 적용된 지역명을 포함한다. 사용자의 의도와 다른 지역으로 보이면 결과를 단정하지 말고 후보 확인을 요청한다. IP/쿠키 기본 위치에 의존하지 않는다.
71
+
72
+ ## Safety and scope
73
+
74
+ - 읽기 전용 검색/상세 조회만 수행한다.
75
+ - 로그인, 채팅, 찜, 거래 제안, 지원, 문의, 예약, 계약, 구매 자동화는 하지 않는다.
76
+ - 공개 웹 표면이 바뀌거나 빈 응답/봇 차단/로그인벽이 나오면 실패 모드로 보고하고 우회하지 않는다.
77
+ - 결과는 실시간 재고/공고 상태와 달라질 수 있으므로 source URL을 함께 제시한다.
78
+
79
+ ## Failure modes
80
+
81
+ - 당근의 Remix route 이름이나 JSON shape가 변경되면 `_data` 조회가 실패할 수 있다.
82
+ - 지역명이 넓거나 중복되면 다른 행정동이 선택될 수 있다.
83
+ - 검색 결과가 0건이어도 사이트 정책/지역 기본값/필터 조합 때문일 수 있으므로 source URL을 보존한다.
84
+ - 상세 조회는 삭제/종료/비공개 전환된 글에서 실패할 수 있다.
85
+
86
+ ## Done when
87
+
88
+ - 지역명이 있으면 지역 id를 해석하고 적용했다.
89
+ - 목록 조회 또는 상세 조회를 최소 1회 수행했다.
90
+ - 결과에 source URL과 effective region을 포함했다.
91
+ - 인증/거래성 액션은 수행하지 않았다.
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env python3
2
+ import argparse, json, re, sys, urllib.parse, urllib.request
3
+ from html import unescape
4
+
5
+ HEADERS = {"User-Agent":"Mozilla/5.0", "Accept":"application/json,text/html;q=0.9,*/*;q=0.8"}
6
+
7
+ def fetch_json(url):
8
+ req = urllib.request.Request(url, headers=HEADERS)
9
+ with urllib.request.urlopen(req, timeout=25) as r:
10
+ return json.load(r)
11
+
12
+ def fetch_text(url):
13
+ req = urllib.request.Request(url, headers={"User-Agent":"Mozilla/5.0", "Accept":"text/html"})
14
+ with urllib.request.urlopen(req, timeout=25) as r:
15
+ return r.read().decode('utf-8', 'ignore')
16
+
17
+ def won(v):
18
+ if v in (None, ''): return '-'
19
+ try: return f"{int(float(v)):,}원"
20
+ except Exception: return str(v)
21
+
22
+ def resolve_region(region):
23
+ if not region: return None
24
+ url = 'https://www.daangn.com/kr/api/v1/regions/keyword?keyword=' + urllib.parse.quote(region)
25
+ data = fetch_json(url)
26
+ locs = data.get('locations') or []
27
+ if not locs: raise SystemExit(f'지역 후보 없음: {region}')
28
+ # Exact dong/name match first, then Seoul depth-3, then first candidate.
29
+ exact = [x for x in locs if region in (x.get('name'), x.get('name1'), x.get('name2'), x.get('name3'))]
30
+ seoul = [x for x in locs if x.get('name1') == '서울특별시' and x.get('depth') == 3]
31
+ sel = (exact or seoul or locs)[0]
32
+ return sel
33
+
34
+ def region_param(sel):
35
+ return urllib.parse.quote(f"{sel['name']}-{sel['id']}")
36
+
37
+ def absolute(href):
38
+ if not href: return ''
39
+ if href.startswith('http'): return href
40
+ return 'https://www.daangn.com' + href
41
+
42
+ def print_json(obj):
43
+ print(json.dumps(obj, ensure_ascii=False, indent=2))
44
+
45
+
46
+ def cmd_search(args):
47
+ sel=resolve_region(args.region) if args.region else None
48
+ params=[]
49
+ if sel: params.append(('in', f"{sel['name']}-{sel['id']}"))
50
+ if args.only_on_sale: params.append(('onlyOnSale','1'))
51
+ if args.price_max: params.append(('priceMax', str(args.price_max)))
52
+ if args.price_min: params.append(('priceMin', str(args.price_min)))
53
+ params.append(('_data','routes/kr.cars._index'))
54
+ url='https://www.daangn.com/kr/cars/?'+urllib.parse.urlencode(params)
55
+ data=fetch_json(url); arr=((data.get('carAllPage') or {}).get('carPosts') or [])
56
+ if args.keyword:
57
+ arr=[a for a in arr if args.keyword.lower() in (a.get('title') or '').lower()]
58
+ arr=arr[:args.limit]
59
+ items=[{'title':a.get('title'),'price':a.get('price'),'price_text':won(a.get('price')),'region':(a.get('region') or {}).get('name'),
60
+ 'status':a.get('status'),'driveDistance':a.get('driveDistance'),'carData':a.get('carData'),
61
+ 'chatRoomCount':a.get('chatRoomCount'),'url':absolute(a.get('href'))} for a in arr]
62
+ print_json({'source':url,'effective_region':data.get('searchRegion') or sel,'count':len(items),'items':items})
63
+
64
+ def cmd_detail(args):
65
+ u=args.url.rstrip('/')+'/?_data=routes%2Fkr.cars.%24car_post_id'
66
+ data=fetch_json(u); print_json({'source':u,'carPost':data.get('carPost') or data})
67
+
68
+ p=argparse.ArgumentParser(description='Daangn cars read-only search/detail')
69
+ sub=p.add_subparsers(dest='cmd', required=True)
70
+ s=sub.add_parser('search'); s.add_argument('keyword', nargs='?'); s.add_argument('--region'); s.add_argument('--price-min',type=int); s.add_argument('--price-max',type=int); s.add_argument('--only-on-sale',action='store_true',default=True); s.add_argument('--limit',type=int,default=10); s.set_defaults(func=cmd_search)
71
+ d=sub.add_parser('detail'); d.add_argument('url'); d.set_defaults(func=cmd_detail)
72
+ args=p.parse_args(); args.func(args)
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "daangn-cars-search",
3
+ "description": "당근중고차 공개 웹 데이터로 차량을 검색하고, 돌쇠에서는 공식 계정 표면에서 문의·찜·거래 준비까지 진행한다.",
4
+ "profiles": [
5
+ "proxy",
6
+ "action:commerce"
7
+ ],
8
+ "frontmatter": "name: daangn-cars-search\ndescription: 당근중고차 공개 웹 데이터로 차량을 검색하고, 돌쇠에서는 공식 계정 표면에서 문의·찜·거래 준비까지 진행한다.\nlicense: MIT\nmetadata:\n category: automotive\n locale: ko-KR\n phase: v1"
9
+ }
@@ -0,0 +1,90 @@
1
+ # Daangn Jobs Search
2
+
3
+ ## What this skill does
4
+
5
+ 당근알바 공개 Remix `_data` JSON route로 채용/알바 공고 목록과 상세 정보를 읽기 전용으로 조회한다.
6
+
7
+ 최종 사용자는 자연어로 요청해도 되고, 필요하면 아래의 Python helper를 직접 실행한다. 외부 패키지나 k-skill-proxy 없이 Python 표준 라이브러리만 사용한다.
8
+
9
+ ## When to use
10
+
11
+ - "당근알바 합정동 카페 찾아봐"
12
+ - "홍대 근처 주말 알바 검색"
13
+ - "이 당근알바 공고 상세 봐줘"
14
+
15
+ ## When not to use
16
+
17
+ - 당근 계정 로그인이 필요한 작업
18
+ - 채팅, 찜, 거래 제안, 문의, 지원, 예약, 계약, 구매처럼 상대방 또는 계정에 영향을 주는 작업
19
+ - CAPTCHA/봇 차단/로그인벽 우회가 필요한 작업
20
+
21
+ ## Prerequisites
22
+
23
+ - 인터넷 연결
24
+ - Python 3.9+
25
+ - 이 저장소 루트에서 실행하거나, 스크립트 경로를 절대경로로 지정
26
+
27
+ ## Data surfaces
28
+
29
+ - Region resolver: `https://www.daangn.com/kr/api/v1/regions/keyword?keyword=<지역명>`
30
+ - Search `_data`: `/kr/jobs/?in=<지역명>-<id>&search=<keyword>&_data=routes/kr.jobs._index`
31
+ - Detail fallback: `<job-url>` redirects to `jobs.daangn.com/job-posts/<id>` and exposes public HTML title/meta/JSON-LD. The helper first tries the legacy `_data` route and falls back to HTML meta when that route returns an empty response.
32
+
33
+ ## Workflow
34
+
35
+ 1. 사용자 요청에서 키워드, 지역명, 가격/거래 유형 같은 필터를 추출한다.
36
+ 2. 지역명이 있으면 region resolver로 내부 region id를 찾는다.
37
+ 3. 목록 검색은 category별 `_data` route를 호출한다.
38
+ 4. 상세 URL이 주어지면 category별 detail route 또는 공개 HTML 메타를 조회한다.
39
+ 5. 결과를 짧게 정리하되 source URL과 적용 지역을 보존한다.
40
+
41
+ ## Commands
42
+
43
+ ```bash
44
+ python3 daangn-jobs-search/scripts/daangn_jobs.py search "카페" --region "합정동" --limit 5
45
+ python3 daangn-jobs-search/scripts/daangn_jobs.py detail "https://www.daangn.com/kr/jobs/.../"
46
+ ```
47
+
48
+ ## Output fields
49
+
50
+ - title, company, region, address, salary, salaryType, workDays, workTimeStart, workTimeEnd, closed, url
51
+ - detail: `jobPost` 원문 if the `_data` route is available; otherwise public page `title`, `meta`, and `json_ld`
52
+
53
+ ## Region handling
54
+
55
+ 지역 필터가 있으면 먼저 당근 지역 검색 API로 내부 지역 id를 해석한다.
56
+
57
+ ```text
58
+ https://www.daangn.com/kr/api/v1/regions/keyword?keyword=합정동
59
+ → 서울특별시 마포구 합정동, id=231
60
+ → in=합정동-231
61
+ ```
62
+
63
+ 동일한 지명이 여러 지역에 있으면 다음 우선순위로 선택한다.
64
+
65
+ 1. 사용자가 입력한 문자열이 `name`, `name1`, `name2`, `name3` 중 하나와 정확히 맞는 후보
66
+ 2. 서울 `depth=3` 동 단위 후보
67
+ 3. 첫 번째 후보
68
+
69
+ 응답에는 항상 `effective_region` 또는 실제 적용된 지역명을 포함한다. 사용자의 의도와 다른 지역으로 보이면 결과를 단정하지 말고 후보 확인을 요청한다. IP/쿠키 기본 위치에 의존하지 않는다.
70
+
71
+ ## Safety and scope
72
+
73
+ - 읽기 전용 검색/상세 조회만 수행한다.
74
+ - 로그인, 채팅, 찜, 거래 제안, 지원, 문의, 예약, 계약, 구매 자동화는 하지 않는다.
75
+ - 공개 웹 표면이 바뀌거나 빈 응답/봇 차단/로그인벽이 나오면 실패 모드로 보고하고 우회하지 않는다.
76
+ - 결과는 실시간 재고/공고 상태와 달라질 수 있으므로 source URL을 함께 제시한다.
77
+
78
+ ## Failure modes
79
+
80
+ - 당근의 Remix route 이름이나 JSON shape가 변경되면 `_data` 조회가 실패할 수 있다.
81
+ - 지역명이 넓거나 중복되면 다른 행정동이 선택될 수 있다.
82
+ - 검색 결과가 0건이어도 사이트 정책/지역 기본값/필터 조합 때문일 수 있으므로 source URL을 보존한다.
83
+ - 상세 조회는 삭제/종료/비공개 전환된 글에서 실패할 수 있다.
84
+
85
+ ## Done when
86
+
87
+ - 지역명이 있으면 지역 id를 해석하고 적용했다.
88
+ - 목록 조회 또는 상세 조회를 최소 1회 수행했다.
89
+ - 결과에 source URL과 effective region을 포함했다.
90
+ - 인증/거래성 액션은 수행하지 않았다.
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env python3
2
+ import argparse, json, re, sys, urllib.parse, urllib.request
3
+ from html import unescape
4
+
5
+ HEADERS = {"User-Agent":"Mozilla/5.0", "Accept":"application/json,text/html;q=0.9,*/*;q=0.8"}
6
+
7
+ def fetch_json(url):
8
+ req = urllib.request.Request(url, headers=HEADERS)
9
+ with urllib.request.urlopen(req, timeout=25) as r:
10
+ body = r.read()
11
+ if not body:
12
+ raise ValueError(f'빈 JSON 응답: {url}')
13
+ return json.loads(body)
14
+
15
+ def fetch_text(url):
16
+ req = urllib.request.Request(url, headers={"User-Agent":"Mozilla/5.0", "Accept":"text/html"})
17
+ with urllib.request.urlopen(req, timeout=25) as r:
18
+ return r.read().decode('utf-8', 'ignore')
19
+
20
+ def won(v):
21
+ if v in (None, ''): return '-'
22
+ try: return f"{int(float(v)):,}원"
23
+ except Exception: return str(v)
24
+
25
+ def resolve_region(region):
26
+ if not region: return None
27
+ url = 'https://www.daangn.com/kr/api/v1/regions/keyword?keyword=' + urllib.parse.quote(region)
28
+ data = fetch_json(url)
29
+ locs = data.get('locations') or []
30
+ if not locs: raise SystemExit(f'지역 후보 없음: {region}')
31
+ # Exact dong/name match first, then Seoul depth-3, then first candidate.
32
+ exact = [x for x in locs if region in (x.get('name'), x.get('name1'), x.get('name2'), x.get('name3'))]
33
+ seoul = [x for x in locs if x.get('name1') == '서울특별시' and x.get('depth') == 3]
34
+ sel = (exact or seoul or locs)[0]
35
+ return sel
36
+
37
+ def region_param(sel):
38
+ return urllib.parse.quote(f"{sel['name']}-{sel['id']}")
39
+
40
+ def absolute(href):
41
+ if not href: return ''
42
+ if href.startswith('http'): return href
43
+ return 'https://www.daangn.com' + href
44
+
45
+ def print_json(obj):
46
+ print(json.dumps(obj, ensure_ascii=False, indent=2))
47
+
48
+ def parse_html_detail(url):
49
+ html = fetch_text(url)
50
+ title = re.search(r'<title>(.*?)</title>', html, re.S)
51
+ meta = {}
52
+ for m in re.finditer(r'<meta[^>]+(?:property|name)=["\']([^"\']+)["\'][^>]+content=["\']([^"\']*)["\']', html):
53
+ key, value = m.group(1), unescape(m.group(2)).strip()
54
+ if key in ('description', 'og:title', 'og:description', 'og:image'):
55
+ meta[key] = value
56
+ json_ld = []
57
+ for m in re.finditer(r'<script[^>]*type=["\']application/ld\+json["\'][^>]*>(.*?)</script>', html, re.S):
58
+ try:
59
+ json_ld.append(json.loads(unescape(m.group(1))))
60
+ except Exception:
61
+ pass
62
+ return {
63
+ 'source': url,
64
+ 'title': unescape(title.group(1)).strip() if title else meta.get('og:title'),
65
+ 'meta': meta,
66
+ 'json_ld': json_ld[:3],
67
+ }
68
+
69
+
70
+ def cmd_search(args):
71
+ sel=resolve_region(args.region) if args.region else None
72
+ params=[]
73
+ if sel: params.append(('in', f"{sel['name']}-{sel['id']}"))
74
+ if args.keyword: params.append(('search', args.keyword))
75
+ params.append(('_data','routes/kr.jobs._index'))
76
+ url='https://www.daangn.com/kr/jobs/?'+urllib.parse.urlencode(params)
77
+ data=fetch_json(url); arr=((data.get('jobsAllPage') or {}).get('jobPosts') or [])[:args.limit]
78
+ items=[{'title':a.get('title'),'company':a.get('workplaceCompanyName'),'region':a.get('workplaceRegion'),
79
+ 'address':a.get('workplaceRoadNameAddress'),'salary':a.get('salary'),'salaryType':a.get('salaryType'),
80
+ 'workDays':a.get('workDays'),'workTimeStart':a.get('workTimeStart'),'workTimeEnd':a.get('workTimeEnd'),
81
+ 'closed':a.get('closed'),'url':absolute(a.get('href') or a.get('jobsWebDetailUrl'))} for a in arr]
82
+ print_json({'source':url,'effective_region':data.get('searchRegion') or sel,'count':len(items),'items':items})
83
+
84
+ def cmd_detail(args):
85
+ u=args.url.rstrip('/')+'/?_data=routes%2Fkr.jobs.%24job_post_id'
86
+ try:
87
+ data=fetch_json(u)
88
+ print_json({'source':u,'jobPost':data.get('jobPost') or data})
89
+ except Exception:
90
+ detail = parse_html_detail(args.url)
91
+ detail['data_source_attempted'] = u
92
+ print_json(detail)
93
+
94
+ p=argparse.ArgumentParser(description='Daangn jobs read-only search/detail')
95
+ sub=p.add_subparsers(dest='cmd', required=True)
96
+ s=sub.add_parser('search'); s.add_argument('keyword', nargs='?'); s.add_argument('--region'); s.add_argument('--limit',type=int,default=10); s.set_defaults(func=cmd_search)
97
+ d=sub.add_parser('detail'); d.add_argument('url'); d.set_defaults(func=cmd_detail)
98
+ args=p.parse_args(); args.func(args)
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "daangn-jobs-search",
3
+ "description": "당근알바 공개 웹 데이터로 공고를 검색하고, 돌쇠에서는 공식 계정 표면에서 지원서 작성·채팅·승인 기반 전송까지 진행한다.",
4
+ "profiles": [
5
+ "proxy",
6
+ "action:communication"
7
+ ],
8
+ "frontmatter": "name: daangn-jobs-search\ndescription: 당근알바 공개 웹 데이터로 공고를 검색하고, 돌쇠에서는 공식 계정 표면에서 지원서 작성·채팅·승인 기반 전송까지 진행한다.\nlicense: MIT\nmetadata:\n category: jobs\n locale: ko-KR\n phase: v1"
9
+ }