Merge main into dev for PR 319

This commit is contained in:
Jeffrey (Dongkyu) Kim 2026-06-14 18:11:45 +09:00
commit e0d842435b
6 changed files with 115 additions and 7 deletions

View file

@ -1,5 +0,0 @@
---
"k-skill-proxy": patch
---
Archive unsupported Naver Map and Blue Ribbon proxy support. The proxy no longer registers `/v1/naver-map/*` or `/v1/blue-ribbon/nearby`, and the unsupported skill/package code is preserved under `legacy/` for a future revival if operational blockers are resolved.

1
.gitignore vendored
View file

@ -10,5 +10,6 @@ __pycache__/
dist/
.sisyphus/
.omo/
.gjc/
.agents/

View file

@ -1,6 +1,6 @@
---
name: korean-humanizer
description: AI가 쓴 티가 나는 한국어 글을 자연스러운 사람 글로 고친다. 번역체, AI 상투어, 과도한 명사화·피동, 3의 법칙, 과장된 의의 부여, 마무리 상투구, 챗봇 잔재, 줄표·곡선따옴표 같은 한국어 특유의 AI 흔적을 심각도(S1/S2/S3)로 분류해 잡아내고 의미는 보존하면서 다시 쓴다. 목표 글자수를 함께 주면(예: "1000자로", length=1000) 그 분량에 맞춰 늘리거나 줄인다. "AI 티 안 나게", "사람이 쓴 것처럼", "자연스럽게 다듬어줘", "번역체 고쳐줘", "어색한 거 고쳐줘", "N자로 맞춰서" 같은 요청에 사용.
description: 'AI가 쓴 티가 나는 한국어 글을 자연스러운 사람 글로 고친다. 번역체, AI 상투어, 과도한 명사화·피동, 3의 법칙, 과장된 의의 부여, 마무리 상투구, 챗봇 잔재, 줄표·곡선따옴표 같은 한국어 특유의 AI 흔적을 심각도(S1/S2/S3)로 분류해 잡아내고 의미는 보존하면서 다시 쓴다. 목표 글자수를 함께 주면(예: "1000자로", length=1000) 그 분량에 맞춰 늘리거나 줄인다. "AI 티 안 나게", "사람이 쓴 것처럼", "자연스럽게 다듬어줘", "번역체 고쳐줘", "어색한 거 고쳐줘", "N자로 맞춰서" 같은 요청에 사용.'
license: MIT
metadata:
category: writing

View file

@ -1,5 +1,11 @@
# k-skill-proxy
## 0.6.1
### Patch Changes
- Archive unsupported Naver Map and Blue Ribbon proxy support. The proxy no longer registers `/v1/naver-map/*` or `/v1/blue-ribbon/nearby`, and the unsupported skill/package code is preserved under `legacy/` for a future revival if operational blockers are resolved.
## 0.6.0
### Minor Changes

View file

@ -1,6 +1,6 @@
{
"name": "k-skill-proxy",
"version": "0.6.0",
"version": "0.6.1",
"private": true,
"description": "Fastify proxy for k-skill upstream APIs",
"license": "MIT",

View file

@ -5936,6 +5936,112 @@ test("g2b sanctioned-supplier route returns active sanctions and uses capital-S
});
test("korean-law search endpoint proxies law.go.kr with the server OC and browser headers", async (t) => {
const originalFetch = global.fetch;
let calledUrl = null;
let calledHeaders = null;
global.fetch = async (url, options) => {
calledUrl = String(url);
calledHeaders = options.headers;
return new Response(JSON.stringify({ PrecSearch: { prec: [{ 사건번호: "2023두54914" }] } }), {
status: 200,
headers: { "content-type": "application/json;charset=UTF-8" }
});
};
const app = buildServer({ env: { LAW_OC: "server-oc" } });
t.after(async () => {
global.fetch = originalFetch;
await app.close();
});
const response = await app.inject({
method: "GET",
url: "/v1/korean-law/search?target=prec&query=%EB%B6%80%EB%8B%B9%ED%95%B4%EA%B3%A0"
});
assert.equal(response.statusCode, 200);
assert.equal(response.json().PrecSearch.prec[0].사건번호, "2023두54914");
assert.equal(response.json().proxy.cache.hit, false);
assert.match(calledUrl, /\/DRF\/lawSearch\.do\?/);
assert.match(calledUrl, /OC=server-oc/);
assert.match(calledUrl, /target=prec/);
assert.ok(calledHeaders["User-Agent"].includes("Mozilla/5.0"));
assert.equal(calledHeaders.Referer, "https://www.law.go.kr/");
});
test("korean-law search endpoint caches successful upstream responses", async (t) => {
const originalFetch = global.fetch;
let fetchCalls = 0;
global.fetch = async () => {
fetchCalls += 1;
return new Response(JSON.stringify({ LawSearch: { law: [] } }), {
status: 200,
headers: { "content-type": "application/json;charset=UTF-8" }
});
};
const app = buildServer({ env: { LAW_OC: "server-oc" } });
t.after(async () => {
global.fetch = originalFetch;
await app.close();
});
const url = "/v1/korean-law/search?target=law&query=%EA%B4%80%EC%84%B8%EB%B2%95";
const first = await app.inject({ method: "GET", url });
const second = await app.inject({ method: "GET", url });
assert.equal(first.json().proxy.cache.hit, false);
assert.equal(second.json().proxy.cache.hit, true);
assert.equal(fetchCalls, 1);
});
test("korean-law detail endpoint routes to lawService.do", async (t) => {
const originalFetch = global.fetch;
let calledUrl = null;
global.fetch = async (url) => {
calledUrl = String(url);
return new Response(JSON.stringify({ PrecService: { 판례정보일련번호: "228541" } }), {
status: 200,
headers: { "content-type": "application/json;charset=UTF-8" }
});
};
const app = buildServer({ env: { LAW_OC: "server-oc" } });
t.after(async () => {
global.fetch = originalFetch;
await app.close();
});
const response = await app.inject({
method: "GET",
url: "/v1/korean-law/detail?target=prec&ID=228541"
});
assert.equal(response.statusCode, 200);
assert.match(calledUrl, /\/DRF\/lawService\.do\?/);
assert.match(calledUrl, /ID=228541/);
});
test("korean-law search endpoint returns 400 for a missing query", async (t) => {
const originalFetch = global.fetch;
let called = false;
global.fetch = async () => {
called = true;
return new Response("{}", { status: 200 });
};
const app = buildServer({ env: { LAW_OC: "server-oc" } });
t.after(async () => {
global.fetch = originalFetch;
await app.close();
});
const response = await app.inject({ method: "GET", url: "/v1/korean-law/search?target=law" });
assert.equal(response.statusCode, 400);
assert.equal(called, false);
});
test("korean-law search endpoint returns 503 when the proxy server lacks LAW_OC", async (t) => {
const app = buildServer();
t.after(async () => {