Commit graph

247 commits

Author SHA1 Message Date
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
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
Jeffrey (Dongkyu) Kim
4a78169220 fix(ohou-today-deal): address PR #264 review (live UA, explicit feed selection, argv validators)
- HIGH: switch fetch_html() to well-formed bot UA with contact URL
  (k-skill-ohou-today-deal/1.0 (+https://github.com/NomaDamas/k-skill)).
  ohou.se Akamai bot manager 403s anonymous UAs but allows identified
  bot UAs that include a contact URL. Live default workflow now returns
  74 deals end-to-end instead of failing with HTTP 403.
- MEDIUM: extract_deals() now explicitly selects React Query entries with
  queryKey == ['today-deal-feed'] or ['special-today-deal-feed'] and
  reads only state.data.todayDealFeed.slots[type=='DEAL']. Unrelated
  DEAL-shaped nodes from navigation/banner modules are excluded.
  Legacy fixture/JSON-payload fallback path preserved for tests that
  construct simplified payloads.
- LOW: --limit now requires a positive integer; --min-discount is
  constrained to 0..100. Both validated via argparse.ArgumentTypeError
  so users get a clear CLI error instead of silent slicing or nonsensical
  thresholds.
- Tests: add 9 new unit tests covering explicit feed selection,
  navigation/GOODS exclusion, fallback compatibility, and argv validators.
  Strengthen skill-docs.test.js to lock the special-today-deal-feed
  surface and well-formed UA signature.
- Docs: update SKILL.md and feature doc to document the explicit
  today-deal-feed + special-today-deal-feed extraction boundary and the
  Akamai UA policy.
2026-05-18 16:36:56 +09:00
lee-ji-hong
ca5aefd990 Add Ohou today deal skill 2026-05-18 15:40:18 +09:00
배기민
540e80b804
feat(kstartup-search): 창업진흥원 K-Startup 조회 스킬 + 프록시 라우트 4종 (#259)
* feat(kstartup-search): 창업진흥원 K-Startup 조회 스킬과 프록시 라우트 추가

공공데이터포털 dataset 15125364 (창업진흥원_K-Startup(사업소개,사업공고,콘텐츠 등)_조회서비스) 의
4개 endpoint 를 k-skill-proxy 경유로 조회하는 스킬을 추가한다.

- 신규 라우트: GET /v1/kstartup/{business-info,announcements,contents,statistics}
  - 각각 getBusinessInformation01/getAnnouncementInformation01/getContentInformation01/
    getStatisticalInformation01 으로 중계
  - ServiceKey 는 서버 측 DATA_GO_KR_API_KEY 로 주입, returnType=json 강제
  - 정상 응답만 캐시, data.go.kr 에러 envelope (resultCode != "00", errMsg 등) 은 캐시 우회
- helper: kstartup-search/scripts/run_kstartup.py (stdlib only)
  - 일반 조회는 hosted proxy 사용 → 사용자 키 불필요
  - --direct 옵션은 사용자가 본인 KSKILL_KSTARTUP_API_KEY (혹은 DATA_GO_KR_API_KEY) 로
    upstream 직접 호출 + --dry-run 시 키 redact
- 입력 검증: page/perPage 정수·범위, YYYYMMDD 날짜 + 시작일 ≤ 종료일, Y/N 대문자화,
  텍스트 필드 길이 상한, biz_yr 4자리
- 테스트: k-skill-proxy 서버 테스트 10건 신규 (normalizer, 라우트, 캐시 분리,
  returnType=json 강제, 503/400/502, 키 누수 회귀), Python unittest 13건
- 문서: SKILL.md, docs/features/kstartup-search.md, README 표/리스트,
  docs/sources.md, .changeset/kstartup-search.md (k-skill-proxy minor)

* docs(kstartup-search): docs/setup·security·k-skill-setup·proxy README 에 K-Startup 항목 추가

seoul-density · KOSIS · NTS 선례와 동일한 위치·문구로 다음을 보강한다.

- docs/setup.md: dotenv 예시에 KSKILL_KSTARTUP_API_KEY 추가, credential 표에 K-Startup 행 추가, "다음에 볼 문서" 리스트 추가
- docs/security-and-secrets.md: standard variable names 에 KSKILL_KSTARTUP_API_KEY 추가, hosted proxy 사용 스킬 목록·proxy 운영 prose 에 K-Startup 추가, dotenv 예시 추가
- k-skill-setup/SKILL.md: credential resolution prose 와 시크릿 요약 표에 K-Startup 안내 추가
- packages/k-skill-proxy/README.md: 라우트 목록에 /v1/kstartup/{business-info,announcements,contents,statistics} 추가
- docs/features/k-skill-proxy.md: 라우트 목록에 같은 4개 추가

* fix(kstartup-search): strict calendar-date validation in Python helper

validate_yyyymmdd() previously only checked month in [1,12] and day in [1,31],
which accepted impossible dates like 20240230 or 20240431 in --direct mode.
The proxy-side normalizer in packages/k-skill-proxy/src/kstartup.js already
uses Date.UTC() to reject such inputs, so this aligns the --direct path with
the proxy path and eliminates validator drift.

Uses datetime.date(year, month, day) and raises HelperError on ValueError.

Adds regression test covering impossible calendar dates (Feb 30, Apr 31,
month 13, day 0) and the leap-year boundary (2024-02-29 valid, 2023-02-29
not).

---------

Co-authored-by: Jeffrey (Dongkyu) Kim <vkehfdl1@gmail.com>
2026-05-18 11:43:33 +09:00
hmmhmmhm/
e5b4465630
영화관 검색 스킬 추가 (#260)
* Add korean cinema search skill

* Document playDate for cinema skill
2026-05-18 11:42:40 +09:00
Jeffrey (Dongkyu) Kim
4e2d1faf19 Support nearby ER status checks
Add an E-Gen based emergency-room skill that resolves a user location, queries the public nearby emergency-room list, and reports operation flags while documenting that exact remaining bed counts are not exposed by this surface.

Constraint: Issue #255 requested NEMC emergency bed status using public monitoring/E-Gen surfaces.
Rejected: Scraping private monitoring dashboards or claiming exact bed utilization | public endpoints expose operation flags, not per-hospital remaining bed counts.
Confidence: high
Scope-risk: narrow
Directive: Preserve the public-data limitation text unless a verified official bed-count endpoint is added.
Tested: npm run lint --workspace emergency-room-beds; npm test --workspace emergency-room-beds; node --test scripts/skill-docs.test.js; npm run typecheck; npm pack --workspace emergency-room-beds --dry-run; ./scripts/validate-skills.sh; live E-Gen coordinate smoke.
Not-tested: npm run ci end-to-end due local Python 3.14 pip/pyexpat import error before tests.
2026-05-17 18:37:07 +09:00
Jeffrey (Dongkyu) Kim
fadc23c3ff Merge branch 'dev' into feature/#252
Resolves package.json conflict by keeping both:
- test: scripts.test_danawa_price_search (from this PR)
- pack:dry-run: sh-notice-search workspace (from dev #251)
2026-05-17 16:19:47 +09:00
Jeffrey (Dongkyu) Kim
0895136e51
Merge pull request #251 from NomaDamas/feature/#207
Feature/#207
2026-05-17 16:16:23 +09:00
Jeffrey (Dongkyu) Kim
c83e194a84 Restore SH notice lookup without proxy policy drift
Reintroduce SH notice search as a direct public HTML client so the skill complies with the free-API proxy boundary while preserving verifiable keyword, pagination, and attachment behavior.

Constraint: i-sh.co.kr board is public unauthenticated HTML, so k-skill-proxy must not host the scraper.\nRejected: Re-adding /v1/sh-notice proxy routes | public HTML scraping in proxy violates repository policy.\nConfidence: high\nScope-risk: moderate\nDirective: Keep SH public HTML access local/direct unless a key-required official free API is discovered and documented.\nTested: npm run ci; npm run lint --workspace sh-notice-search; npm test --workspace sh-notice-search; live SH smoke for 행복주택, 매입임대, 신혼희망타운, page 1/page 5, 1/6/9/11/0 attachment details.\nNot-tested: authenticated SH flows, 청약 application/submission, direct attachment downloads.
2026-05-15 19:22:55 +09:00
Jeffrey (Dongkyu) Kim
5a6dcedb99
Merge pull request #249 from NomaDamas/feature/#248
Feature/#248
2026-05-15 18:02:04 +09:00
Jeffrey (Dongkyu) Kim
945bd32296 Keep icon-only Danawa payment badges visible
Class-only Danawa payment icons can carry eligibility information without visible text, so synthesize display labels from the same normalized condition map used for types and booleans. This keeps raw row labels, condition fields, and returned-window counts aligned for downstream table renderers.\n\nConstraint: PR #253 review follow-up requires TDD coverage before parser changes.\nRejected: Leaving payment_badges text-only | icon-only conditional rows would still render without visible payment labels.\nConfidence: high\nScope-risk: narrow\nDirective: Derive future payment badge labels, types, and booleans from one canonical mapping.\nTested: python3 -m py_compile danawa-price-search/scripts/danawa_search.py scripts/test_danawa_price_search.py; PYTHONPATH=.:scripts python3 -m unittest scripts.test_danawa_price_search; python3 danawa-price-search/scripts/danawa_search.py offers 75001853 --limit 5; npm run lint; npm run typecheck; npm run test\nNot-tested: Danawa icon-only markup was verified with synthetic fixtures rather than a live page snapshot.
2026-05-15 17:50:58 +09:00
Jeffrey (Dongkyu) Kim
56a00005ef Ensure captured Danawa payment badges stay conditional
Classify every whitelisted payment badge into normalized condition types so callers cannot count captured discount, membership, or text-only card rows as normal prices.

Constraint: PR #253 review required TDD follow-up on feature/#252 without changing total_price sorting.\nRejected: Removing discount and membership from the whitelist | would lose Danawa condition labels already captured by the parser.\nConfidence: high\nScope-risk: narrow\nDirective: Keep payment_badge whitelist and payment_condition_types in sync whenever adding new badge classes or text keywords.\nTested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_danawa_price_search; live offers 75001853 --limit 5; npm run lint; npm run typecheck; npm run test; architect verification CLEAR.\nNot-tested: Danawa markup variants not represented by current live page or synthetic badge fixtures.
2026-05-15 17:33:48 +09:00
chanmin
5ff8859b2a fix(danawa-price-search): capture .ico.* payment-condition badges and surface as row labels
PR #226 row 파서에 결제조건 배지(`.ico.cash`/`.ico.point`/`.ico.coupon`/`.ico.card`) selector가 누락돼, 카드 결제 불가능한 현금/쿠폰/포인트 전용가가 일반 최저가로 노출되는 결함을 고친다.

- `offers()` row 파싱부에 결제조건 배지 화이트리스트 캡처 블록 추가 (클래스 `cash`/`point`/`coupon`/`discount`/`card`/`membership` 또는 텍스트 `현금`/`포인트`/`쿠폰`/`할인`만 인정 — 빠른배송/안내/상품리뷰 노이즈 차단)
- row dict 신규 필드 6개: `payment_badges`, `cash_only`, `point_only`, `coupon_only`, `card_only_badge`, `is_conditional_price`
- 반환 dict에 `normal_count`, `conditional_count` 추가
- `SKILL.md` / `docs/features/danawa-price-search.md` 갱신 (Output shape · Response style · Workflow · Failure modes에 결제조건 정책과 표 예시 명시)

정렬 정책은 그대로 `total_price` 단일 기준이며, 결제조건은 row 단위 플래그/라벨로만 노출해 호출자가 결제수단에 맞춰 직접 판단하도록 한다.

회귀 (pcode=75001853, 갤럭시 S25 256GB 자급제 `offers --limit 5`):
- 1위 킴스클럽 979,000원 / `cash_only=True` / `payment_badges=["현금"]`
- 2위 롯데ON 1,072,080원 / `cash_only=False` / `payment_badges=[]`
- 3~5위 일반가 row 모두 `payment_badges` 빈 리스트 (노이즈 0건)

Closes #252

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:12:23 +09:00
Jeffrey (Dongkyu) Kim
1476011e4f Preserve Daiso caller headers through Bearer stock lookup
Keep advanced caller headers on the authenticated stock endpoint while generated Bearer and X-DM-UID values remain authoritative. Document the degraded selPkupStr fallback order in skill and source docs so the public workflow matches the restored API surface.\n\nConstraint: PR #250 review required resilient Bearer-primary stock lookup plus selPkupStr fallback and header/body contract coverage.\nRejected: Replacing caller headers with only auth headers | It regressed tracing/test-control header pass-through.\nConfidence: high\nScope-risk: narrow\nDirective: Keep Authorization and X-DM-UID generated by the auth flow even when callers provide same-named headers.\nTested: node --test packages/daiso-product-search/test/index.test.js; npm test --workspace daiso-product-search; npm run lint --workspace daiso-product-search; node --test scripts/skill-docs.test.js; npm run ci; live lookupStoreProductAvailability smoke for 강남역2호점 / VT 리들샷 100.\nNot-tested: Forced live upstream repeated 403; covered by injected fixture tests.
2026-05-15 16:35:16 +09:00
arnold714
2641f43863 feat(daiso-product-search): replace blocked-API fallback with Bearer token auth
selStrPkupStck는 더 이상 차단 상태가 아니며, /api/auth/request로 비로그인 JWT를
발급받아 AES-128-CBC(키: PRE_AUTH_ENC_KEY)로 암호화한 Bearer 토큰으로 접근한다.
403 응답 시 토큰을 재발급해 1회 재시도한다. pickupEligibility(selPkupStr) 폴백
로직은 제거했다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 15:33:24 +09:00
Jeffrey (Dongkyu) Kim
6df974df36 docs(flight-ticket-search): register skill in README table and add feature guide
PR #224 머지 시 README "어떤 걸 할 수 있나" 표와 "포함된 기능" 리스트, 그리고
docs/features/flight-ticket-search.md 가이드가 등록되지 않아 main에 있는 다른
모든 스킬과 달리 사용자/에이전트가 README만 봐서는 이 스킬을 발견할 수 없는
상태였다. 누락분을 hotfix로 보강한다.

- README 표에 `flight-ticket-search` 행 추가 (마이리얼트립 옆 항공 클러스터)
- README "포함된 기능" 리스트에 가이드 링크 추가
- docs/features/flight-ticket-search.md 신규 작성:
  · 사용 시나리오, 구현 표면(fast-flights==2.2, 사용자 venv 격리)
  · search / compare-month / compare-range / compare-years CLI 예시
  · 응답 필드, IATA 입력 가이드, 예약 링크 정책
  · 검증된 노선 목록, 실패 모드, 비범위, 출처

검증:
- node --test scripts/skill-docs.test.js → 138/138 pass
- ./scripts/validate-skills.sh → skill layout looks valid

코드 변경 없음 → changeset 불필요.
2026-05-15 01:35:43 +09:00
Jeffrey (Dongkyu) Kim
8baf3adc23 Merge branch 'dev' into feature/#228 2026-05-15 00:19:51 +09:00
Jeffrey (Dongkyu) Kim
729a94071a
Merge pull request #241 from Romano1994/feat/seoul-density
Add seoul-density skill and proxy route for Seoul realtime hotspot crowd levels
2026-05-15 00:18:08 +09:00
Jeffrey (Dongkyu) Kim
641d96b8fc Harden NTS validate privacy boundary
Prevent proxy exception messages from exposing upstream URLs, align validate field bounds across proxy and Python helpers, and make the hosted validate privacy path explicit in docs.

Constraint: non-interactive PR #243 follow-up with no production DATA_GO_KR_API_KEY authority.

Rejected: returning raw upstream fetch errors | could leak serviceKey if custom fetch/proxy errors include full URLs.

Rejected: leaving helper-copy drift to manual cmp checks | behavior test now loads the skill-local helper directly.

Confidence: high

Scope-risk: narrow

Directive: keep validate uncached and avoid echoing representative/date/address inputs in proxy responses.

Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_nts_business_registration; npm run test --workspace k-skill-proxy -- --test-name-pattern 'NTS business'; mocked fetch-exception smoke; git diff --check origin/dev...HEAD; npm run ci

Not-tested: live data.go.kr calls, no production DATA_GO_KR_API_KEY authority
2026-05-14 22:20:33 +09:00
Jeffrey (Dongkyu) Kim
cd3366a9dc Route NTS business checks through the proxy
Add the NTS business registration skill and proxy endpoints so agents can verify business-number status and authenticity without exposing data.go.kr keys to users.\n\nConstraint: data.go.kr publicDataPk=15081808 requires a server-side API key, so the route belongs behind k-skill-proxy.\nRejected: caller-supplied service keys | would violate the proxy credential boundary and duplicate user setup.\nConfidence: high\nScope-risk: moderate\nDirective: Keep future NTS fields normalized at the proxy boundary and never accept client serviceKey overrides.\nTested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_nts_business_registration; npm run test --workspace k-skill-proxy -- --test-name-pattern 'NTS business'; buildServer smoke inject; npm run ci\nNot-tested: live data.go.kr request, because this session has no production DATA_GO_KR_API_KEY authority.
2026-05-14 21:40:26 +09:00
romano1994
315dbbb66b Add seoul-density skill and proxy route for Seoul realtime hotspot crowd levels 2026-05-14 15:37:54 +09:00
Jeffrey (Dongkyu) Kim
1d310eec39 Rebase Gangnam Unni search onto latest dev
Keep the Gangnam Unni package dry-run coverage while incorporating the latest dev validation scripts.\n\nConstraint: PR #233 became conflicting after dev advanced with ticket availability and Daangn skills.\nRejected: Taking either package script side wholesale | would drop either Gangnam Unni pack coverage or current dev test coverage.\nConfidence: high\nScope-risk: narrow\nDirective: Preserve additive root script checks for independently merged skills.\nTested: package.json JSON parse; git diff --check.\nNot-tested: Full npm run ci pending after merge commit.
2026-05-14 12:23:09 +09:00
Jeffrey (Dongkyu) Kim
3ccb44afda Constrain report fetch credentials
Scope caller-owned GitHub credentials to API requests, add exact-file contents fallback for known report fetches, and report actual inspected detail attempts. This tightens the public mirror boundary without adding proxy auth or broadening release metadata.

Constraint: public GitHub mirror remains keyless by default; optional caller tokens must stay least-privilege.

Rejected: forwarding GitHub auth headers to all GitHub-operated hosts | raw.githubusercontent.com does not need API credentials for the verified path.

Confidence: high

Scope-risk: narrow

Directive: Keep optional credentials host-scoped unless a future caller explicitly opts into raw-host forwarding.

Tested: npm run lint --workspace daishin-report-search; npm run test --workspace daishin-report-search; npm pack --workspace daishin-report-search --dry-run; npm run ci; injected raw/API header and contents fallback smoke; live exact-report and latest-list CLI smokes; architect/code-reviewer verification.

Not-tested: authenticated live GitHub token path with a real token.
2026-05-14 09:57:45 +09:00
Jeffrey (Dongkyu) Kim
3e1d3a21a2 Make report discovery failures actionable
Constraint: GitHub tree discovery is public and keyless by default, so latest/search must not require the proxy or a token.\nRejected: Proxying the public GitHub API | violates the repo no-proxy policy for fully public endpoints.\nConfidence: high\nScope-risk: narrow\nDirective: Keep caller-supplied GitHub tokens optional and never persist or echo request headers in source errors.\nTested: npm run lint --workspace daishin-report-search; npm run test --workspace daishin-report-search; npm pack --workspace daishin-report-search --dry-run; npm run ci; live CLI latest structured 403 smoke; live exact-report smoke; injected rate/header/entity smokes; architect verification CLEAR.\nNot-tested: Authenticated live latest search with a real GitHub token.
2026-05-14 09:45:50 +09:00
Jeffrey (Dongkyu) Kim
d48a962d91 Make Daishin reports discoverable from the public mirror
Constraint: Issue #228 requires a skill that discovers latest report pages from the provided GitHub Pages mirror and makes them agent-readable.\nRejected: Screen-scraping GitHub Pages directory listings | the GitHub recursive tree API is a more stable public index.\nConfidence: high\nScope-risk: narrow\nDirective: Keep this skill on public unauthenticated GitHub/raw endpoints unless upstream starts requiring an API key; do not add a proxy route for public pages.\nTested: npm run lint --workspace daishin-report-search; npm run test --workspace daishin-report-search; npm pack --workspace daishin-report-search --dry-run; npm run ci; live CLI list/detail smoke tests.\nNot-tested: Authenticated GitHub API higher-rate-limit path.
2026-05-14 09:19:28 +09:00
Jeffrey (Dongkyu) Kim
a5eb876511 Rebase ticket availability onto latest dev
Keep the ticket availability validation entries while incorporating the latest dev Daangn skill checks.\n\nConstraint: PR #234 became conflicting again after dev advanced.\nRejected: Taking dev package scripts unchanged | would drop ticket availability validation.\nConfidence: high\nScope-risk: narrow\nDirective: Preserve additive root script checks for independently merged skills.\nTested: package.json JSON parse; git diff --check.\nNot-tested: Full npm run ci pending after merge commit.
2026-05-14 00:57:09 +09:00
Jeffrey (Dongkyu) Kim
609f6150b5
Merge pull request #237 from taeyoung1005/feature/daangn-search-skills
feat: add Daangn search skills
2026-05-14 00:55:49 +09:00
Jeffrey (Dongkyu) Kim
3109b6684a Keep Daangn jobs detail resilient
Add an HTML metadata fallback because the public jobs detail _data route currently returns an empty response while the redirected public page still exposes read-only title/meta data.

Constraint: PR 237 must remain read-only and avoid proxy/auth additions for public Daangn surfaces
Rejected: Treating the 204 _data response as acceptable | it breaks the documented detail command
Confidence: high
Scope-risk: narrow
Directive: Keep Daangn jobs detail on public HTML/meta fallback unless a stable JSON detail surface is verified
Tested: npm run ci; live daangn_jobs.py search/detail smoke
Not-tested: authenticated or interactive Daangn actions, intentionally out of scope
2026-05-14 00:40:00 +09:00
Jeffrey (Dongkyu) Kim
45dcfd0897 Unblock ticket availability PR against current dev
Preserve the ticket availability checks while keeping the newer manus bundle CI additions from dev.\n\nConstraint: PR #234 was non-mergeable because root package scripts changed on both head and dev.\nRejected: Taking either side wholesale | would drop either ticket availability validation or manus bundle validation.\nConfidence: high\nScope-risk: narrow\nDirective: Keep root lint/test script additions additive when merging independent skills.\nTested: node JSON parse for package.json; git diff --check.\nNot-tested: Full npm run ci pending after merge commit.
2026-05-14 00:38:28 +09:00
Jeffrey (Dongkyu) Kim
860bf53ed3 Unblock Gangnam Unni PR against current dev
Preserve the PR's workspace release coverage while keeping the newer manus bundle test entry from dev.\n\nConstraint: PR #233 was non-mergeable because package.json changed on both head and dev.\nRejected: Taking either side wholesale | would drop either gangnamunni pack coverage or manus bundle test coverage.\nConfidence: high\nScope-risk: narrow\nDirective: Keep additive package script conflicts merged rather than replacing workspace entries.\nTested: node JSON parse for package.json; git diff --check.\nNot-tested: Full npm run ci pending after merge commit.
2026-05-14 00:36:55 +09:00
Jeffrey (Dongkyu) Kim
49bf262bb9 Route shared key APIs through the proxy
Move KOSIS general lookups and Kakao Local geocoding behind k-skill-proxy so users do not need to manage those API keys for common skill flows. Keep KOSIS bigdata/direct calls user-keyed because userStatsId is account-specific.

Constraint: Free API proxy policy allows proxying upstreams that require API keys while keeping routes narrow, cache-backed, and public.

Rejected: Proxy ODsay transit routing | Basic quota is low, time-limited, and IP-whitelist-bound, so centralizing it would create quota and operations risk.

Confidence: high

Scope-risk: moderate

Directive: Keep KOSIS bigdata direct unless a per-user credential design is added; do not route broad Kakao surfaces without explicit allowlists and rate limits.

Tested: npm run ci; local KOSIS proxy smoke via /v1/kosis/search and /v1/kosis/meta; local Kakao proxy smoke via /v1/kakao-local/geocode q=서울역.

Not-tested: Production proxy deployment after main merge/cron update.
2026-05-13 16:31:29 +09:00
TaeyoungPark
95d5e9d05b docs: document Daangn search skills 2026-05-13 16:01:42 +09:00
Jeffrey (Dongkyu) Kim
34127550fa Let intercity booking helper create temporary seat holds
Extend the Tmoney intercity helper from read-only timetable lookup to the browser-equivalent seat-stage and temporary hold flow, saving the official card-information page and cancel/back fields while still avoiding card submission.

Constraint: readPcpySats.do creates a live sats_Pcpy_Id hold, so abandoned test holds must be released with the official pcpyCanc=C back flow.

Rejected: Automating final payment | card submission is irreversible and remains a manual user action.

Confidence: high

Scope-risk: narrow

Directive: Treat holds as short-lived; hand off immediately and cancel abandoned holds.

Tested: python3 -m py_compile intercity-bus-booking/scripts/intercity_bus_search.py ~/.agents/skills/intercity-bus-booking/scripts/intercity_bus_search.py; live --hold-first-seat for 동서울→속초 20260520 produced sats_Pcpy_Id and card-info page; posted cancel/back fields and verified timetable remained 24/28; ./scripts/validate-skills.sh; node --test scripts/skill-docs.test.js; npm run lint

Not-tested: card info entry, final payment, mixed passenger hold payloads
2026-05-13 15:43:26 +09:00
Jeffrey (Dongkyu) Kim
b4aae5b295 Make intercity timetable lookup follow Tmoney form contract
Add a read-only timetable helper that starts a cookie-backed Tmoney session, submits the hidden browser fields required by readAlcnList.do, and parses readSasFeeInf schedule rows into JSON.

Constraint: Tmoney returns a generic errorCont page unless bef_Aft_Dvs and req_Rec_Num are posted with the timetable form.

Rejected: Browser automation-first lookup | official HTTP flow works when the browser-submitted hidden fields are included.

Confidence: high

Scope-risk: narrow

Directive: Do not automate final card submission or payment from this skill without explicit user confirmation.

Tested: python3 -m py_compile intercity-bus-booking/scripts/intercity_bus_search.py; python3 intercity-bus-booking/scripts/intercity_bus_search.py --depart-code 0511601 --arrive-code 2482701 --depart-name 동서울 --arrive-name 속초 --date 20260520 --limit 1; rsync to ~/.claude/skills and ~/.agents/skills; ./scripts/validate-skills.sh; node --test scripts/skill-docs.test.js; npm run lint

Not-tested: temporary seat hold, cancellation, card entry, and payment flows
2026-05-13 14:49:22 +09:00
Hybirdss
83079cd4c8 feat(ticket-availability): YES24·인터파크 공연 일정·잔여석 조회 (조회 전용)
- 공개 endpoint (YES24 axPerfDay/PlayTime/RemainSeat, 인터파크 playSeq/REMAINSEAT) 만 단일 HTTP 호출
- httpx only, CloakBrowser/Playwright 없음, 로그인·시크릿·쿠키 없음
- 예매·결제·좌석 선택·자동화 의도적 제외 (공연법 §4조의2 매크로 부정구매 형사처벌)
- 20 unit test (mocked httpx) + validate-skills.sh PASS
- README + docs/features 가이드 추가
2026-05-13 02:50:26 +09:00
Jeffrey (Dongkyu) Kim
da0632c73d Enable public Gangnam Unni clinic lookup
Add a read-only Gangnam Unni search skill and npm helper that parses the public Next.js search payload, documents the discovered access path, and keeps login/app-only medical actions out of scope.\n\nConstraint: Issue #220 requested a Gangnam Unni plastic-surgery clinic lookup skill with TDD and PR delivery.\nRejected: Proxy route | upstream is an unauthenticated public web surface, so proxy policy says direct user-machine calls.\nConfidence: high\nScope-risk: narrow\nDirective: Keep this skill read-only; do not add login, booking, consultation, payment, or medical-advice automation.\nTested: npm test --workspace gangnamunni-clinic-search; live CLI search for "강남 성형외과"; npm run ci twice after implementation/deslop review.\nNot-tested: Logged-in/app-only Gangnam Unni flows, intentionally out of scope.
2026-05-13 01:49:16 +09:00
Jeffrey (Dongkyu) Kim
3e22a78bf3
Merge pull request #225 from taeyoung1005/feat/korean-bus-booking-skills
한국 고속버스·시외버스 예매 스킬 추가
2026-05-12 19:20:22 +09:00
Jeffrey (Dongkyu) Kim
568a4453b9
Merge pull request #226 from taeyoung1005/feat/danawa-price-search
feat: 다나와 최저가 비교 스킬 추가
2026-05-12 19:18:43 +09:00
Jeffrey (Dongkyu) Kim
552e5c646b
Merge pull request #229 from taeyoung1005/feat/myrealtrip-mcp-search
마이리얼트립 MCP 검색 스킬 추가
2026-05-12 19:17:16 +09:00