smart-web-mcp 0.9.1 → 0.10.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 (58) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/korea/coupang.d.ts +46 -0
  3. package/dist/korea/coupang.js +165 -0
  4. package/dist/korea/coupang.js.map +1 -0
  5. package/dist/korea/dart.d.ts +53 -0
  6. package/dist/korea/dart.js +105 -0
  7. package/dist/korea/dart.js.map +1 -0
  8. package/dist/korea/drug-safety.d.ts +33 -0
  9. package/dist/korea/drug-safety.js +60 -0
  10. package/dist/korea/drug-safety.js.map +1 -0
  11. package/dist/korea/fine-dust.d.ts +27 -0
  12. package/dist/korea/fine-dust.js +88 -0
  13. package/dist/korea/fine-dust.js.map +1 -0
  14. package/dist/korea/food-safety.d.ts +21 -0
  15. package/dist/korea/food-safety.js +50 -0
  16. package/dist/korea/food-safety.js.map +1 -0
  17. package/dist/korea/geeknews.d.ts +31 -0
  18. package/dist/korea/geeknews.js +144 -0
  19. package/dist/korea/geeknews.js.map +1 -0
  20. package/dist/korea/index.d.ts +16 -0
  21. package/dist/korea/index.js +17 -0
  22. package/dist/korea/index.js.map +1 -0
  23. package/dist/korea/law.d.ts +41 -0
  24. package/dist/korea/law.js +85 -0
  25. package/dist/korea/law.js.map +1 -0
  26. package/dist/korea/naver-news.d.ts +38 -0
  27. package/dist/korea/naver-news.js +67 -0
  28. package/dist/korea/naver-news.js.map +1 -0
  29. package/dist/korea/naver-shopping.d.ts +39 -0
  30. package/dist/korea/naver-shopping.js +51 -0
  31. package/dist/korea/naver-shopping.js.map +1 -0
  32. package/dist/korea/proxy-client.d.ts +20 -0
  33. package/dist/korea/proxy-client.js +88 -0
  34. package/dist/korea/proxy-client.js.map +1 -0
  35. package/dist/korea/public-restroom.d.ts +44 -0
  36. package/dist/korea/public-restroom.js +184 -0
  37. package/dist/korea/public-restroom.js.map +1 -0
  38. package/dist/korea/real-estate.d.ts +56 -0
  39. package/dist/korea/real-estate.js +95 -0
  40. package/dist/korea/real-estate.js.map +1 -0
  41. package/dist/korea/spellcheck.d.ts +32 -0
  42. package/dist/korea/spellcheck.js +142 -0
  43. package/dist/korea/spellcheck.js.map +1 -0
  44. package/dist/korea/stock.d.ts +59 -0
  45. package/dist/korea/stock.js +84 -0
  46. package/dist/korea/stock.js.map +1 -0
  47. package/dist/korea/subway.d.ts +29 -0
  48. package/dist/korea/subway.js +47 -0
  49. package/dist/korea/subway.js.map +1 -0
  50. package/dist/korea/weather.d.ts +35 -0
  51. package/dist/korea/weather.js +92 -0
  52. package/dist/korea/weather.js.map +1 -0
  53. package/dist/korea/zipcode.d.ts +25 -0
  54. package/dist/korea/zipcode.js +70 -0
  55. package/dist/korea/zipcode.js.map +1 -0
  56. package/dist/mcp-server.js +386 -0
  57. package/dist/mcp-server.js.map +1 -1
  58. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -8,6 +8,8 @@ The format is based on Keep a Changelog[^1] and this project uses SemVer.
8
8
 
9
9
  ### Added
10
10
 
11
+ - 16 new Korean MCP tools: `kr_geeknews` (GeekNews RSS), `kr_subway` (서울 지하철 실시간 도착정보), `kr_weather` (기상청 단기예보), `kr_fine_dust` (에어코리아 미세먼지), `kr_stock` (KRX 주식), `kr_dart` (금감원 DART 전자공시), `kr_real_estate` (국토부 부동산 실거래가), `kr_drug_safety` (식약처 의약품 안전), `kr_food_safety` (식품안전나라), `kr_naver_news` (네이버 뉴스 검색), `kr_naver_shopping` (네이버 쇼핑 가격비교), `kr_coupang` (쿠팡 상품 키워드검색 + anti-bot 우회), `kr_spellcheck` (한국어 맞춤법 검사), `kr_zipcode` (우체국 우편번호 검색), `kr_law` (법망 한국 법령 검색), `kr_public_restroom` (공공데이터 공중화장실 조회). Most tools call the public k-skill-proxy endpoint; `kr_coupang` uses the Retention Corp hosted backend (a.retn.kr) to bypass Coupang anti-bot; `kr_dart` uses `API_K_DART` env var; `kr_public_restroom` uses the official nationwide CSV dataset.
12
+
11
13
  - `smartfetch` now recognizes Naver Map and Kakao Map place URLs as first-class targets and normalizes place metadata such as title, address, phone, hours, review counts, and canonical place links instead of treating them as generic map shells
12
14
  - `smartsearch` now has site-native public fallbacks for `site:reddit.com`, `site:github.com` repository discovery, and `site:npmjs.com` queries alongside the existing Velog, Stack Exchange, and Hacker News fallbacks
13
15
  - `smartfetch` now has first-class competitive-programming fetch coverage for BOJ, Codeforces, AtCoder, QOJ, and Jungol problem/profile-style pages, plus solved.ac profile normalization through the unofficial user APIs
@@ -28,6 +30,20 @@ The format is based on Keep a Changelog[^1] and this project uses SemVer.
28
30
  - `smart-web-dev` issue reporting now points at `jojo-labs/smart-web`, and the dev hot-reload runtime writes explicit ESM snapshot metadata before loading rebuilt `dist/*.js` modules
29
31
  - `initSettings` now writes `settings.json` through a temp file + rename so crashes during first-run or `--force` initialization cannot leave the runtime config truncated
30
32
 
33
+ ## [0.10.0](https://github.com/jojo-labs/smart-web/compare/v0.9.2...v0.10.0) (2026-04-25)
34
+
35
+
36
+ ### Features
37
+
38
+ * **korea:** add 16 Korean MCP tools ([#122](https://github.com/jojo-labs/smart-web/issues/122)) ([42df840](https://github.com/jojo-labs/smart-web/commit/42df840f95fd820fc3da420ae6ec235f37cb28e4))
39
+
40
+ ## [0.9.2](https://github.com/jojo-labs/smart-web/compare/v0.9.1...v0.9.2) (2026-04-25)
41
+
42
+
43
+ ### CI / Release
44
+
45
+ * make required PR verify match main checks ([#120](https://github.com/jojo-labs/smart-web/issues/120)) ([89920af](https://github.com/jojo-labs/smart-web/commit/89920aff2e6ba8caaebc42c6a2be2eb59471addf))
46
+
31
47
  ## [0.9.1](https://github.com/jojo-labs/smart-web/compare/v0.9.0...v0.9.1) (2026-04-25)
32
48
 
33
49
 
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Coupang product keyword search via Retention Corp hosted backend.
3
+ *
4
+ * Two execution paths (same as upstream coupang_partners library):
5
+ * 1. Operator path — COUPANG_ACCESS_KEY + COUPANG_SECRET_KEY both set.
6
+ * Calls Coupang Partners API with local HMAC signing.
7
+ * Not implemented here; use the Python library for that path.
8
+ * 2. Hosted fallback — keys absent or OPENCLAW_SHOPPING_FORCE_HOSTED=1.
9
+ * Calls https://a.retn.kr/v1/public/assist with X-OpenClaw-Client-Id: openclaw-skill.
10
+ * This path works without any credentials.
11
+ *
12
+ * This module implements the hosted fallback path only.
13
+ * For URL-based product pages (www.coupang.com/vp/products/...), the existing
14
+ * commerce provider in smartfetch handles fetching and anti-bot fallback.
15
+ *
16
+ * Affiliate disclosure: links from this endpoint are Retention Corp affiliate links
17
+ * (https://a.retn.kr/s/...). Disclose to users per the SKILL.md policy.
18
+ */
19
+ export type CoupangProduct = {
20
+ title: string;
21
+ price?: string;
22
+ is_rocket: boolean;
23
+ url: string;
24
+ image_url?: string;
25
+ rating?: string;
26
+ review_count?: string;
27
+ };
28
+ export type CoupangResult = {
29
+ source: "coupang";
30
+ action: string;
31
+ query: string;
32
+ products: CoupangProduct[];
33
+ disclosure: string;
34
+ note: string;
35
+ };
36
+ export declare function runCoupang(options: {
37
+ action?: "search" | "rocket" | "budget" | "compare" | "goldbox";
38
+ query?: string;
39
+ maxPrice?: number;
40
+ limit?: number;
41
+ timeoutMs?: number;
42
+ }): Promise<CoupangResult | {
43
+ ok: false;
44
+ message: string;
45
+ }>;
46
+ export declare function renderCoupang(result: CoupangResult): string;
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Coupang product keyword search via Retention Corp hosted backend.
3
+ *
4
+ * Two execution paths (same as upstream coupang_partners library):
5
+ * 1. Operator path — COUPANG_ACCESS_KEY + COUPANG_SECRET_KEY both set.
6
+ * Calls Coupang Partners API with local HMAC signing.
7
+ * Not implemented here; use the Python library for that path.
8
+ * 2. Hosted fallback — keys absent or OPENCLAW_SHOPPING_FORCE_HOSTED=1.
9
+ * Calls https://a.retn.kr/v1/public/assist with X-OpenClaw-Client-Id: openclaw-skill.
10
+ * This path works without any credentials.
11
+ *
12
+ * This module implements the hosted fallback path only.
13
+ * For URL-based product pages (www.coupang.com/vp/products/...), the existing
14
+ * commerce provider in smartfetch handles fetching and anti-bot fallback.
15
+ *
16
+ * Affiliate disclosure: links from this endpoint are Retention Corp affiliate links
17
+ * (https://a.retn.kr/s/...). Disclose to users per the SKILL.md policy.
18
+ */
19
+ import { httpPost } from "./proxy-client.js";
20
+ const RETN_BASE = (process.env["OPENCLAW_SHOPPING_BASE_URL"] || "https://a.retn.kr").replace(/\/$/, "");
21
+ const RETN_ASSIST = `${RETN_BASE}/v1/public/assist`;
22
+ const CLIENT_ID = process.env["OPENCLAW_SHOPPING_CLIENT_ID"] || "openclaw-skill";
23
+ function parseProducts(raw) {
24
+ if (!Array.isArray(raw)) {
25
+ // Try text extraction if result is a string
26
+ if (typeof raw === "string") {
27
+ return parseProductsFromText(raw);
28
+ }
29
+ return [];
30
+ }
31
+ return raw.map((item) => {
32
+ const priceRaw = item["price"] ?? item["salePrice"];
33
+ return {
34
+ title: String(item["productName"] ?? item["title"] ?? item["name"] ?? ""),
35
+ is_rocket: Boolean(item["isRocket"] ?? item["rocket"] ?? false),
36
+ url: String(item["productUrl"] ?? item["url"] ?? item["link"] ?? ""),
37
+ ...(priceRaw !== undefined ? { price: String(priceRaw) } : {}),
38
+ ...(item["imageUrl"] ? { image_url: String(item["imageUrl"]) } : {}),
39
+ ...(item["rating"] !== undefined ? { rating: String(item["rating"]) } : {}),
40
+ ...(item["reviewCount"] !== undefined ? { review_count: String(item["reviewCount"]) } : {}),
41
+ };
42
+ }).filter((p) => p.title || p.url);
43
+ }
44
+ function parseProductsFromText(text) {
45
+ // Best-effort: extract JSON array from MCP content text
46
+ try {
47
+ const jsonMatch = text.match(/\[[\s\S]*\]/);
48
+ if (jsonMatch) {
49
+ const arr = JSON.parse(jsonMatch[0]);
50
+ if (Array.isArray(arr))
51
+ return parseProducts(arr);
52
+ }
53
+ }
54
+ catch {
55
+ // ignore
56
+ }
57
+ return [];
58
+ }
59
+ async function callRetentionAssist(tool, args, timeoutMs) {
60
+ const body = JSON.stringify({
61
+ jsonrpc: "2.0",
62
+ id: 1,
63
+ method: "tools/call",
64
+ params: { name: tool, arguments: args },
65
+ });
66
+ const result = await httpPost(RETN_ASSIST, body, {
67
+ "Content-Type": "application/json",
68
+ "X-OpenClaw-Client-Id": CLIENT_ID,
69
+ accept: "application/json",
70
+ }, timeoutMs);
71
+ if (!result.ok)
72
+ return { ok: false, message: result.message };
73
+ const envelope = result.data;
74
+ return envelope;
75
+ }
76
+ function extractProducts(envelope) {
77
+ const payload = envelope.data?.payload;
78
+ const resultContent = payload?.["result"]?.["content"];
79
+ if (Array.isArray(resultContent)) {
80
+ for (const block of resultContent) {
81
+ if (block["type"] === "text") {
82
+ const text = String(block["text"] ?? "");
83
+ const products = parseProductsFromText(text);
84
+ if (products.length > 0)
85
+ return products;
86
+ }
87
+ }
88
+ }
89
+ if (envelope.data?.result)
90
+ return parseProducts(envelope.data.result);
91
+ return [];
92
+ }
93
+ export async function runCoupang(options) {
94
+ const { action = "search", query, maxPrice, limit = 10, timeoutMs = 20000 } = options;
95
+ const disclosure = "파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음";
96
+ const note = "가격·품절·배송 정보는 실시간으로 변동될 수 있습니다.";
97
+ if (action === "goldbox") {
98
+ const envelope = await callRetentionAssist("get_coupang_goldbox", { limit }, timeoutMs);
99
+ if (!envelope.ok)
100
+ return { ok: false, message: "message" in envelope ? envelope.message : "Coupang goldbox failed" };
101
+ const products = extractProducts(envelope);
102
+ return { source: "coupang", action: "goldbox", query: "골드박스 특가", products, disclosure, note };
103
+ }
104
+ if (!query)
105
+ return { ok: false, message: "검색어(query)가 필요합니다." };
106
+ let tool = "search_coupang_products";
107
+ const args = { keyword: query, limit };
108
+ if (action === "rocket") {
109
+ tool = "search_coupang_rocket";
110
+ }
111
+ else if (action === "budget" && maxPrice !== undefined) {
112
+ tool = "search_coupang_budget";
113
+ args["max_price"] = maxPrice;
114
+ }
115
+ else if (action === "compare") {
116
+ tool = "compare_coupang_products";
117
+ args["query"] = query;
118
+ }
119
+ const envelope = await callRetentionAssist(tool, args, timeoutMs);
120
+ if (!envelope.ok) {
121
+ const msg = "message" in envelope ? envelope.message : "Coupang search failed";
122
+ return { ok: false, message: msg };
123
+ }
124
+ const ev = envelope;
125
+ if (!ev.ok || !ev.data) {
126
+ return { ok: false, message: `Coupang hosted backend error: ${ev.error ?? "no data returned"}` };
127
+ }
128
+ const products = extractProducts(ev);
129
+ return { source: "coupang", action, query, products, disclosure, note };
130
+ }
131
+ export function renderCoupang(result) {
132
+ const lines = [
133
+ `# 쿠팡 ${result.action === "goldbox" ? "골드박스" : `"${result.query}"`}`,
134
+ result.action === "rocket" ? "_(로켓배송 전용)_" : "",
135
+ "",
136
+ ].filter((l) => l !== "");
137
+ if (result.products.length === 0) {
138
+ lines.push("검색 결과가 없습니다.");
139
+ lines.push("");
140
+ }
141
+ const rocket = result.products.filter((p) => p.is_rocket);
142
+ const normal = result.products.filter((p) => !p.is_rocket);
143
+ if (rocket.length > 0) {
144
+ lines.push("## 로켓배송");
145
+ for (const p of rocket.slice(0, 5)) {
146
+ lines.push(`- **${p.title}**${p.price ? ` — ${p.price}` : ""}`);
147
+ if (p.url)
148
+ lines.push(` [보러가기](${p.url})`);
149
+ }
150
+ lines.push("");
151
+ }
152
+ if (normal.length > 0) {
153
+ lines.push("## 일반배송");
154
+ for (const p of normal.slice(0, 5)) {
155
+ lines.push(`- **${p.title}**${p.price ? ` — ${p.price}` : ""}`);
156
+ if (p.url)
157
+ lines.push(` [보러가기](${p.url})`);
158
+ }
159
+ lines.push("");
160
+ }
161
+ lines.push(`_${result.disclosure}_`);
162
+ lines.push(`_${result.note}_`);
163
+ return lines.join("\n");
164
+ }
165
+ //# sourceMappingURL=coupang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coupang.js","sourceRoot":"","sources":["../../src/korea/coupang.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * 금감원 DART 전자공시 조회 — direct API, requires API_K_DART env var
3
+ * API base: https://opendart.fss.or.kr/api/
4
+ */
5
+ export type DartDisclosure = {
6
+ corp_code: string;
7
+ corp_name: string;
8
+ stock_code: string;
9
+ corp_cls: string;
10
+ report_nm: string;
11
+ rcept_no: string;
12
+ flr_nm: string;
13
+ rcept_dt: string;
14
+ rm: string;
15
+ };
16
+ export type DartCompany = {
17
+ corp_code: string;
18
+ corp_name: string;
19
+ corp_name_eng?: string;
20
+ stock_code?: string;
21
+ ceo_nm?: string;
22
+ adres?: string;
23
+ est_dt?: string;
24
+ hm_url?: string;
25
+ induty_code?: string;
26
+ acc_mt?: string;
27
+ };
28
+ export type DartResult = {
29
+ source: "dart";
30
+ status: string;
31
+ message: string;
32
+ action: string;
33
+ data: Record<string, unknown>;
34
+ };
35
+ export declare function runDart(options: {
36
+ action: "search" | "company" | "financials" | "disclosures";
37
+ corp_code?: string;
38
+ corp_name?: string;
39
+ stock_code?: string;
40
+ bgn_de?: string;
41
+ end_de?: string;
42
+ bsns_year?: string;
43
+ reprt_code?: string;
44
+ fs_div?: "OFS" | "CFS";
45
+ pblntf_ty?: string;
46
+ page_no?: number;
47
+ page_count?: number;
48
+ timeoutMs?: number;
49
+ }): Promise<DartResult | {
50
+ ok: false;
51
+ message: string;
52
+ }>;
53
+ export declare function renderDart(result: DartResult): string;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * 금감원 DART 전자공시 조회 — direct API, requires API_K_DART env var
3
+ * API base: https://opendart.fss.or.kr/api/
4
+ */
5
+ import { httpGet } from "./proxy-client.js";
6
+ const DART_BASE = "https://opendart.fss.or.kr/api";
7
+ function dartKey() {
8
+ return process.env["API_K_DART"] ?? null;
9
+ }
10
+ async function dartGet(endpoint, params, timeoutMs = 20000) {
11
+ const key = dartKey();
12
+ if (!key) {
13
+ return { ok: false, message: "API_K_DART 환경변수가 없습니다. https://opendart.fss.or.kr 에서 발급하세요." };
14
+ }
15
+ const url = new URL(`${DART_BASE}/${endpoint}`);
16
+ url.searchParams.set("crtfc_key", key);
17
+ for (const [k, v] of Object.entries(params)) {
18
+ if (v)
19
+ url.searchParams.set(k, v);
20
+ }
21
+ const result = await httpGet(url.toString(), {}, timeoutMs);
22
+ if (!result.ok)
23
+ return { ok: false, message: result.message };
24
+ const d = result.data;
25
+ if (d["status"] && d["status"] !== "000") {
26
+ return { ok: false, message: `DART API 오류: [${d["status"]}] ${String(d["message"] ?? "")}` };
27
+ }
28
+ return { ok: true, data: result.data };
29
+ }
30
+ export async function runDart(options) {
31
+ const { action, corp_code, bgn_de, end_de, bsns_year, reprt_code = "11011", fs_div = "CFS", pblntf_ty, page_no = 1, page_count = 10, timeoutMs = 20000, } = options;
32
+ if (action === "company") {
33
+ if (!corp_code)
34
+ return { ok: false, message: "corp_code가 필요합니다." };
35
+ const result = await dartGet("company.json", { corp_code }, timeoutMs);
36
+ if (!result.ok)
37
+ return result;
38
+ return { source: "dart", status: "000", message: "정상", action, data: result.data };
39
+ }
40
+ if (action === "financials") {
41
+ if (!corp_code)
42
+ return { ok: false, message: "corp_code가 필요합니다." };
43
+ if (!bsns_year)
44
+ return { ok: false, message: "bsns_year(사업연도)가 필요합니다." };
45
+ const result = await dartGet("fnlttSinglAcntAll.json", { corp_code, bsns_year, reprt_code, fs_div }, timeoutMs);
46
+ if (!result.ok)
47
+ return result;
48
+ return { source: "dart", status: "000", message: "정상", action, data: result.data };
49
+ }
50
+ // disclosures (list.json)
51
+ const today = new Date().toISOString().slice(0, 10).replace(/-/g, "");
52
+ const threeMonthsAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10).replace(/-/g, "");
53
+ const params = {
54
+ bgn_de: bgn_de ?? threeMonthsAgo,
55
+ end_de: end_de ?? today,
56
+ page_no: String(page_no),
57
+ page_count: String(page_count),
58
+ sort: "date",
59
+ sort_mth: "desc",
60
+ };
61
+ if (corp_code)
62
+ params["corp_code"] = corp_code;
63
+ if (pblntf_ty)
64
+ params["pblntf_ty"] = pblntf_ty;
65
+ const result = await dartGet("list.json", params, timeoutMs);
66
+ if (!result.ok)
67
+ return result;
68
+ return { source: "dart", status: "000", message: "정상", action, data: result.data };
69
+ }
70
+ export function renderDart(result) {
71
+ if (result.action === "company") {
72
+ const d = result.data;
73
+ return [
74
+ `# DART 기업개황 — ${String(d["corp_name"] ?? "")}`,
75
+ d["corp_name_eng"] ? `영문명: ${String(d["corp_name_eng"])}` : "",
76
+ `종목코드: ${String(d["stock_code"] ?? "-")}`,
77
+ `대표자: ${String(d["ceo_nm"] ?? "-")}`,
78
+ `업종코드: ${String(d["induty_code"] ?? "-")}`,
79
+ `설립일: ${String(d["est_dt"] ?? "-")}`,
80
+ `결산월: ${String(d["acc_mt"] ?? "-")}월`,
81
+ d["adres"] ? `주소: ${String(d["adres"])}` : "",
82
+ d["hm_url"] ? `홈페이지: ${String(d["hm_url"])}` : "",
83
+ "",
84
+ "_금감원 DART 공시 데이터 기준 / 투자 조언 아님_",
85
+ ].filter((l) => l !== "").join("\n");
86
+ }
87
+ if (result.action === "financials") {
88
+ const list = (result.data["list"] ?? []);
89
+ const lines = ["# DART 재무제표", ""];
90
+ for (const item of list.slice(0, 20)) {
91
+ lines.push(`- **${String(item["account_nm"] ?? "")}**: ${String(item["thstrm_amount"] ?? "")}`);
92
+ }
93
+ lines.push("\n_금감원 DART 공시 데이터 기준 / 투자 조언 아님_");
94
+ return lines.join("\n");
95
+ }
96
+ // disclosures
97
+ const list = (result.data["list"] ?? []);
98
+ const lines = ["# DART 공시 목록", `총 ${String(result.data["total_count"] ?? "?")}건`, ""];
99
+ for (const item of list) {
100
+ lines.push(`- **${item.report_nm}** — ${item.corp_name} (${item.rcept_dt})`);
101
+ }
102
+ lines.push("\n_금감원 DART 공시 데이터 기준 / 투자 조언 아님_");
103
+ return lines.join("\n");
104
+ }
105
+ //# sourceMappingURL=dart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dart.js","sourceRoot":"","sources":["../../src/korea/dart.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAE3C,MAAM,SAAS,GAAG,gCAAgC,CAAA;AAmClD,SAAS,OAAO;IACd,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,CAAA;AAC1C,CAAC;AAED,KAAK,UAAU,OAAO,CAAoC,QAAgB,EAAE,MAA8B,EAAE,SAAS,GAAG,KAAK;IAC3H,MAAM,GAAG,GAAG,OAAO,EAAE,CAAA;IACrB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,6DAA6D,EAAE,CAAA;IAC9F,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,SAAS,IAAI,QAAQ,EAAE,CAAC,CAAA;IAC/C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;IACtC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC;YAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACnC,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC,CAAA;IAC9D,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAA;IAE7D,MAAM,CAAC,GAAG,MAAM,CAAC,IAA+B,CAAA;IAChD,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK,EAAE,CAAC;QACzC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAA;IAC9F,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAA;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAc7B;IACC,MAAM,EACJ,MAAM,EACN,SAAS,EACT,MAAM,EACN,MAAM,EACN,SAAS,EACT,UAAU,GAAG,OAAO,EACpB,MAAM,GAAG,KAAK,EACd,SAAS,EACT,OAAO,GAAG,CAAC,EACX,UAAU,GAAG,EAAE,EACf,SAAS,GAAG,KAAK,GAClB,GAAG,OAAO,CAAA;IAEX,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAA;QAClE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,EAAE,SAAS,CAAC,CAAA;QACtE,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,MAAM,CAAA;QAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAA+B,EAAE,CAAA;IAC/G,CAAC;IAED,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAA;QAClE,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAA;QACxE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,wBAAwB,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,CAAA;QAC/G,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,MAAM,CAAA;QAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAA+B,EAAE,CAAA;IAC/G,CAAC;IAED,0BAA0B;IAC1B,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACrE,MAAM,cAAc,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACnH,MAAM,MAAM,GAA2B;QACrC,MAAM,EAAE,MAAM,IAAI,cAAc;QAChC,MAAM,EAAE,MAAM,IAAI,KAAK;QACvB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;QAC9B,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,MAAM;KACjB,CAAA;IACD,IAAI,SAAS;QAAE,MAAM,CAAC,WAAW,CAAC,GAAG,SAAS,CAAA;IAC9C,IAAI,SAAS;QAAE,MAAM,CAAC,WAAW,CAAC,GAAG,SAAS,CAAA;IAE9C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;IAC5D,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAA;IAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAA+B,EAAE,CAAA;AAC/G,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAkB;IAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAA;QACrB,OAAO;YACL,iBAAiB,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE;YAC/C,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YAC9D,SAAS,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE;YACzC,QAAQ,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE;YACpC,SAAS,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,EAAE;YAC1C,QAAQ,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE;YACpC,QAAQ,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,GAAG;YACrC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YAC7C,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YACjD,EAAE;YACF,iCAAiC;SAClC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAA8B,CAAA;QACrE,MAAM,KAAK,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC,CAAA;QACjC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;QACjG,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAA;QAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAED,cAAc;IACd,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAqB,CAAA;IAC5D,MAAM,KAAK,GAAG,CAAC,cAAc,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IACrF,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,QAAQ,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;IAC9E,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAA;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Drug safety info (식약처 의약품) via k-skill-proxy
3
+ * Endpoint: GET /v1/mfds/drug-safety/lookup?itemName=타이레놀
4
+ *
5
+ * Policy: always surface red flags first. This tool returns data only.
6
+ * Do NOT use for emergency diagnosis — always refer to 119/응급실 when needed.
7
+ */
8
+ export type DrugItem = {
9
+ item_name?: string;
10
+ entp_name?: string;
11
+ efcy_qesitm?: string;
12
+ use_method_qesitm?: string;
13
+ atpn_qesitm?: string;
14
+ intrc_qesitm?: string;
15
+ se_qesitm?: string;
16
+ deposit_method_qesitm?: string;
17
+ item_image?: string;
18
+ source?: string;
19
+ };
20
+ export type DrugSafetyResult = {
21
+ source: "drug-safety";
22
+ query: string[];
23
+ total: number;
24
+ items: DrugItem[];
25
+ };
26
+ export declare function runDrugSafety(options: {
27
+ itemNames: string[];
28
+ timeoutMs?: number;
29
+ }): Promise<DrugSafetyResult | {
30
+ ok: false;
31
+ message: string;
32
+ }>;
33
+ export declare function renderDrugSafety(result: DrugSafetyResult): string;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Drug safety info (식약처 의약품) via k-skill-proxy
3
+ * Endpoint: GET /v1/mfds/drug-safety/lookup?itemName=타이레놀
4
+ *
5
+ * Policy: always surface red flags first. This tool returns data only.
6
+ * Do NOT use for emergency diagnosis — always refer to 119/응급실 when needed.
7
+ */
8
+ import { proxyGet } from "./proxy-client.js";
9
+ export async function runDrugSafety(options) {
10
+ const { itemNames, timeoutMs = 20000 } = options;
11
+ if (!itemNames.length)
12
+ return { ok: false, message: "itemName이 필요합니다." };
13
+ const allItems = [];
14
+ for (const itemName of itemNames) {
15
+ const result = await proxyGet("/v1/mfds/drug-safety/lookup", { itemName }, timeoutMs);
16
+ if (!result.ok) {
17
+ if (allItems.length === 0)
18
+ return { ok: false, message: `Drug safety lookup failed: ${result.message}` };
19
+ continue;
20
+ }
21
+ const items = (result.data["items"] ?? result.data["list"] ?? [result.data]);
22
+ allItems.push(...items);
23
+ }
24
+ return {
25
+ source: "drug-safety",
26
+ query: itemNames,
27
+ total: allItems.length,
28
+ items: allItems,
29
+ };
30
+ }
31
+ export function renderDrugSafety(result) {
32
+ const lines = [
33
+ "⚠️ **이 정보는 참고용입니다. 최종 판단은 약사·의료진에게 확인하세요. 응급 증상(호흡곤란·의식저하·심한 발진)은 즉시 119.**",
34
+ "",
35
+ `# 의약품 안전 정보 — ${result.query.join(", ")}`,
36
+ `총 ${result.total}건`,
37
+ "",
38
+ ];
39
+ for (const item of result.items) {
40
+ lines.push(`## ${item.item_name ?? "?"}`);
41
+ if (item.entp_name)
42
+ lines.push(`- 제조사: ${item.entp_name}`);
43
+ if (item.efcy_qesitm)
44
+ lines.push(`\n**효능·효과**: ${item.efcy_qesitm}`);
45
+ if (item.use_method_qesitm)
46
+ lines.push(`\n**용법·용량**: ${item.use_method_qesitm}`);
47
+ if (item.atpn_qesitm)
48
+ lines.push(`\n**주의사항**: ${item.atpn_qesitm}`);
49
+ if (item.intrc_qesitm)
50
+ lines.push(`\n**상호작용**: ${item.intrc_qesitm}`);
51
+ if (item.se_qesitm)
52
+ lines.push(`\n**이상반응**: ${item.se_qesitm}`);
53
+ if (item.deposit_method_qesitm)
54
+ lines.push(`\n**보관법**: ${item.deposit_method_qesitm}`);
55
+ lines.push("");
56
+ }
57
+ lines.push("_식약처 e약은요 공식 데이터 기준_");
58
+ return lines.join("\n");
59
+ }
60
+ //# sourceMappingURL=drug-safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drug-safety.js","sourceRoot":"","sources":["../../src/korea/drug-safety.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAsB5C,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAGnC;IACC,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IAChD,IAAI,CAAC,SAAS,CAAC,MAAM;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAA;IAExE,MAAM,QAAQ,GAAe,EAAE,CAAA;IAC/B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAA0B,6BAA6B,EAAE,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAA;QAC9G,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,8BAA8B,MAAM,CAAC,OAAO,EAAE,EAAE,CAAA;YACxG,SAAQ;QACV,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAe,CAAA;QAC1F,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAA;IACzB,CAAC;IAED,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,QAAQ,CAAC,MAAM;QACtB,KAAK,EAAE,QAAQ;KAChB,CAAA;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACvD,MAAM,KAAK,GAAG;QACZ,6EAA6E;QAC7E,EAAE;QACF,iBAAiB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAC1C,KAAK,MAAM,CAAC,KAAK,GAAG;QACpB,EAAE;KACH,CAAA;IACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC,CAAA;QACzC,IAAI,IAAI,CAAC,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;QAC1D,IAAI,IAAI,CAAC,WAAW;YAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACpE,IAAI,IAAI,CAAC,iBAAiB;YAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,iBAAiB,EAAE,CAAC,CAAA;QAChF,IAAI,IAAI,CAAC,WAAW;YAAE,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACnE,IAAI,IAAI,CAAC,YAAY;YAAE,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,YAAY,EAAE,CAAC,CAAA;QACrE,IAAI,IAAI,CAAC,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;QAC/D,IAAI,IAAI,CAAC,qBAAqB;YAAE,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,qBAAqB,EAAE,CAAC,CAAA;QACtF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;IAClC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Fine dust / air quality (에어코리아) via k-skill-proxy
3
+ * Proxy endpoint: GET /v1/fine-dust/report?regionHint=서울 강남구
4
+ */
5
+ export type FineDustResult = {
6
+ source: "fine-dust";
7
+ station: string;
8
+ region_hint: string;
9
+ queried_at: string;
10
+ pm10: string;
11
+ pm10_grade: string;
12
+ pm25: string;
13
+ pm25_grade: string;
14
+ overall_grade: string;
15
+ retrieval_method: string;
16
+ candidate_stations?: string[];
17
+ ambiguous?: boolean;
18
+ };
19
+ export declare function runFineDust(options: {
20
+ regionHint?: string;
21
+ stationName?: string;
22
+ timeoutMs?: number;
23
+ }): Promise<FineDustResult | {
24
+ ok: false;
25
+ message: string;
26
+ }>;
27
+ export declare function renderFineDust(result: FineDustResult): string;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Fine dust / air quality (에어코리아) via k-skill-proxy
3
+ * Proxy endpoint: GET /v1/fine-dust/report?regionHint=서울 강남구
4
+ */
5
+ import { proxyGet } from "./proxy-client.js";
6
+ const GRADE_MAP = {
7
+ "1": "좋음",
8
+ "2": "보통",
9
+ "3": "나쁨",
10
+ "4": "매우나쁨",
11
+ good: "좋음",
12
+ normal: "보통",
13
+ bad: "나쁨",
14
+ very_bad: "매우나쁨",
15
+ };
16
+ function gradeLabel(raw) {
17
+ const s = String(raw ?? "");
18
+ return GRADE_MAP[s] ?? s;
19
+ }
20
+ export async function runFineDust(options) {
21
+ const { regionHint, stationName, timeoutMs = 15000 } = options;
22
+ const params = {};
23
+ if (stationName) {
24
+ params["stationName"] = stationName;
25
+ }
26
+ else if (regionHint) {
27
+ params["regionHint"] = regionHint;
28
+ }
29
+ else {
30
+ return { ok: false, message: "regionHint 또는 stationName이 필요합니다." };
31
+ }
32
+ const result = await proxyGet("/v1/fine-dust/report", params, timeoutMs);
33
+ if (!result.ok) {
34
+ return { ok: false, message: `Fine dust lookup failed: ${result.message}` };
35
+ }
36
+ const d = result.data;
37
+ // Ambiguous location — multiple candidates returned
38
+ if (d["ambiguous_location"] === true || d["candidate_stations"]) {
39
+ const candidates = d["candidate_stations"] ?? [];
40
+ return {
41
+ source: "fine-dust",
42
+ station: "",
43
+ region_hint: regionHint ?? stationName ?? "",
44
+ queried_at: new Date().toISOString(),
45
+ pm10: "",
46
+ pm10_grade: "",
47
+ pm25: "",
48
+ pm25_grade: "",
49
+ overall_grade: "",
50
+ retrieval_method: String(d["retrieval_method"] ?? ""),
51
+ candidate_stations: candidates,
52
+ ambiguous: true,
53
+ };
54
+ }
55
+ return {
56
+ source: "fine-dust",
57
+ station: String(d["stationName"] ?? d["station"] ?? ""),
58
+ region_hint: regionHint ?? stationName ?? "",
59
+ queried_at: String(d["dataTime"] ?? d["queried_at"] ?? new Date().toISOString()),
60
+ pm10: String(d["pm10Value"] ?? d["pm10"] ?? ""),
61
+ pm10_grade: gradeLabel(d["pm10Grade"] ?? d["pm10_grade"]),
62
+ pm25: String(d["pm25Value"] ?? d["pm25"] ?? ""),
63
+ pm25_grade: gradeLabel(d["pm25Grade"] ?? d["pm25_grade"]),
64
+ overall_grade: gradeLabel(d["khaiGrade"] ?? d["overall_grade"] ?? d["grade"]),
65
+ retrieval_method: String(d["retrieval_method"] ?? d["fallback"] ?? "proxy"),
66
+ };
67
+ }
68
+ export function renderFineDust(result) {
69
+ if (result.ambiguous) {
70
+ const lines = [`# 미세먼지 — 위치 확인 필요`, `"${result.region_hint}"에 해당하는 측정소가 여러 개입니다.`, ""];
71
+ lines.push("측정소 후보:");
72
+ for (const s of result.candidate_stations ?? [])
73
+ lines.push(`- ${s}`);
74
+ lines.push("\n`stationName` 파라미터로 위 중 하나를 지정해서 재조회하세요.");
75
+ return lines.join("\n");
76
+ }
77
+ const lines = [
78
+ `# 미세먼지 — ${result.station || result.region_hint}`,
79
+ `조회 시점: ${result.queried_at}`,
80
+ "",
81
+ `- PM10: ${result.pm10} μg/m³ (${result.pm10_grade})`,
82
+ `- PM2.5: ${result.pm25} μg/m³ (${result.pm25_grade})`,
83
+ `- 통합대기: **${result.overall_grade}**`,
84
+ `- 조회방식: ${result.retrieval_method}`,
85
+ ];
86
+ return lines.join("\n");
87
+ }
88
+ //# sourceMappingURL=fine-dust.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fine-dust.js","sourceRoot":"","sources":["../../src/korea/fine-dust.ts"],"names":[],"mappings":"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"}