smart-web-mcp 0.9.2 → 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 +9 -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
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Food safety info (식약처/식품안전나라) via k-skill-proxy
3
+ * Endpoints: /v1/mfds/food-safety/recall, /v1/mfds/food-safety/unfit, /v1/mfds/food-safety/functional-ingredient
4
+ */
5
+ export type FoodSafetyResult = {
6
+ source: "food-safety";
7
+ action: string;
8
+ query: string;
9
+ total: number;
10
+ items: Record<string, unknown>[];
11
+ };
12
+ export declare function runFoodSafety(options: {
13
+ action: "recall" | "unfit" | "functional-ingredient";
14
+ query: string;
15
+ limit?: number;
16
+ timeoutMs?: number;
17
+ }): Promise<FoodSafetyResult | {
18
+ ok: false;
19
+ message: string;
20
+ }>;
21
+ export declare function renderFoodSafety(result: FoodSafetyResult): string;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Food safety info (식약처/식품안전나라) via k-skill-proxy
3
+ * Endpoints: /v1/mfds/food-safety/recall, /v1/mfds/food-safety/unfit, /v1/mfds/food-safety/functional-ingredient
4
+ */
5
+ import { proxyGet } from "./proxy-client.js";
6
+ export async function runFoodSafety(options) {
7
+ const { action, query, limit = 20, timeoutMs = 20000 } = options;
8
+ const pathMap = {
9
+ recall: "/v1/mfds/food-safety/recall",
10
+ unfit: "/v1/mfds/food-safety/unfit",
11
+ "functional-ingredient": "/v1/mfds/food-safety/functional-ingredient",
12
+ };
13
+ const path = pathMap[action];
14
+ if (!path)
15
+ return { ok: false, message: `Unknown action: ${action}` };
16
+ const result = await proxyGet(path, { q: query, limit: String(limit) }, timeoutMs);
17
+ if (!result.ok)
18
+ return { ok: false, message: `Food safety lookup failed: ${result.message}` };
19
+ const items = (result.data["items"] ?? result.data["list"] ?? []);
20
+ const total = typeof result.data["total"] === "number" ? result.data["total"] : items.length;
21
+ return { source: "food-safety", action, query, total, items };
22
+ }
23
+ export function renderFoodSafety(result) {
24
+ const actionLabel = {
25
+ recall: "회수·판매중지",
26
+ unfit: "검사부적합",
27
+ "functional-ingredient": "기능성 원료 인정현황",
28
+ };
29
+ const lines = [
30
+ "⚠️ **응급 증상(혈변·탈수·호흡곤란·의식저하)은 즉시 119.**",
31
+ "",
32
+ `# 식품 안전 정보 — ${actionLabel[result.action] ?? result.action}`,
33
+ `검색어: "${result.query}" | 총 ${result.total}건`,
34
+ "",
35
+ ];
36
+ if (result.items.length === 0) {
37
+ lines.push("조회 결과가 없습니다.");
38
+ return lines.join("\n");
39
+ }
40
+ for (const item of result.items.slice(0, 20)) {
41
+ const name = String(item["prdlst_nm"] ?? item["item_name"] ?? item["name"] ?? item["PRDUCT_NM"] ?? "?");
42
+ const maker = String(item["bssh_nm"] ?? item["entp_name"] ?? item["ENTP_NM"] ?? "");
43
+ const reason = String(item["recalls_reason"] ?? item["unfit_reason"] ?? item["reason"] ?? item["RECALL_REASON"] ?? "");
44
+ const date = String(item["recalls_dt"] ?? item["dt"] ?? item["DATE"] ?? "");
45
+ lines.push(`- **${name}**${maker ? ` (${maker})` : ""}${reason ? ` — ${reason}` : ""}${date ? ` [${date}]` : ""}`);
46
+ }
47
+ lines.push("\n_식약처/식품안전나라 공식 데이터 기준_");
48
+ return lines.join("\n");
49
+ }
50
+ //# sourceMappingURL=food-safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"food-safety.js","sourceRoot":"","sources":["../../src/korea/food-safety.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * GeekNews (news.hada.io) — public RSS/Atom feed
3
+ * Feed: https://feeds.feedburner.com/geeknews-feed
4
+ */
5
+ export type GeeknewsItem = {
6
+ id: string;
7
+ title: string;
8
+ link: string;
9
+ author: string;
10
+ published: string;
11
+ summary: string;
12
+ };
13
+ export type GeeknewsResult = {
14
+ source: "geeknews";
15
+ query: string | null;
16
+ limit: number;
17
+ total: number;
18
+ items: GeeknewsItem[];
19
+ feed_url: string;
20
+ };
21
+ export declare function runGeeknews(options: {
22
+ action?: "list" | "search" | "detail";
23
+ query?: string;
24
+ id?: string;
25
+ limit?: number;
26
+ timeoutMs?: number;
27
+ }): Promise<GeeknewsResult | {
28
+ ok: false;
29
+ message: string;
30
+ }>;
31
+ export declare function renderGeeknews(result: GeeknewsResult): string;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * GeekNews (news.hada.io) — public RSS/Atom feed
3
+ * Feed: https://feeds.feedburner.com/geeknews-feed
4
+ */
5
+ import { httpGetText } from "./proxy-client.js";
6
+ const GEEKNEWS_FEED = "https://feeds.feedburner.com/geeknews-feed";
7
+ const GEEKNEWS_HOME = "https://news.hada.io";
8
+ function stripHtml(html) {
9
+ return html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
10
+ }
11
+ function decodeXmlEntities(text) {
12
+ return text
13
+ .replace(/&amp;/g, "&")
14
+ .replace(/&lt;/g, "<")
15
+ .replace(/&gt;/g, ">")
16
+ .replace(/&quot;/g, '"')
17
+ .replace(/&#39;/g, "'")
18
+ .replace(/&apos;/g, "'")
19
+ .replace(/&nbsp;/g, " ")
20
+ .replace(/&#(\d+);/g, (_m, n) => String.fromCharCode(parseInt(n, 10)));
21
+ }
22
+ function extractXml(text, tag) {
23
+ const match = text.match(new RegExp(`<${tag}(?:[^>]*)>([\\s\\S]*?)<\\/${tag}>`, "i"));
24
+ return match ? decodeXmlEntities(stripHtml(match[1] || "")).trim() : "";
25
+ }
26
+ function extractCdata(text, tag) {
27
+ const match = text.match(new RegExp(`<${tag}[^>]*>(?:<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>|([\\s\\S]*?))<\\/${tag}>`, "i"));
28
+ const raw = match?.[1] ?? match?.[2] ?? "";
29
+ return decodeXmlEntities(stripHtml(raw)).trim();
30
+ }
31
+ function extractLink(block) {
32
+ const atomLink = block.match(/<link[^>]+href=["']([^"']+)["']/i)?.[1];
33
+ if (atomLink)
34
+ return atomLink.trim();
35
+ const rssLink = extractXml(block, "link");
36
+ if (rssLink)
37
+ return rssLink.trim();
38
+ return "";
39
+ }
40
+ function extractId(block) {
41
+ const guid = extractXml(block, "guid");
42
+ if (guid)
43
+ return guid;
44
+ const id = extractXml(block, "id");
45
+ if (id)
46
+ return id;
47
+ return extractLink(block);
48
+ }
49
+ function parseItems(feedXml) {
50
+ const items = [];
51
+ const blockPattern = /<(?:item|entry)\b[^>]*>([\s\S]*?)<\/(?:item|entry)>/gi;
52
+ for (const blockMatch of feedXml.matchAll(blockPattern)) {
53
+ const block = blockMatch[1] || "";
54
+ const title = extractCdata(block, "title") || extractXml(block, "title");
55
+ const link = extractLink(block);
56
+ const author = extractCdata(block, "author") || extractXml(block, "author") || extractXml(block, "dc:creator") || "GeekNews";
57
+ const published = extractXml(block, "pubDate") || extractXml(block, "published") || extractXml(block, "updated") || "";
58
+ const summary = extractCdata(block, "description") || extractCdata(block, "summary") || extractXml(block, "description") || extractXml(block, "summary") || "";
59
+ const id = extractId(block);
60
+ if (title || link) {
61
+ items.push({
62
+ id: id || link,
63
+ title,
64
+ link: link || GEEKNEWS_HOME,
65
+ author,
66
+ published,
67
+ summary: summary.slice(0, 1000),
68
+ });
69
+ }
70
+ }
71
+ return items;
72
+ }
73
+ function matchesQuery(item, query) {
74
+ const q = query.toLowerCase();
75
+ return (item.title.toLowerCase().includes(q) ||
76
+ item.summary.toLowerCase().includes(q) ||
77
+ item.author.toLowerCase().includes(q) ||
78
+ item.link.toLowerCase().includes(q) ||
79
+ item.id.toLowerCase().includes(q));
80
+ }
81
+ export async function runGeeknews(options) {
82
+ const { action = "list", query, id, limit = 20, timeoutMs = 15000 } = options;
83
+ const feedResult = await httpGetText(GEEKNEWS_FEED, {
84
+ accept: "application/rss+xml, application/atom+xml, text/xml, */*",
85
+ }, timeoutMs);
86
+ if (!feedResult.ok) {
87
+ return { ok: false, message: `Failed to fetch GeekNews feed: ${feedResult.message}` };
88
+ }
89
+ const allItems = parseItems(feedResult.data);
90
+ if (action === "detail" && id) {
91
+ const found = allItems.find((item) => item.id === id ||
92
+ item.link === id ||
93
+ item.id.includes(id) ||
94
+ item.link.includes(id));
95
+ const matched = found ? [found] : [];
96
+ return {
97
+ source: "geeknews",
98
+ query: id,
99
+ limit: 1,
100
+ total: matched.length,
101
+ items: matched,
102
+ feed_url: GEEKNEWS_FEED,
103
+ };
104
+ }
105
+ if (action === "search" && query) {
106
+ const filtered = allItems.filter((item) => matchesQuery(item, query)).slice(0, limit);
107
+ return {
108
+ source: "geeknews",
109
+ query,
110
+ limit,
111
+ total: filtered.length,
112
+ items: filtered,
113
+ feed_url: GEEKNEWS_FEED,
114
+ };
115
+ }
116
+ // list
117
+ return {
118
+ source: "geeknews",
119
+ query: null,
120
+ limit,
121
+ total: allItems.length,
122
+ items: allItems.slice(0, limit),
123
+ feed_url: GEEKNEWS_FEED,
124
+ };
125
+ }
126
+ export function renderGeeknews(result) {
127
+ const lines = [`# GeekNews (${result.total} items)`];
128
+ if (result.query)
129
+ lines.push(`Query: ${result.query}`);
130
+ lines.push("");
131
+ for (const item of result.items) {
132
+ lines.push(`## ${item.title}`);
133
+ lines.push(`- Link: ${item.link}`);
134
+ if (item.author && item.author !== "GeekNews")
135
+ lines.push(`- Author: ${item.author}`);
136
+ if (item.published)
137
+ lines.push(`- Published: ${item.published}`);
138
+ if (item.summary)
139
+ lines.push(`\n${item.summary}`);
140
+ lines.push("");
141
+ }
142
+ return lines.join("\n");
143
+ }
144
+ //# sourceMappingURL=geeknews.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geeknews.js","sourceRoot":"","sources":["../../src/korea/geeknews.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export { runGeeknews, renderGeeknews } from "./geeknews.js";
2
+ export { runSubway, renderSubway } from "./subway.js";
3
+ export { runWeather, renderWeather } from "./weather.js";
4
+ export { runFineDust, renderFineDust } from "./fine-dust.js";
5
+ export { runStock, renderStock } from "./stock.js";
6
+ export { runDart, renderDart } from "./dart.js";
7
+ export { runRealEstate, renderRealEstate } from "./real-estate.js";
8
+ export { runDrugSafety, renderDrugSafety } from "./drug-safety.js";
9
+ export { runFoodSafety, renderFoodSafety } from "./food-safety.js";
10
+ export { runNaverNews, renderNaverNews } from "./naver-news.js";
11
+ export { runNaverShopping, renderNaverShopping } from "./naver-shopping.js";
12
+ export { runCoupang, renderCoupang } from "./coupang.js";
13
+ export { runSpellCheck, renderSpellCheck } from "./spellcheck.js";
14
+ export { runZipcode, renderZipcode } from "./zipcode.js";
15
+ export { runLaw, renderLaw } from "./law.js";
16
+ export { runPublicRestroom, renderPublicRestroom } from "./public-restroom.js";
@@ -0,0 +1,17 @@
1
+ export { runGeeknews, renderGeeknews } from "./geeknews.js";
2
+ export { runSubway, renderSubway } from "./subway.js";
3
+ export { runWeather, renderWeather } from "./weather.js";
4
+ export { runFineDust, renderFineDust } from "./fine-dust.js";
5
+ export { runStock, renderStock } from "./stock.js";
6
+ export { runDart, renderDart } from "./dart.js";
7
+ export { runRealEstate, renderRealEstate } from "./real-estate.js";
8
+ export { runDrugSafety, renderDrugSafety } from "./drug-safety.js";
9
+ export { runFoodSafety, renderFoodSafety } from "./food-safety.js";
10
+ export { runNaverNews, renderNaverNews } from "./naver-news.js";
11
+ export { runNaverShopping, renderNaverShopping } from "./naver-shopping.js";
12
+ export { runCoupang, renderCoupang } from "./coupang.js";
13
+ export { runSpellCheck, renderSpellCheck } from "./spellcheck.js";
14
+ export { runZipcode, renderZipcode } from "./zipcode.js";
15
+ export { runLaw, renderLaw } from "./law.js";
16
+ export { runPublicRestroom, renderPublicRestroom } from "./public-restroom.js";
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/korea/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC3E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Korean law search via 법망 (Beopmang) public REST API
3
+ * Primary: https://api.beopmang.org/api/v4/law
4
+ * Also supports korean-law-mcp remote endpoint as alternative base
5
+ */
6
+ export type LawItem = {
7
+ law_id: string;
8
+ name: string;
9
+ abbr?: string;
10
+ promulgated_at?: string;
11
+ effective_at?: string;
12
+ ministry?: string;
13
+ snippet?: string;
14
+ };
15
+ export type LawArticle = {
16
+ law_id: string;
17
+ law_name: string;
18
+ article: string;
19
+ content: string;
20
+ };
21
+ export type LawSearchResult = {
22
+ source: "korean-law";
23
+ action: "search" | "get-text" | "search-precedents";
24
+ query: string;
25
+ total: number;
26
+ items?: LawItem[];
27
+ article?: LawArticle;
28
+ precedents?: Record<string, unknown>[];
29
+ };
30
+ export declare function runLaw(options: {
31
+ action: "search" | "get-text" | "search-precedents";
32
+ query?: string;
33
+ law_id?: string;
34
+ article?: string;
35
+ limit?: number;
36
+ timeoutMs?: number;
37
+ }): Promise<LawSearchResult | {
38
+ ok: false;
39
+ message: string;
40
+ }>;
41
+ export declare function renderLaw(result: LawSearchResult): string;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Korean law search via 법망 (Beopmang) public REST API
3
+ * Primary: https://api.beopmang.org/api/v4/law
4
+ * Also supports korean-law-mcp remote endpoint as alternative base
5
+ */
6
+ import { httpGet } from "./proxy-client.js";
7
+ const BEOPMANG_BASE = "https://api.beopmang.org/api/v4";
8
+ export async function runLaw(options) {
9
+ const { action, query, law_id, article, limit = 10, timeoutMs = 20000 } = options;
10
+ if (action === "search") {
11
+ if (!query)
12
+ return { ok: false, message: "검색어(query)가 필요합니다." };
13
+ const url = `${BEOPMANG_BASE}/law?action=search&q=${encodeURIComponent(query)}&limit=${limit}`;
14
+ const result = await httpGet(url, {}, timeoutMs);
15
+ if (!result.ok)
16
+ return { ok: false, message: `Law search failed: ${result.message}` };
17
+ const items = (result.data["laws"] ?? result.data["items"] ?? result.data["results"] ?? [])
18
+ .map((item) => ({
19
+ law_id: String(item["law_id"] ?? item["id"] ?? ""),
20
+ name: String(item["name"] ?? item["law_name"] ?? ""),
21
+ abbr: item["abbr"] ? String(item["abbr"]) : undefined,
22
+ promulgated_at: item["promulgated_at"] ? String(item["promulgated_at"]) : undefined,
23
+ ministry: item["ministry"] ? String(item["ministry"]) : undefined,
24
+ snippet: item["snippet"] ? String(item["snippet"]) : undefined,
25
+ }));
26
+ return { source: "korean-law", action: "search", query, total: items.length, items };
27
+ }
28
+ if (action === "get-text") {
29
+ if (!law_id)
30
+ return { ok: false, message: "law_id가 필요합니다. 먼저 search로 법령을 찾으세요." };
31
+ const params = new URLSearchParams({ action: "get", law_id });
32
+ if (article)
33
+ params.set("article", article);
34
+ const url = `${BEOPMANG_BASE}/law?${params.toString()}`;
35
+ const result = await httpGet(url, {}, timeoutMs);
36
+ if (!result.ok)
37
+ return { ok: false, message: `Law text lookup failed: ${result.message}` };
38
+ const d = result.data;
39
+ const artObj = {
40
+ law_id,
41
+ law_name: String(d["law_name"] ?? d["name"] ?? ""),
42
+ article: String(d["article"] ?? article ?? "전문"),
43
+ content: String(d["content"] ?? d["text"] ?? ""),
44
+ };
45
+ return { source: "korean-law", action: "get-text", query: article ?? "전문", total: 1, article: artObj };
46
+ }
47
+ // search-precedents
48
+ if (!query)
49
+ return { ok: false, message: "검색어(query)가 필요합니다." };
50
+ const url = `${BEOPMANG_BASE}/tools?action=search_precedents&q=${encodeURIComponent(query)}&limit=${limit}`;
51
+ const result = await httpGet(url, {}, timeoutMs);
52
+ if (!result.ok)
53
+ return { ok: false, message: `Precedent search failed: ${result.message}` };
54
+ const precedents = (result.data["precedents"] ?? result.data["items"] ?? []);
55
+ return { source: "korean-law", action: "search-precedents", query, total: precedents.length, precedents };
56
+ }
57
+ export function renderLaw(result) {
58
+ if (result.action === "search") {
59
+ const lines = [`# 법령 검색 — "${result.query}"`, `${result.total}건`, ""];
60
+ for (const item of result.items ?? []) {
61
+ lines.push(`- **${item.name}**${item.abbr ? ` (${item.abbr})` : ""}${item.law_id ? ` [ID: ${item.law_id}]` : ""}`);
62
+ if (item.ministry)
63
+ lines.push(` 소관: ${item.ministry}`);
64
+ if (item.snippet)
65
+ lines.push(` ${item.snippet}`);
66
+ }
67
+ lines.push("\n_법망(api.beopmang.org) / 법제처 공식 데이터 기준_");
68
+ return lines.join("\n");
69
+ }
70
+ if (result.action === "get-text" && result.article) {
71
+ const a = result.article;
72
+ return [`# ${a.law_name} ${a.article}`, "", a.content, "", "_법망(api.beopmang.org) 기준. 법률 자문이 아닙니다._"].join("\n");
73
+ }
74
+ // precedents
75
+ const lines = [`# 판례 검색 — "${result.query}"`, `${result.total}건`, ""];
76
+ for (const p of result.precedents ?? []) {
77
+ const title = String(p["title"] ?? p["case_name"] ?? p["name"] ?? "");
78
+ const court = String(p["court"] ?? "");
79
+ const date = String(p["date"] ?? p["judgment_date"] ?? "");
80
+ lines.push(`- **${title}** ${court} ${date}`);
81
+ }
82
+ lines.push("\n_법망(api.beopmang.org) / 법제처 공식 데이터 기준_");
83
+ return lines.join("\n");
84
+ }
85
+ //# sourceMappingURL=law.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"law.js","sourceRoot":"","sources":["../../src/korea/law.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Naver News search via k-skill-proxy
3
+ * Endpoint: GET /v1/naver-news/search?q=검색어&display=10&sort=date
4
+ */
5
+ export type NaverNewsItem = {
6
+ title: string;
7
+ description: string;
8
+ link: string;
9
+ original_link: string | null;
10
+ pub_date: string;
11
+ pub_date_iso: string | null;
12
+ };
13
+ export type NaverNewsMeta = {
14
+ extraction: string;
15
+ total: number;
16
+ start: number;
17
+ display: number;
18
+ last_build_date: string;
19
+ sort: string;
20
+ };
21
+ export type NaverNewsResult = {
22
+ source: "naver-news";
23
+ query: string;
24
+ sort: string;
25
+ items: NaverNewsItem[];
26
+ meta: NaverNewsMeta;
27
+ };
28
+ export declare function runNaverNews(options: {
29
+ query: string;
30
+ display?: number;
31
+ start?: number;
32
+ sort?: "sim" | "date";
33
+ timeoutMs?: number;
34
+ }): Promise<NaverNewsResult | {
35
+ ok: false;
36
+ message: string;
37
+ }>;
38
+ export declare function renderNaverNews(result: NaverNewsResult): string;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Naver News search via k-skill-proxy
3
+ * Endpoint: GET /v1/naver-news/search?q=검색어&display=10&sort=date
4
+ */
5
+ import { proxyGet } from "./proxy-client.js";
6
+ export async function runNaverNews(options) {
7
+ const { query, display = 10, start = 1, sort = "date", timeoutMs = 15000 } = options;
8
+ if (!query || query.length < 2)
9
+ return { ok: false, message: "검색어는 2글자 이상이어야 합니다." };
10
+ if (start + display - 1 > 1000)
11
+ return { ok: false, message: "start + display - 1은 1000을 초과할 수 없습니다." };
12
+ const result = await proxyGet("/v1/naver-news/search", {
13
+ q: query,
14
+ display: String(display),
15
+ start: String(start),
16
+ sort,
17
+ }, timeoutMs);
18
+ if (!result.ok)
19
+ return { ok: false, message: `Naver News search failed: ${result.message}` };
20
+ const d = result.data;
21
+ const items = (d["items"] ?? []);
22
+ const meta = (d["meta"] ?? {
23
+ extraction: "naver-openapi",
24
+ total: 0,
25
+ start,
26
+ display,
27
+ last_build_date: "",
28
+ sort,
29
+ });
30
+ return { source: "naver-news", query, sort, items, meta };
31
+ }
32
+ function formatPubDate(iso, raw) {
33
+ if (!iso)
34
+ return raw;
35
+ try {
36
+ const d = new Date(iso);
37
+ const kst = new Date(d.getTime() + 9 * 60 * 60 * 1000);
38
+ return kst.toISOString().slice(0, 16).replace("T", " ") + " KST";
39
+ }
40
+ catch {
41
+ return raw;
42
+ }
43
+ }
44
+ export function renderNaverNews(result) {
45
+ const lines = [
46
+ `# 네이버 뉴스 — "${result.query}"`,
47
+ `정렬: ${result.sort === "date" ? "최신순" : "유사도순"} | ${result.meta.total.toLocaleString("ko")}건 중 ${result.items.length}건`,
48
+ "",
49
+ ];
50
+ if (result.items.length === 0) {
51
+ lines.push("검색 결과가 없습니다.");
52
+ return lines.join("\n");
53
+ }
54
+ for (const item of result.items) {
55
+ const url = item.original_link || item.link;
56
+ const date = formatPubDate(item.pub_date_iso, item.pub_date);
57
+ lines.push(`## ${item.title}`);
58
+ lines.push(`${date}`);
59
+ if (item.description)
60
+ lines.push(`\n${item.description}`);
61
+ lines.push(`\n[원문 보기](${url})`);
62
+ lines.push("");
63
+ }
64
+ lines.push("_기사 요약에 따르면 — 네이버 뉴스 검색 API 기준_");
65
+ return lines.join("\n");
66
+ }
67
+ //# sourceMappingURL=naver-news.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naver-news.js","sourceRoot":"","sources":["../../src/korea/naver-news.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Naver Shopping price comparison via k-skill-proxy
3
+ * Endpoint: GET /v1/naver-shopping/search?q=에어팟&limit=10&sort=rel
4
+ */
5
+ export type NaverShoppingItem = {
6
+ title: string;
7
+ price: number | null;
8
+ price_text: string;
9
+ mall_name: string;
10
+ url: string;
11
+ image_url?: string;
12
+ review_count?: number;
13
+ purchase_count?: number;
14
+ score?: number;
15
+ };
16
+ export type NaverShoppingMeta = {
17
+ extraction: string;
18
+ sort_applied: string;
19
+ upstream_sort?: string;
20
+ total?: number;
21
+ };
22
+ export type NaverShoppingResult = {
23
+ source: "naver-shopping";
24
+ query: string;
25
+ sort: string;
26
+ items: NaverShoppingItem[];
27
+ meta: NaverShoppingMeta;
28
+ };
29
+ export declare function runNaverShopping(options: {
30
+ query: string;
31
+ limit?: number;
32
+ page?: number;
33
+ sort?: "rel" | "date" | "price_asc" | "price_dsc" | "review";
34
+ timeoutMs?: number;
35
+ }): Promise<NaverShoppingResult | {
36
+ ok: false;
37
+ message: string;
38
+ }>;
39
+ export declare function renderNaverShopping(result: NaverShoppingResult): string;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Naver Shopping price comparison via k-skill-proxy
3
+ * Endpoint: GET /v1/naver-shopping/search?q=에어팟&limit=10&sort=rel
4
+ */
5
+ import { proxyGet } from "./proxy-client.js";
6
+ export async function runNaverShopping(options) {
7
+ const { query, limit = 10, page = 1, sort = "rel", timeoutMs = 15000 } = options;
8
+ if (!query || query.length < 2)
9
+ return { ok: false, message: "검색어는 2글자 이상이어야 합니다." };
10
+ const result = await proxyGet("/v1/naver-shopping/search", {
11
+ q: query,
12
+ limit: String(Math.min(limit, 40)),
13
+ page: String(page),
14
+ sort,
15
+ }, timeoutMs);
16
+ if (!result.ok)
17
+ return { ok: false, message: `Naver Shopping search failed: ${result.message}` };
18
+ const d = result.data;
19
+ const items = (d["items"] ?? []);
20
+ const meta = (d["meta"] ?? { extraction: "unknown", sort_applied: "unknown" });
21
+ return { source: "naver-shopping", query, sort, items, meta };
22
+ }
23
+ export function renderNaverShopping(result) {
24
+ const lines = [
25
+ `# 네이버 쇼핑 — "${result.query}"`,
26
+ `정렬: ${result.sort} | 조회 시점 노출가 기준 (배송비·쿠폰 별도)`,
27
+ "",
28
+ ];
29
+ if (result.items.length === 0) {
30
+ lines.push("검색 결과가 없습니다.");
31
+ return lines.join("\n");
32
+ }
33
+ // Sort by price asc for display
34
+ const sorted = [...result.items].sort((a, b) => (a.price ?? Infinity) - (b.price ?? Infinity));
35
+ for (const [i, item] of sorted.entries()) {
36
+ const price = item.price !== null ? `${item.price.toLocaleString("ko")}원` : item.price_text || "가격 미표시";
37
+ lines.push(`${i + 1}. **${item.title}**`);
38
+ lines.push(` - 판매처: ${item.mall_name}`);
39
+ lines.push(` - 가격: ${price}`);
40
+ if (item.review_count !== undefined)
41
+ lines.push(` - 리뷰: ${item.review_count.toLocaleString("ko")}개`);
42
+ lines.push(` - [보러가기](${item.url})`);
43
+ lines.push("");
44
+ }
45
+ if (result.meta.sort_applied === "unsupported") {
46
+ lines.push(`_정렬 방식 '${result.sort}'은 이 경로에서 지원되지 않아 ${result.meta.upstream_sort ?? "rel"}로 조회됨_`);
47
+ }
48
+ lines.push("_조회 시점 기준 / 배송비·쿠폰·회원 혜택 미반영_");
49
+ return lines.join("\n");
50
+ }
51
+ //# sourceMappingURL=naver-shopping.js.map