454 Commits

Author SHA1 Message Date
Jeffrey (Dongkyu) Kim dd88f56d35 Merge remote-tracking branch 'origin/dev' into dev-issue-331-d2b
# Conflicts:
#	package-lock.json
#	package.json
2026-07-02 15:17:10 +09:00
Jeffrey (Dongkyu) Kim c85a214f15 Merge pull request #358 from NomaDamas/dev-issue-336-payment-order
Add court payment order assistant skill
2026-07-02 15:09:52 +09:00
Cheol-H-Jeong b0b788987b Add Popbill all-service skill 2026-07-02 08:49:48 +09:00
Jeffrey (Dongkyu) Kim 1a317f5d35 Add court payment order assistant skill 2026-07-02 01:29:50 +09:00
Jeffrey (Dongkyu) Kim 9f2949eb34 Add D2B notice search skill 2026-07-02 00:57:11 +09:00
Jeffrey (Dongkyu) Kim 96a7f7751c Add S2B notice search skill 2026-07-01 23:25:13 +09:00
semteo04 3f8fa9ecce feat: yebigun-training 스킬 추가 (예비군 훈련정보 조회 & 작년 대비 비교)
로그인된 예비군 홈페이지(yebigun1.mil.kr) Chrome 세션을 재사용해 훈련 일정/장소를
조회하고 작년 기록과 비교한다. 식별 정보 없는 조회 화면만 읽고(view), 신청/편집
화면은 열기만 하며(open-menu) 로그인·제출은 절대 자동화하지 않는다.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 20:15:36 +09:00
Jeffrey (Dongkyu) Kim face06274e Add naming-house skill 2026-06-29 22:01:01 +09:00
Jeffrey (Dongkyu) Kim 0d9ac65eee Merge pull request #347 from NomaDamas/dev
Promote dev to main
2026-06-26 10:00:40 +09:00
Jeffrey (Dongkyu) Kim db8117491b Add missing README skill entries 2026-06-25 22:15:06 +09:00
Jeffrey (Dongkyu) Kim 9e89f682cc Migrate k-skill-proxy deploy to gpu01 cron 2026-06-25 22:04:42 +09:00
Jeffrey (Dongkyu) Kim 441ffbd592 Merge remote-tracking branch 'origin/dev' into pr-341-work
# Conflicts:
#	package.json
2026-06-25 16:31:31 +09:00
Jeffrey (Dongkyu) Kim cd73d45c05 Merge remote-tracking branch 'origin/dev' into pr-334-work
# Conflicts:
#	package.json
2026-06-25 16:18:33 +09:00
Jeffrey (Dongkyu) Kim 172beb3b78 Add G2B order plan search skill 2026-06-24 23:54:29 +09:00
Jeffrey (Dongkyu) Kim 2dd20c2fbd Merge dev into lovebug report 2026-06-24 23:22:12 +09:00
wbjung 46d64ff0c8 Add resume-based job posting match skill 2026-06-24 21:22:02 +09:00
Jeffrey (Dongkyu) Kim 451d557a6b fix(daangn-realty-search): harden relay-store helper 2026-06-24 17:33:04 +09:00
Jeffrey (Dongkyu) Kim 55866b15a3 Add lovebug report skill 2026-06-24 17:29:21 +09:00
wbjung c619d3b7c7 Add recruiting talent search skills 2026-06-17 23:14:54 +09:00
Jeffrey (Dongkyu) Kim c3f44eef14 feat(kakaotalk-mac): replace kakaocli workflow with katok
Closes #320

Plan: .omo/plans/issue-320-katok-skill.md
2026-06-16 13:44:56 +09:00
Jeffrey (Dongkyu) Kim c8bb7f9f35 Merge dev and address PR review fixes 2026-06-12 19:34:20 +09:00
Jeffrey (Dongkyu) Kim f485591ac2 feat(k-skill-proxy): fold Korean law lookups into k-skill-proxy, drop Beopmang (#315)
Add hosted korean-law proxy routes and make the korean-law-search skill
proxy-first, removing the unstable Beopmang fallback from the support list.

- proxy: new src/korean-law.js wrapping official 법제처 DRF lawSearch.do /
  lawService.do, injecting LAW_OC + browser User-Agent/Referer (the real
  cause of "사용자 정보 검증 실패") and retrying empty/HTML responses.
- proxy: /v1/korean-law/search and /v1/korean-law/detail routes + lawOc
  config + koreanLawConfigured health flag; 17 module + 6 route tests.
- skill/docs: korean-law-search becomes proxy-first (no per-user LAW_OC,
  no local CLI). Drop Beopmang everywhere; credit chrisryugj/korean-law-mcp
  as design reference and 법제처 open.law.go.kr as official source.
- ops: LAW_OC added to deploy doc KEYS, secret accessor loop, and the
  Cloud Run deploy workflow set-secrets.
- changeset: k-skill-proxy minor.
2026-06-12 18:07:03 +09:00
John 440cd697a7 feat: 사업자 실사 스킬군 — 단품 5종 + 복합 1종, proxy route 3개 추가 (#316)
사업자등록번호로 "이 사업자 실제 문제 없나"를 무료 공공 데이터로 교차 조회하는
스킬군을 기여한다. 점수·등급·"위험" 라벨 없이 사실+출처+조회시각만 병렬한다.

단품 스킬:
- national-pension-workplace  국민연금 가입 사업장 (proxy, 3046071)
- nts-tax-delinquency         국세 체납 명단공개 (무인증 직접)
- fsc-corporate-info          금융위 기업기본정보 (proxy, 15043184)
- g2b-sanctioned-supplier     조달청 부정당제재 (proxy, 15129466)
- localdata-business-status   지방행정 인허가 영업상태 208업종 (무인증 직접)

복합 스킬:
- biz-health-check  위 5종 + 기존 nts-business-registration을 한 번에 호출

proxy(packages/k-skill-proxy):
- keyed route 3개 추가 — 키는 서버의 DATA_GO_KR_API_KEY로만 주입(사용자 시크릿 없음)
- 연금 route는 basic+detail+monthly 3콜 오케스트레이션 + 월별중복 dedup
- server.test.js에 route 테스트 10건 추가 (정상/503 미설정/400/403 forbidden)

무인증 스킬은 stdlib(urllib)만 사용해 의존성 없이 직접 호출한다.
문서: docs/features ×6, README 표·링크, docs/sources.md 갱신, plugin.json 재생성.

활용신청(프록시 운영 서버 등록 필요): 3046071·15043184·15129466
(15081808 국세청 상태조회는 nts-business-registration용으로 이미 등록, 키 공유).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 16:46:30 +09:00
Jeffrey (Dongkyu) Kim b6200892e3 Revert "docs(korean-law-search): document official precedent API evidence (#313)"
This reverts commit 5faec8bb2a.
2026-06-11 11:45:04 +09:00
Jeffrey (Dongkyu) Kim 79f6038328 feat(toss-securities): add official read-only OpenAPI client (#312)
Add an official Toss Securities Open API client alongside the existing
unofficial tossctl wrapper. The package ships read-only helpers backed by
the official REST API (https://openapi.tossinvest.com): OAuth2
client_credentials token issuance with an in-memory token cache, bearer +
X-Tossinvest-Account header handling, TossApiError/TossCredentialsError
with secret/token redaction, and 429 Retry-After/backoff retry.

Credentials are read from TOSSINVEST_CLIENT_ID/TOSSINVEST_CLIENT_SECRET
(optional TOSSINVEST_ACCOUNT/TOSSINVEST_API_BASE_URL) and sent directly to
Toss, never through a shared proxy. Order mutation remains out of scope;
the tossctl path is retained as a documented fallback.

Closes #306
2026-06-10 22:50:47 +09:00
Jeffrey (Dongkyu) Kim 5faec8bb2a docs(korean-law-search): document official precedent API evidence (#313)
Enhance the existing korean-law-search skill and feature doc with the
official 법제처 Open API precedent endpoints and detail retrieval, without
adding a new skill, package, workspace, or changeset.

- Document 판례 목록 조회 (lawSearch.do?target=prec) and 판례 본문 조회
  (lawService.do?target=prec&ID=...) as official evidence behind the
  korean-law-mcp search_precedents/get_precedent_text path.
- Add supported precedent filters (query, court, case number, source
  name, date, sort) and precedent-specific failure modes (missing LAW_OC,
  upstream unavailable/rate-limit/timeout, empty results, body
  unavailable for some sources) plus the legal-advice boundary.
- Keep korean-law-mcp first and Beopmang as the only post-failure
  fallback; lawService.do?target=prec is official detail retrieval, not a
  Beopmang-style fallback.
- Extend the skill-docs regression test with stable endpoint/tool
  literals and concept-level filter/failure-mode/legal-boundary checks.

Closes #308
2026-06-10 22:50:34 +09:00
Jeffrey (Dongkyu) Kim e25f8dd9ab feat(korean-humanizer): rebuild v2 on im-not-ai framework
Build on happy-nut's PR #311 korean-humanizer skill (cherry-picked,
authorship preserved) by re-centering it on the epoko77-ai/im-not-ai
(Humanize KR, MIT) methodology:

- 4대 철칙 (의미 불변 · 근거 기반 · 장르 유지 · 과윤문 금지 30%/50% 가드)
- S1/S2/S3 severity tiers and A~D quality grades
- A~J taxonomy with Korean-specific patterns (A-16 그/그녀 강박,
  A-18 관계절 좌향 수식, A-19 이중 조사, C-11 연결어미 뒤 쉼표, E-7 경어법)
- detect -> rewrite -> audit -> grade loop with self-check checklist
- references/ai-tell-taxonomy.md full A~J table
- docs/features/korean-humanizer.md crediting im-not-ai and happy-nut
- README row + link, regenerated plugin.json, docs regression test

Co-authored-by: happy-nut <happynut.dev@gmail.com>
2026-06-10 14:32:44 +09:00
iamiks 52dbfee064 feat(srt-booking): SRT 좌석 확인과 탐색 우선순위 개선 (#305)
* feat(srt): 좌석 조회와 탐색 우선순위 추가

SRT search 결과의 stable train_id로 객차별 좌석을 조회하고, 특정 호차/좌석 확인과 탐색 우선순위 옵션을 제공한다.

Constraint: SRT와 KTX는 별도 upstream 표면이므로 SRT HTML 파서와 테스트를 분리함
Rejected: KTX 좌석 helper 공유 | Korail API와 SRT 웹 좌석선택 HTML 계약이 달라 혼용하면 파서 안정성이 낮아짐
Confidence: medium
Scope-risk: moderate
Directive: SRT 좌석선택 HTML에서 노출되지 않는 속성은 추정하지 말고 명시적으로 처리할 것
Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_srt_booking scripts.test_ktx_booking; python3 -m py_compile scripts/srt_booking.py scripts/srt_seats.py scripts/test_srt_booking.py
Not-tested: 실제 예약 API에 우선순위 좌석 선택을 연결하는 흐름

* fix(srt): 좌석 조회 JSON 출력 안정화

SRT 대기열 메시지가 stdout에 섞여 seats JSON을 깨는 실제 표면 문제를 막고, 누락된 좌석 방향/위치 속성을 unknown으로 정규화한다.

Constraint: issue #303 범위는 예약 부작용이 없는 좌석 조회 보조 흐름으로 제한됨
Rejected: 실제 예약 subcommand 추가 | 좌석 선점/예약은 외부 부작용이라 이번 acceptance criteria에 포함되지 않음
Confidence: high
Scope-risk: narrow
Directive: SRTrain upstream 출력이 추가되더라도 helper stdout은 JSON 전용으로 유지할 것
Tested: RED→GREEN in .omo/ulw-loop/evidence/srt-c002-red-green-tests.txt; live SRT tmux QA in .omo/ulw-loop/evidence/srt-c001-live-search-seats.txt; npm run ci in .omo/ulw-loop/evidence/srt-c003-regression-ci.txt
Not-tested: 실제 예약/결제/취소 부작용 흐름

* test(srt): split seat helper regression coverage

---------

Co-authored-by: Jeffrey (Dongkyu) Kim <vkehfdl1@gmail.com>
2026-06-09 10:57:54 +09:00
Jeffrey (Dongkyu) Kim bbba283151 Archive unsupported map skills 2026-06-05 22:24:15 +09:00
Jeffrey (Dongkyu) Kim 46f44ed724 chore: remove startup-support skill 2026-06-05 17:21:58 +09:00
Jeffrey (Dongkyu) Kim 346ce7f516 fix(startup-support): use K-Startup proxy surface 2026-06-05 13:03:28 +09:00
Jeffrey (Dongkyu) Kim 581b0344ce Merge commit 'c27a3e9' into ulw-merge-seven-prs
# Conflicts:
#	package.json
2026-05-31 17:25:22 +09:00
Jeffrey (Dongkyu) Kim cc768f4031 Merge commit 'cff6b29' into ulw-merge-seven-prs 2026-05-31 17:24:25 +09:00
Jeffrey (Dongkyu) Kim cff6b29ff9 fix(startup-support): remove fabricated detail data 2026-05-31 17:23:57 +09:00
Donghun Seol 00a6d9feae fix(foresttrip-vacancy): exclude 예비 rooms, gate useDt strictly, dedup duplicate rooms
월별예약조회 API가 srchDate 단일 일자 요청에도 5일 윈도우를 반환하고,
"예비"로 표기된 운영자 보유분이 raw 응답에 포함되며, 같은 객실이 다른
goodsId로 중복 표시되는 세 가지 문제를 한꺼번에 fix한다.

수정:
- collect_results 안에 strict useDt gate 추가 (today~last_day 범위 밖 행 차단)
- is_reserve_room() helper로 goodsNm에 "예비" 포함 객실 제외
- (forest_id, use_dt, name) 단위 dedup으로 중복 행 제거
- is_available()는 시그니처/로직 변경 없이 booking-state predicate 유지

추가:
- foresttrip-vacancy/tests/ 18개 단위 테스트 (mock + fixture 기반)
- IsReserveRoomTest, IsAvailableTest, CollectResultsFilterTest,
  StrictUseDtGateTest, GroundTruthTest 다섯 클래스
- 거제·구재봉 fixture로 사용자 라이브 검증 결과 회귀 보호
- package.json lint·test 스크립트에 등록

문서:
- SKILL.md: API 5일 윈도우/예비 객실/중복 dedup 자동 처리 명시 + 회복 시나리오 보강
- docs/features/foresttrip-vacancy.md: 기본 흐름 6단계와 주의할 점 보강

사용자 라이브 검증 ground truth (2026-05-12 기준):
- 거제자연휴양림 5/13 ~9개, 5/16 0개, 5/17 19개, 5/23 0개, 5/24 0개
- 구재봉자연휴양림 5/16 1개 (206호 쑥부쟁이방)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 20:57:25 +09:00
iamiks 24feb3edca feat(ktx-booking): 좌석 탐색 우선순위 개선
KTX 상세 좌석 조회에서 가운데 호차를 먼저 탐색하고,
같은 호차 안에서는 콘센트 좌석과 순방향 좌석을 우선 노출합니다.
#294 요구사항을 우선순위 함수와 command_seats 회귀 테스트로 고정합니다.

Constraint: #294는 기존 seats 공개 인터페이스 유지를 요구함
Rejected: 예약 API에 객차/좌석 번호를 직접 주입 | 현재 helper 예약 경로가 해당 선택 인자를 노출하지 않음
Confidence: high
Scope-risk: narrow
Directive: 좌석 우선순위 변경 시 command_seats 출력 순서 테스트를 함께 갱신할 것
Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_ktx_booking
Tested: node --test scripts/skill-docs.test.js
Tested: npm run typecheck
Tested: npm run ci
2026-05-28 22:49:31 +09:00
iamiks 8420792a82 Expose KTX seat-level lookup before reservation
Add a seats command to inspect residual seats by car, normalize seat metadata, and surface power-outlet hints while preserving the existing search and reserve selector flow. Update skill docs so seat-number and good-seat requests route through the detailed lookup before reservation.

Constraint: Korail reservation remains separate from seat inspection; the new flow must not select, hold, or pay for seats.

Rejected: Reusing train-level has_general_seat flags for good-seat requests | those flags cannot answer car number, seat label, or outlet availability.

Confidence: high

Scope-risk: moderate

Directive: Keep search, seats, and reserve on the same train_type and stable train_id path so stale results fail explicitly.

Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_ktx_booking; python3 -m py_compile scripts/ktx_booking.py scripts/test_ktx_booking.py; node --check scripts/skill-docs.test.js

Not-tested: npm run ci is blocked locally because gitignored .agents/ and .venv directories are treated as missing SKILL.md by scripts/validate-skills.sh.
2026-05-28 22:49:13 +09:00
TaeyoungPark 9b2e0957f2 chore: merge upstream/dev into feat/myrealtrip-mcp-search 2026-05-27 16:33:36 +09:00
TaeyoungPark d12bfa1fab feat: Add startup-support skill for Korean government startup programs
- Add startup-support skill to search Korean government startup support programs
- Implement Python script with multiple data sources (public data, local governments)
- Add k-skill-proxy routes for API endpoints
- Update documentation (README.md, docs/features/, docs/sources.md, etc.)
- Add comprehensive test suite

Closes #startup-support
2026-05-27 15:40:12 +09:00
Jeffrey (Dongkyu) Kim 99340393de docs: 네이버맵 스킬 미작동 안내 추가 (NCP 키 미설정) 2026-05-25 18:31:03 +09:00
Jeffrey (Dongkyu) Kim 72a3fd7ca6 merge: resolve conflicts with dev after PR #282 merge 2026-05-25 17:16:53 +09:00
Jeffrey (Dongkyu) Kim 440f33b52f feat(#268): 네이버맵 길찾기 MVP 스킬 + NCP Maps proxy 라우트 3종
feat(#268): 네이버맵 길찾기 MVP 스킬 + NCP Maps proxy 라우트 3종
2026-05-25 16:39:51 +09:00
Jeffrey (Dongkyu) Kim 68bd64ebd4 Preserve route proxy rate-limit semantics
Narrow the Naver Maps proxy contract to JSON reverse geocode responses and preserve upstream quota signals so client fallback can make accurate decisions.

Constraint: PR #282 review requested TDD fixes for XML contract mismatch, upstream 429 mapping, lint coverage, and route option documentation.

Rejected: XML passthrough in this follow-up | It would require a separate response-shaping contract and tests beyond the JSON proxy boundary.

Confidence: high

Scope-risk: narrow

Directive: Keep Naver Maps auth failures sanitized as 503 without upstream body snippets while preserving non-auth diagnostic snippets.

Tested: node --test packages/k-skill-proxy/test/server.test.js; node --test scripts/skill-docs.test.js; bash scripts/validate-skills.sh; PYENV_VERSION=3.12.0 npm run ci; architect verification CLEAR

Not-tested: Live NCP Maps calls with production credentials

Co-authored-by: OmX <omx@oh-my-codex.dev>
2026-05-23 19:57:21 +09:00
Jeffrey (Dongkyu) Kim 366d346f03 Keep Kakao route contracts local and explicit
Constraint: PR #283 review requested TDD fixes for Kakao Local distance sorting, Mobility toll avoidance, lint coverage, and coord2region routing coverage.
Rejected: Relying on upstream Kakao validation for sort=distance | it spends quota and returns a proxy/upstream error instead of local bad_request.
Rejected: Document-only toll avoidance correction | the skill already promises the behavior and Kakao Mobility exposes an explicit avoid option.
Confidence: high
Scope-risk: narrow
Directive: Preserve server-side KAKAO_REST_API_KEY injection only; never accept or forward caller apiKey query values.
Tested: node --test packages/k-skill-proxy/test/server.test.js; npm test --workspace k-skill-proxy; npm run lint --workspace k-skill-proxy; node --test scripts/skill-docs.test.js; bash scripts/validate-skills.sh; manual Fastify inject smoke for sort=distance and avoid forwarding; npm run ci through lint/typecheck until local Python pyexpat failure.
Not-tested: Full npm run ci completion due local Python 3.14 pyexpat ImportError during pip install.
2026-05-23 19:25:10 +09:00
Jeffrey (Dongkyu) Kim 45084293f0 Feature/#270 (#281)
* Enable deterministic Middle Korean-style rewriting

Constraint: Issue #270 requested a new skill that converts incoming Korean text into 한국 중세 국어 style under non-interactive TDD automation.
Rejected: LLM-only prompt guidance | It would not provide deterministic CLI behavior or regression-testable output.
Confidence: high
Scope-risk: narrow
Directive: Keep this as creative style conversion, not an academically exact Middle Korean translator.
Tested: node --test scripts/test_korean_middle_korean.js; npm run lint; npm run typecheck; root node/python/workspace tests without pip bootstrap; npm run pack:dry-run; installed-skill smoke.
Not-tested: npm run test bootstrap step because python3 -m pip fails in this local Homebrew Python 3.14 environment due pyexpat/libexpat symbol mismatch before tests start.

* Align Middle Korean profile contract with implementation

Preserve the existing date-before-lexicon transform order and document it as the v1 contract instead of reordering an already-reviewed helper.

Constraint: PR #281 review requested the docs/contract mismatch be resolved with TDD evidence.

Rejected: Reordering the converter | would alter current output behavior beyond the approved follow-up.

Confidence: high

Scope-risk: narrow

Directive: Treat middle-korean-style-v1 output-changing rule order edits as contract changes that need regression tests and docs updates.

Tested: node --test scripts/test_korean_middle_korean.js; npm run lint; npm run typecheck; npm run pack:dry-run; npm run test without pip bootstrap commands; installed-skill smoke.

Not-tested: npm run test direct bootstrap remains blocked locally by Homebrew Python 3.14 pyexpat/libexpat symbol mismatch.

* Clarify middle Korean profile stability

Align the documented v1 contract with the intentionally broad deterministic replacer so future readers do not infer exact proper-noun preservation.

Constraint: PR #281 round 2 architect WATCH asked to weaken preservation guarantees or add stronger rule boundaries.

Rejected: Changing replacement behavior | The PR already verified the creative v1 output and only the contract wording was mismatched.

Confidence: high

Scope-risk: narrow

Directive: Treat output-changing edits to middle-korean-style-v1 as compatibility-affecting and update docs plus regression tests together.

Tested: node --test scripts/test_korean_middle_korean.js; node --check korean-middle-korean/scripts/korean_middle_korean.js; node --check scripts/korean_middle_korean.js; npm run lint; npm run typecheck; root/workspace post-bootstrap test chain; npm run pack:dry-run; installed skill smoke.

Not-tested: Direct npm run test still blocked before tests by local Homebrew Python 3.14 pyexpat/libexpat symbol mismatch.

* Protect structural spans during style conversion

Keep arbitrary text links, email addresses, and code spans usable while preserving the deterministic middle-korean-style-v1 prose transform.\n\nConstraint: PR #281 round 3 requested URL/email/code-like span protection after broad global replacement probes rewrote structural tokens.\nRejected: Narrowing all lexicon and particle rules with word-boundary heuristics | would change established v1 creative broad-replacement behavior beyond the reviewed issue.\nConfidence: high\nScope-risk: narrow\nDirective: Protect new structural span classes before broad replacements and add regression tests before extending the protected surface.\nTested: node --test scripts/test_korean_middle_korean.js; node --check korean-middle-korean/scripts/korean_middle_korean.js; node --check scripts/korean_middle_korean.js; CLI URL/email/code/Markdown probes; installed-skill smoke via ~/.agents/skills/korean-middle-korean/scripts/korean_middle_korean.js; npm run lint; npm run typecheck; root/workspace test chain without pip bootstrap; npm run pack:dry-run; post-deslop npm run lint && npm run typecheck && node --test scripts/test_korean_middle_korean.js && npm run pack:dry-run\nNot-tested: direct npm run test remains blocked before repo tests by local Homebrew Python 3.14 pyexpat/libexpat import error.
2026-05-23 17:54:56 +09:00
Jeffrey (Dongkyu) Kim 6d49a28d87 feat(kakao-map): Kakao Local/Mobility 프록시 라우트 + 장소·자동차 길찾기 스킬 (#267)
- packages/k-skill-proxy:
  - /v1/kakao-map/search/keyword (좌표 중심·반경·카테고리 필터)
  - /v1/kakao-map/search/category (좌표 중심 필수, FD6/CE7 등 공식 코드 화이트리스트)
  - /v1/kakao-map/coord2address (좌표→도로명/지번)
  - /v1/kakao-map/coord2region (좌표→법정동/행정동)
  - /v1/kakao-mobility/directions (자동차 길찾기, priority/car_fuel/waypoints/alternatives 옵션)
  - 모두 운영자 KAKAO_REST_API_KEY 서버측 주입, caller apiKey 무시
- kakao-map 스킬 + docs/features/kakao-map.md 신규
- proxy 테스트 10건 신규 (헤더 주입·캐시, 좌표·반경·정렬·카테고리·priority 검증, 503 missing-key 매트릭스, semantic failure non-cache, health 플래그)
- README/포함된 기능, packages/k-skill-proxy/README, docs/sources, changeset 동시 갱신

Closes #267
2026-05-23 17:51:06 +09:00
Jeffrey (Dongkyu) Kim ff2aa91f83 feat(naver-map-route): NCP Maps Directions/Geocode/Reverse-Geocode 프록시 라우트 + MVP 길찾기 스킬 (#268)
- packages/k-skill-proxy: NAVER_MAP_CLIENT_ID/SECRET 서버측 보관, /v1/naver-map/{directions,geocode,reverse-geocode} 라우트 3종 추가
- naver-map-route: instruction-level MVP 스킬 (mock 기본, ROUTE_PLANNER_ENABLE_LIVE_PROVIDER=true + ROUTE_PLANNER_PROVIDER=naver 에서만 live)
- /route, /이동루트 수동 입력 처리, graceful fallback 정책 문서화
- proxy 테스트 8건 신규 (missing-key 503, 캐시, 좌표 검증, semantic failure non-cache, auth error sanitize, geocode 헤더 주입, reverse-geocode orders 검증, health 플래그)
- README 표/포함된 기능, packages/k-skill-proxy/README, docs/features/naver-map-route, docs/sources, changeset 동시 갱신

Closes #268
2026-05-23 17:36:55 +09:00
Jeffrey (Dongkyu) Kim e6d7072e93 Feature/#274 (#277)
* Add Seoul Bike live station lookup

Expose narrow Seoul Open Data proxy surfaces for realtime bike availability, station master pages, and coordinate-based nearby lookups while keeping the upstream key server-side. Add a single Python skill entrypoint plus docs so agents can answer last-mile bike and dock availability questions.

Constraint: Issue #274 requires , TDD, three proxy routes, branch feature/#274, and PR to dev.
Rejected: Client-side Seoul OpenAPI key handling | would leak upstream credentials and violate existing proxy patterns.
Confidence: high
Scope-risk: moderate
Directive: Keep these routes read-only; do not add rental/booking mutations or user-key requirements.
Tested: node --test packages/k-skill-proxy/test/server.test.js --test-name-pattern 'seoul bike'; PYTHONPATH=.:scripts python3 -m unittest scripts.test_seoul_bike; local fake-proxy smoke run; PATH="/Users/jeffrey/.pyenv/versions/3.11.9/bin:/Users/jeffrey/.codex/tmp/arg0/codex-arg08RBix6:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/jeffrey/.cmuxterm/omo-bin:/opt/homebrew/share/android-commandlinetools/platform-tools:/opt/homebrew/share/android-commandlinetools/emulator:/opt/homebrew/share/android-commandlinetools/cmdline-tools/latest/bin:/Users/jeffrey/.local/bin:/Users/jeffrey/.bun/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/opt/openjdk@21/bin:/opt/homebrew/opt/postgresql@18/bin:/Users/jeffrey/.jenv/shims:/Users/jeffrey/.jenv/bin:/opt/homebrew/opt/imagemagick/bin:/opt/homebrew/Cellar/pyenv-virtualenv/1.4.0/shims:/Users/jeffrey/.pyenv/shims:/opt/homebrew/opt/openssl@3/bin:/Users/jeffrey/.rbenv/shims:/Users/jeffrey/.rbenv/bin:/Users/jeffrey/google-cloud-sdk/bin:/Applications/cmux.app/Contents/Resources/bin:/Users/jeffrey/Library/pnpm:/Users/jeffrey/.nvm/versions/node/v24.13.0/bin:/Users/jeffrey/.cops/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/Library/Apple/usr/bin:/Library/TeX/texbin:/Users/jeffrey/.cargo/bin:/Users/jeffrey/Library/Application Support/JetBrains/Toolbox/scripts:/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin:/Users/jeffrey/xcode-projects/marshroom/cli" npm run ci.
Not-tested: Live hosted Seoul Open Data request with production SEOUL_OPEN_API_KEY.

* Prevent Seoul Bike upstream errors from masquerading as empty availability

Constraint: Seoul Open API can return application-level error JSON with HTTP 200, so proxy routes must inspect RESULT envelopes before caching or normalizing rows.
Rejected: Treating missing rentBikeStatus.row as an empty success | it masks quota/service failures and caches false no-station results.
Confidence: high
Scope-risk: narrow
Directive: Preserve non-cacheable proxy error behavior for Seoul Open API semantic failures across realtime, stations, and nearby routes.
Tested: node --test packages/k-skill-proxy/test/server.test.js --test-name-pattern 'seoul bike'; PYTHONPATH=.:scripts python3 -m unittest scripts.test_seoul_bike; local fake-proxy seoul_bike.py nearby smoke; PATH="/Users/jeffrey/.pyenv/versions/3.11.9/bin:/Users/jeffrey/.codex/tmp/arg0/codex-arg0j0fIum:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/jeffrey/.cmuxterm/omo-bin:/opt/homebrew/share/android-commandlinetools/platform-tools:/opt/homebrew/share/android-commandlinetools/emulator:/opt/homebrew/share/android-commandlinetools/cmdline-tools/latest/bin:/Users/jeffrey/.local/bin:/Users/jeffrey/.bun/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/opt/openjdk@21/bin:/opt/homebrew/opt/postgresql@18/bin:/Users/jeffrey/.jenv/shims:/Users/jeffrey/.jenv/bin:/opt/homebrew/opt/imagemagick/bin:/opt/homebrew/Cellar/pyenv-virtualenv/1.4.0/shims:/Users/jeffrey/.pyenv/shims:/opt/homebrew/opt/openssl@3/bin:/Users/jeffrey/.rbenv/shims:/Users/jeffrey/.rbenv/bin:/Users/jeffrey/google-cloud-sdk/bin:/Applications/cmux.app/Contents/Resources/bin:/Users/jeffrey/Library/pnpm:/Users/jeffrey/.nvm/versions/node/v24.13.0/bin:/Users/jeffrey/.cops/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/Library/Apple/usr/bin:/Library/TeX/texbin:/Users/jeffrey/.cargo/bin:/Users/jeffrey/Library/Application Support/JetBrains/Toolbox/scripts:/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin:/Users/jeffrey/xcode-projects/marshroom/cli" npm run ci; architect review APPROVED.
Not-tested: Live Seoul Open API error response from production service.

* Reject ambiguous Seoul Bike integer input

Tighten the public Seoul Bike query boundary so malformed integer strings cannot be partially parsed into valid requests.

Constraint: PR #277 review found parseInt accepted partially numeric query values on Seoul Bike routes.\nRejected: Keep parseInt with bounds checks | bounds still allow misleading values like 10abc and 1.5.\nConfidence: high\nScope-risk: narrow\nDirective: Keep Seoul Bike public query aliases strict; do not reintroduce partial numeric parsing.\nTested: node --test packages/k-skill-proxy/test/server.test.js --test-name-pattern 'seoul bike'; PYTHONPATH=.:scripts python3 -m unittest scripts.test_seoul_bike; explicit app.inject invalid-query smoke; PATH="/Users/jeffrey/.pyenv/versions/3.11.9/bin:/Users/jeffrey/.codex/tmp/arg0/codex-arg0uv50Mt:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/jeffrey/.cmuxterm/omo-bin:/opt/homebrew/share/android-commandlinetools/platform-tools:/opt/homebrew/share/android-commandlinetools/emulator:/opt/homebrew/share/android-commandlinetools/cmdline-tools/latest/bin:/Users/jeffrey/.local/bin:/Users/jeffrey/.bun/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/opt/openjdk@21/bin:/opt/homebrew/opt/postgresql@18/bin:/Users/jeffrey/.jenv/shims:/Users/jeffrey/.jenv/bin:/opt/homebrew/opt/imagemagick/bin:/opt/homebrew/Cellar/pyenv-virtualenv/1.4.0/shims:/Users/jeffrey/.pyenv/shims:/opt/homebrew/opt/openssl@3/bin:/Users/jeffrey/.rbenv/shims:/Users/jeffrey/.rbenv/bin:/Users/jeffrey/google-cloud-sdk/bin:/Applications/cmux.app/Contents/Resources/bin:/Users/jeffrey/Library/pnpm:/Users/jeffrey/.nvm/versions/node/v24.13.0/bin:/Users/jeffrey/.cops/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/Library/Apple/usr/bin:/Library/TeX/texbin:/Users/jeffrey/.cargo/bin:/Users/jeffrey/Library/Application Support/JetBrains/Toolbox/scripts:/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin:/Users/jeffrey/xcode-projects/marshroom/cli" npm run ci\nNot-tested: live hosted Seoul Open API traffic

* Protect hosted Seoul Bike proxy secrets

Sanitize Seoul Bike upstream fetch and parse failures before they can reach the global error handler, and reject blank nearby coordinates before JavaScript can coerce them to zero.\n\nConstraint: PR #277 round-3 review found server-side Seoul Open API keys could leak through exception messages containing keyed upstream URLs.\nRejected: Letting the global error handler format Seoul Bike upstream exceptions | it echoes exception messages and can expose the hosted proxy API key.\nConfidence: high\nScope-risk: narrow\nDirective: Keep server-side API-key-bearing upstream URLs out of client-visible error messages and logs for hosted no-user-key routes.\nTested: node --test packages/k-skill-proxy/test/server.test.js --test-name-pattern 'seoul bike'; PYTHONPATH=.:scripts python3 -m unittest scripts.test_seoul_bike; explicit app.inject smoke for sanitized Seoul Bike failures and blank coordinates; local fake-proxy seoul-bike nearby smoke; PATH="/Users/jeffrey/.pyenv/versions/3.11.9/bin:/Users/jeffrey/.codex/tmp/arg0/codex-arg0mxZmWx:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/jeffrey/.cmuxterm/omo-bin:/opt/homebrew/share/android-commandlinetools/platform-tools:/opt/homebrew/share/android-commandlinetools/emulator:/opt/homebrew/share/android-commandlinetools/cmdline-tools/latest/bin:/Users/jeffrey/.local/bin:/Users/jeffrey/.bun/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/opt/openjdk@21/bin:/opt/homebrew/opt/postgresql@18/bin:/Users/jeffrey/.jenv/shims:/Users/jeffrey/.jenv/bin:/opt/homebrew/opt/imagemagick/bin:/opt/homebrew/Cellar/pyenv-virtualenv/1.4.0/shims:/Users/jeffrey/.pyenv/shims:/opt/homebrew/opt/openssl@3/bin:/Users/jeffrey/.rbenv/shims:/Users/jeffrey/.rbenv/bin:/Users/jeffrey/google-cloud-sdk/bin:/Applications/cmux.app/Contents/Resources/bin:/Users/jeffrey/Library/pnpm:/Users/jeffrey/.nvm/versions/node/v24.13.0/bin:/Users/jeffrey/.cops/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/Library/Apple/usr/bin:/Library/TeX/texbin:/Users/jeffrey/.cargo/bin:/Users/jeffrey/Library/Application Support/JetBrains/Toolbox/scripts:/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin:/Users/jeffrey/xcode-projects/marshroom/cli" npm run ci.\nNot-tested: Live Seoul Open API network failure from production Cloud Run.
2026-05-22 13:54:36 +09:00
Jeffrey (Dongkyu) Kim 80e7805681 ci(k-skill-proxy): replace local pm2+cloudflared with Cloud Run auto-deploy via GitHub Actions
main에 머지되면 GitHub Actions가 자동으로 Workload Identity Federation으로 GCP 인증 후
Artifact Registry에 컨테이너 이미지를 빌드/푸시하고 Cloud Run(asia-northeast1) 서비스
k-skill-proxy를 재배포한다. 시크릿은 GCP Secret Manager에서 런타임에 주입된다.

- add .github/workflows/deploy-k-skill-proxy.yml (WIF, on push to main)
- add packages/k-skill-proxy/Dockerfile (multi-stage node:20-alpine, port bridge)
- add docs/deploy-k-skill-proxy.md (1회성 GCP 셋업 + 운영 점검 절차)
- remove ecosystem.config.cjs (PM2 root config)
- remove scripts/run-k-skill-proxy.sh (local secrets.env source + node launcher)
- remove wrangler devDependency (unused Cloudflare Workers CLI)
- update AGENTS.md, CLAUDE.md, CONTRIBUTING.md, docs/features/k-skill-proxy.md,
  packages/k-skill-proxy/README.md to describe the new Cloud Run + GHA flow
- clean dead k-skill-proxy-cloudrun entries from .gitignore
2026-05-21 13:45:06 +09:00
Jeffrey (Dongkyu) Kim 68abad3de0 Feature/#256 (#266)
* Enable public local-election candidate lookups

Add an NEC integrated-search skill and helper package so agents can answer 지방선거 후보자 lookup requests without credentials or proxy routes.

Constraint: Issue #256 requested TDD, Ralph completion, branch feature/#256, and PR targeting dev.

Rejected: k-skill-proxy route | NEC integrated candidate search is public and requires no API key.

Confidence: high

Scope-risk: moderate

Directive: Keep the helper read-only and do not automate NEC login, CAPTCHA, filing, or privileged election workflows.

Tested: git diff --check; node --test packages/local-election-candidate-search/test/index.test.js; npm run lint --workspace local-election-candidate-search; npm run test --workspace local-election-candidate-search; npm pack --workspace local-election-candidate-search --dry-run; node packages/local-election-candidate-search/src/cli.js 오세훈 --election 시도지사 --region 서울 --limit 1; PATH=/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin:/Users/jeffrey/.codex/tmp/arg0/codex-arg0a6JueA:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/jeffrey/.cmuxterm/omo-bin:/opt/homebrew/share/android-commandlinetools/platform-tools:/opt/homebrew/share/android-commandlinetools/emulator:/opt/homebrew/share/android-commandlinetools/cmdline-tools/latest/bin:/Users/jeffrey/.local/bin:/Users/jeffrey/.bun/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/opt/openjdk@21/bin:/opt/homebrew/opt/postgresql@18/bin:/Users/jeffrey/.jenv/shims:/Users/jeffrey/.jenv/bin:/opt/homebrew/opt/imagemagick/bin:/opt/homebrew/Cellar/pyenv-virtualenv/1.4.0/shims:/Users/jeffrey/.pyenv/shims:/opt/homebrew/opt/openssl@3/bin:/Users/jeffrey/.rbenv/shims:/Users/jeffrey/.rbenv/bin:/Users/jeffrey/google-cloud-sdk/bin:/Applications/cmux.app/Contents/Resources/bin:/Users/jeffrey/Library/pnpm:/Users/jeffrey/.nvm/versions/node/v24.13.0/bin:/Users/jeffrey/.cops/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/Library/Apple/usr/bin:/Library/TeX/texbin:/Users/jeffrey/.cargo/bin:/Users/jeffrey/Library/Application Support/JetBrains/Toolbox/scripts:/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin:/Users/jeffrey/xcode-projects/marshroom/cli npm run ci

Not-tested: Exhaustive NEC markup variants for every historical election type.

Co-authored-by: OmX <omx@oh-my-codex.dev>

* Enforce fail-closed candidate identity parsing

Constraint: PR #266 review required exact candidate-name matching and CLI help regression coverage.\nRejected: fallback-to-query-name on missing upstream markup | it can mislabel unrelated candidates as exact matches.\nConfidence: high\nScope-risk: narrow\nDirective: Keep NEC parser changes fail-closed when candidate identity cannot be parsed.\nTested: git diff --check; node --test packages/local-election-candidate-search/test/index.test.js; npm run lint --workspace local-election-candidate-search; npm run test --workspace local-election-candidate-search; npm pack --workspace local-election-candidate-search --dry-run; live CLI smoke for 오세훈; CLI --help smoke.\nNot-tested: repo-wide npm run ci remains blocked by pre-existing missing SKILL.md: ohou-today-deal.

* Preserve unique candidate lookup results

Deduplicate parsed NEC candidate/election rows before applying user limits, and make expected CLI validation failures concise by default while keeping an explicit debug stack escape hatch.

Constraint: PR #266 round-2 follow-up requested TDD fixes for duplicate NEC rows and CLI validation UX.\nRejected: Deduplicating after limit | would still allow duplicates to crowd out unique rows.\nRejected: Always printing stack traces | exposes local paths for normal user-input failures.\nConfidence: high\nScope-risk: narrow\nDirective: Keep dedupe keys stable enough to avoid collapsing legitimately distinct historical election rows.\nTested: git diff --check; node --test packages/local-election-candidate-search/test/index.test.js; npm run lint --workspace local-election-candidate-search; npm run test --workspace local-election-candidate-search; npm pack --workspace local-election-candidate-search --dry-run; live 오세훈 smoke; live 김동연 duplicate repro; CLI no-args/help.\nNot-tested: Full npm run ci remains blocked by pre-existing missing SKILL.md: ohou-today-deal.

* Prevent filtered NEC lookup false negatives

Fix the candidate parser so documented education-superintendent and filtered local-election lookups return bounded, evidence-backed results instead of silently dropping valid rows.

Constraint: PR #266 round-3 review required TDD, Ralph verification, and branch update for issue #256.

Rejected: Full NEC pagination in this follow-up | broader than the approved change; bounded 100-row fetch now avoids user-limit false negatives and warns when capped.

Confidence: high

Scope-risk: narrow

Directive: Preserve exact-name fail-closed parsing and count raw parsed upstream rows before cap-warning decisions.

Tested: git diff --check; node --test packages/local-election-candidate-search/test/index.test.js; npm run lint --workspace local-election-candidate-search; npm run test --workspace local-election-candidate-search; npm pack --workspace local-election-candidate-search --dry-run; live CLI smokes for 오세훈, 조희연, 김동연; CLI help/no-args checks; architect verification CLEAR.

Not-tested: Full npm run ci remains blocked by pre-existing repo-wide missing SKILL.md: ohou-today-deal.

---------

Co-authored-by: OmX <omx@oh-my-codex.dev>
2026-05-18 23:11:23 +09:00