@nomadamas/k-skill 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomadamas/k-skill",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "k-skill unified CLI: assembles runtime-aware skill instructions and ships bundled helper files",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -36,7 +36,7 @@ npx -y @nomadamas/k-skill@0 exec k-skill-cleaner scripts/k_skill_cleaner.py -- \
36
36
  --skills-root . \
37
37
  --scan-default-logs \
38
38
  --days 90 \
39
- --never-use blue-ribbon-nearby,lotto-results \
39
+ --never-use lotto-results,market-kurly-search \
40
40
  --keep k-skill-setup,k-skill-cleaner
41
41
  ```
42
42
 
@@ -2,184 +2,164 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- 전체 `k-skill` 설치가 끝난 뒤, 공통 후속 작업을 처리한다.
5
+ `k-skill` 스킬 설치부터 CLI 런타임, credential, 환경 검증까지 한 번에 정리한다.
6
+ 이미 설치된 항목은 확인만 하고 건너뛴다.
6
7
 
7
- - credential 확보 (에이전트 vault 또는 기본 secrets.env)
8
- - 런타임 환경변수 확인
9
- - 선택 사항: 주기적인 업데이트 확인 자동화
10
- - 선택 사항: GitHub star 여부 확인 및 동의 시 실행
8
+ 기본 원칙:
11
9
 
12
- 스킬의 기본 정책:
10
+ - Node.js 18 이상과 `npx`를 사용한다.
11
+ - credential은 환경변수, agent vault, `~/.config/k-skill/secrets.env` 순으로 확인한다.
12
+ - Dolshoi credential mode에서는 평문 credential을 요청하거나 파일에 직접 저장하지 않는다.
13
+ - 설치, 예약 작업, GitHub star처럼 외부 상태를 바꾸는 작업은 실행 전에 동의를 받는다.
14
+ - 사용자가 승인한 범위만 실행하고 별도 helper, 요약, AI/CLI 예약 작업을 추가하지 않는다.
13
15
 
14
- - 시크릿이 없으면 필요한 값 이름을 사용자에게 정확히 알려준다
15
- - credential resolution order에 따라 확보한다
16
- - 필요한 패키지가 없으면 대체 구현을 찾기보다 전역 설치를 먼저 시도한다
17
- - `cron`, `launchd`, `schtasks`, `gh` 같은 지속성/외부 상태 변경은 자동으로 하지 말고 먼저 사용자 동의를 받는다
18
- - GitHub star는 사용자가 명시적으로 동의했을 때만 실행한다
16
+ ## 1. Install the skills
19
17
 
20
- ## Dolshoi-first runtime policy
18
+ 일반적인 Claude Code, Codex, OpenCode, OpenClaw 등에서는 `skills` CLI로 전체 스킬을
19
+ 전역 설치하는 경로를 권장한다.
21
20
 
22
- 돌쇠는 credential, browser, action을 서로 독립적인 capability로 감지한다.
23
-
24
- 1. `DOLSHOI_ACTION_BROKER_URL`과 실행 가능한 `vault-run`이 모두 있으면 credential action mode다.
25
- 2. 필요한 login capability가 이미 provision되어 있으면 `vault-run <capability_id> <action> [args...]`를 사용한다.
26
- 3. capability가 없으면 username/password/key를 채팅으로 묻지 말고 `request_vault_credential` tool로 앱 vault 입력 UI를 호출한다.
27
- 4. 내장 browser tool이 CloakBrowser를 제공하거나 `CLOAKBROWSER_PEEK_TOKEN`이 있으면 browser action은 CloakBrowser를 우선한다.
28
- 5. 조회 결과가 실제 action의 입력이면 공식 표면에서 장바구니, 예약, 신청서 작성, 연락 초안 등 가역적 단계를 이어서 수행한다.
29
- 6. 결제, 실제 메시지/메일 전송, 최종 제출, 취소 같은 비가역 효과 직전에만 `clarify`로 대상·금액/payload·효과를 승인받고, 승인되면 같은 turn에 실행한다.
21
+ ```bash
22
+ npx --yes skills add NomaDamas/k-skill --all -g
23
+ ```
30
24
 
31
- ## Generic credential resolution order
25
+ 목록을 먼저 보거나 일부 스킬만 설치하려면:
32
26
 
33
- 돌쇠 credential mode가 아닐 때만 아래 portable fallback을 따른다.
27
+ ```bash
28
+ npx --yes skills add NomaDamas/k-skill --list
29
+ npx --yes skills add NomaDamas/k-skill --skill <skill-name> -g
30
+ ```
34
31
 
35
- 1. **이미 환경변수에 있으면** 그대로 사용한다.
36
- 2. **에이전트가 자체 secret vault(1Password CLI, Bitwarden CLI, macOS Keychain 등)를 사용 중이면** 거기서 꺼내 환경변수로 주입해도 된다.
37
- 3. **`~/.config/k-skill/secrets.env`** (기본 fallback) — plain dotenv 파일, 퍼미션 `0600`.
38
- 4. **아무것도 없으면** 유저에게 물어서 2 또는 3에 저장한다.
32
+ Claude Code에서는 marketplace plugin으로 전체 번들을 설치하는 경로도 지원한다.
33
+ Claude Code 안에서 다음 명령을 실행한다.
39
34
 
40
- 기본 경로에 저장하는 것은 fallback일 뿐, 강제가 아니다.
35
+ ```text
36
+ /plugin marketplace add NomaDamas/k-skill
37
+ /plugin install k-skill@k-skill
38
+ ```
41
39
 
42
- ## Standard file location
40
+ plugin으로 설치한 스킬은 `/k-skill:<스킬 이름>`으로 호출한다.
41
+ 예: `/k-skill:k-skill-setup`, `/k-skill:lotto-results`.
43
42
 
44
- - secrets file (기본 fallback): `~/.config/k-skill/secrets.env`
43
+ 설치 방식을 중복 실행할 필요는 없다. 현재 agent에서 스킬이 이미 보이면 설치를
44
+ 다시 하지 말고 다음 단계로 진행한다.
45
45
 
46
- ## Install
46
+ ## 2. Use the k-skill CLI
47
47
 
48
- 스킬은 `k-skill` 전체 스킬 설치가 끝난 실행하는 것을 기본으로 한다.
48
+ 설치되는 `SKILL.md`는 스킬 선택과 최소 안전 규칙을 담은 adapter다. 전체 instruction
49
+ 조립과 bundled `scripts/`, `references/` 접근은 `@nomadamas/k-skill` CLI가 담당한다.
49
50
 
50
- 예:
51
+ 기본 경로는 `npx`이며 CLI를 별도로 설치할 필요는 없다.
51
52
 
52
53
  ```bash
53
- npx --yes skills add <owner/repo> --all -g
54
+ npx -y @nomadamas/k-skill@0 instruct k-skill-setup
55
+ npx -y @nomadamas/k-skill@0 list
54
56
  ```
55
57
 
56
- 설치가 끝나면 스킬을 호출해 아래 setup 단계를 이어간다.
57
-
58
- ## Setup steps
59
-
60
- ### 1. Create the default secrets file (generic fallback only)
61
-
62
- 돌쇠 credential mode나 다른 host vault를 쓰지 않는 경우에만 기본 fallback 파일을 만든다.
58
+ 반복 사용으로 전역 명령이 필요할 때만 선택적으로 설치한다.
63
59
 
64
60
  ```bash
65
- mkdir -p ~/.config/k-skill
66
- cat > ~/.config/k-skill/secrets.env <<'EOF'
67
- KSKILL_SRT_ID=replace-me
68
- KSKILL_SRT_PASSWORD=replace-me
69
- KSKILL_KTX_ID=replace-me
70
- KSKILL_KTX_PASSWORD=replace-me
71
- KSKILL_FORESTTRIP_ID=replace-me
72
- KSKILL_FORESTTRIP_PASSWORD=replace-me
73
- KSKILL_EV_CHARGER_API_KEY=replace-me
74
- KSKILL_BUILDING_REGISTER_API_KEY=replace-me
75
- KSKILL_RISS_API_KEY=replace-me
76
- LAW_OC=replace-me
77
- KIPRIS_PLUS_API_KEY=replace-me
78
- AIR_KOREA_OPEN_API_KEY=replace-me
79
- KSKILL_PROXY_BASE_URL=
80
- EOF
81
- chmod 0600 ~/.config/k-skill/secrets.env
61
+ npm install -g @nomadamas/k-skill@0
62
+ k-skill instruct k-skill-setup
82
63
  ```
83
64
 
84
- 호스트가 제공하는 가장 안전한 입력 표면으로 실제 값을 받아 채운다. 돌쇠에서는 이 파일을 만들거나 평문 값을 묻지 않는다.
65
+ bundled helper와 reference는 항상 CLI를 통해 사용한다.
85
66
 
86
- 서울 지하철 도착정보, 서울 실시간 혼잡도 조회, 서울 따릉이 실시간 대여소 조회, 한국 날씨, 미세먼지, 한강 수위, 주유소 가격, 생활쓰레기 배출정보 조회, 학교 급식 식단 조회, 의약품 안전 체크, 식품 안전 체크는 `KSKILL_PROXY_BASE_URL` 을 비워 두면 기본 hosted path(`k-skill-proxy.nomadamas.org`)를 그대로 쓴다. 전기차 충전소와 건축물대장 표제부 조회도 같은 기본 hosted path를 쓴다. 별도 self-host proxy를 쓸 때만 `KSKILL_PROXY_BASE_URL` 을 채운다.
87
-
88
- 한국 법령 검색은 기본 hosted proxy(`k-skill-proxy.nomadamas.org`)의 `/v1/korean-law/...` endpoint를 경유하므로 사용자 쪽 `LAW_OC` 가 불필요하다. self-host proxy 운영자만 서버 환경변수 `LAW_OC` 를 채운다(무료 발급: `https://open.law.go.kr`).
89
-
90
- 한국 부동산 실거래가 조회는 기본 hosted proxy(`k-skill-proxy.nomadamas.org`)를 경유하므로 사용자 쪽 `DATA_GO_KR_API_KEY` 가 불필요하다.
67
+ ```bash
68
+ npx -y @nomadamas/k-skill@0 exec <skill-name> scripts/<file> -- <args>
69
+ npx -y @nomadamas/k-skill@0 read <skill-name> references/<file>
70
+ ```
91
71
 
92
- 한국 주식 정보 조회는 기본 hosted proxy(`k-skill-proxy.nomadamas.org`)경유하므로 사용자 쪽 `KRX_API_KEY` 가 불필요하다. self-host proxy 운영자만 서버 환경변수 `KRX_API_KEY` 를 사용한다.
72
+ 설치된 스킬 디렉터리나 repository 상대 경로에서 helper직접 실행하지 않는다.
93
73
 
94
- 도서관 도서 조회는 기본 hosted proxy(`k-skill-proxy.nomadamas.org`)를 경유하므로 사용자 쪽 `DATA4LIBRARY_AUTH_KEY` 가 불필요하다. self-host proxy 운영자만 서버 환경변수 `DATA4LIBRARY_AUTH_KEY` 를 사용한다.
74
+ ## 3. Resolve credentials
95
75
 
96
- 생활쓰레기 배출정보 조회는 `k-skill-proxy`의 `/v1/household-waste/info` 라우트를 호출하고, `serviceKey`(`DATA_GO_KR_API_KEY`)는 proxy 서버에서 주입/관리하므로 사용자 쪽 `DATA_GO_KR_API_KEY` 가 불필요하다.
76
+ 스킬이 요구하는 값만 준비한다. 모든 credential을 미리 요구하지 않는다.
97
77
 
98
- 학교 급식 식단 조회는 `k-skill-proxy`의 `/v1/neis/school-search`·`/v1/neis/school-meal`을 호출하고, `KEDU_INFO_KEY`는 프록시 서버에만 두므로 사용자 쪽에 둘 필요가 없다.
78
+ credential resolution order:
99
79
 
100
- 도서관 도서 조회는 `k-skill-proxy`의 `/v1/data4library/*` 라우트를 호출하고, `DATA4LIBRARY_AUTH_KEY`는 프록시 서버에만 두므로 사용자 쪽에 둘 필요가 없다.
80
+ 1. 현재 프로세스 환경변수
81
+ 2. agent가 제공하는 secret vault
82
+ 3. 기본 fallback `~/.config/k-skill/secrets.env`
83
+ 4. 필요한 값이 없으면 정확한 환경변수 이름과 발급처를 안내
101
84
 
102
- 근처 가장 싼 주유소 찾기는 기본 hosted proxy를 경유하므로 사용자 쪽 `OPINET_API_KEY` 가 불필요하다.
85
+ Dolshoi credential mode:
103
86
 
104
- 의약품 안전 체크는 `k-skill-proxy`의 `/v1/mfds/drug-safety/lookup` 라우트를 호출하고, `DATA_GO_KR_API_KEY` 프록시 서버에서만 주입/관리하므로 사용자 쪽에 둘 필요가 없다.
87
+ - `DOLSHOI_ACTION_BROKER_URL`과 usable `vault-run`이 모두 있을 때만 활성화한다.
88
+ - plaintext credential을 묻거나 출력하거나 `secrets.env`를 만들지 않는다.
89
+ - 필요한 credential이 없으면 `request_vault_credential`을 사용한다.
105
90
 
106
- 식품 안전 체크는 `k-skill-proxy`의 `/v1/mfds/food-safety/search` 라우트를 호출하고, `DATA_GO_KR_API_KEY` 및 선택적 `FOODSAFETYKOREA_API_KEY` 는 프록시 서버에서만 주입/관리하므로 사용자 쪽에 둘 필요가 없다.
91
+ Generic mode에서 fallback 파일이 필요하면:
107
92
 
108
- 창업진흥원 K-Startup 조회는 `k-skill-proxy`의 `/v1/kstartup/*` 라우트를 호출하고, `ServiceKey`(`DATA_GO_KR_API_KEY`)는 프록시 서버에서만 주입/관리하므로 일반 조회는 사용자 쪽에 키가 필요 없다. `--direct` 호출을 쓸 때만 `KSKILL_KSTARTUP_API_KEY` 를 채운다.
93
+ ```bash
94
+ mkdir -p ~/.config/k-skill
95
+ touch ~/.config/k-skill/secrets.env
96
+ chmod 0600 ~/.config/k-skill/secrets.env
97
+ ```
109
98
 
110
- 전기차 충전소 조회는 `k-skill-proxy`의 `/v1/ev-charger/info`·`/v1/ev-charger/status`를 호출하므로 일반 사용자는 키가 필요 없다. `--direct`에서만 `KSKILL_EV_CHARGER_API_KEY` 또는 `DATA_GO_KR_API_KEY`를 사용하고, 데이터셋 `15076352` 활용신청은 별도로 해야 한다(자동승인).
99
+ 실제 값은 사용자가 이용 중인 가장 안전한 입력 표면으로 받는다. 대화에 평문 값을
100
+ 붙여 넣도록 요구하지 않는다.
111
101
 
112
- 건축물대장 표제부 조회는 `k-skill-proxy`의 `/v1/building-register/title`을 호출하므로 일반 사용자는 키가 필요 없다. 주소 입력은 같은 proxy의 Kakao geocode먼저 사용한다. `--direct`에서만 `KSKILL_BUILDING_REGISTER_API_KEY` 또는 `DATA_GO_KR_API_KEY`를 사용하고 데이터셋 `15134735` 활용신청을 별도로 해야 한다(자동승인).
102
+ `KSKILL_PROXY_BASE_URL`을 비워 두면 `k-skill-proxy` 기반 스킬은 기본 hosted endpoint를 사용한다.
103
+ 사용자가 직접 운영하는 proxy가 있을 때만 URL을 설정한다.
113
104
 
114
- KERIS/RISS 학술자료 검색은 RISS 검색 API가 기관 전용 키를 요구해 `k-skill-proxy`를 거치지 않는다. 사용자가 직접 발급받은 `KSKILL_RISS_API_KEY`(호환 `RISS_API_KEY`)를 설정해 상류를 호출한다. RISS 키는 비영리 기관/대학에만 발급되며 RISS 검색에는 `DATA_GO_KR_API_KEY`를 사용하지 않는다.
105
+ ```bash
106
+ KSKILL_PROXY_BASE_URL=
107
+ # KSKILL_PROXY_BASE_URL=https://your-proxy.example.com
108
+ ```
115
109
 
116
- 한국 특허 정보 검색은 KIPRIS Plus Open API 경로를 쓸 때 `KIPRIS_PLUS_API_KEY` 채운다. helper는 이 값을 읽어 실제 요청에서 `ServiceKey` 쿼리 파라미터로 보낸다. 공공데이터포털에서 복사한 percent-encoded key도 그대로 넣어도 된다.
110
+ 무료 hosted proxy로 처리되는 기능에는 사용자 upstream API key요구하지 않는다.
111
+ 로그인 기반 스킬은 해당 스킬의 공식 로그인/browser 절차를 따르며 credential을
112
+ `secrets.env`에 복사하도록 요구하지 않는다.
117
113
 
118
- ### Missing secret response template
114
+ Hosted proxy 기본 계약:
119
115
 
120
- 인증 스킬에서 값이 빠졌을 때는 credential resolution order에 따라 확보한다.
116
+ - 미세먼지, 한강 수위, 주유소 가격, 생활쓰레기 배출정보 조회, 학교 급식 식단 조회, 의약품 안전 체크, 식품 안전 체크는 `KSKILL_PROXY_BASE_URL`을 비워 두면 기본 hosted endpoint를 사용한다.
117
+ - 서울 지하철: 사용자 시크릿 불필요 (기본 hosted proxy 사용, 운영자만 `SEOUL_OPEN_API_KEY`).
118
+ - 생활쓰레기 배출정보 조회: 사용자 시크릿 불필요. `/v1/household-waste/info`와 운영자 서버의 `DATA_GO_KR_API_KEY`를 사용한다.
119
+ - 학교 급식 식단 조회: 사용자 시크릿 불필요. `/v1/neis/school-search`, `/v1/neis/school-meal`과 운영자 서버의 `KEDU_INFO_KEY`를 사용한다.
120
+ - 한국 법령 검색은 기본 hosted proxy를 사용하며, 운영자만 서버 환경변수 `LAW_OC`를 설정한다.
121
+ - 한국 특허 정보 검색: `KIPRIS_PLUS_API_KEY`는 운영자 서버에만 둔다.
122
+ - 한국 주식 정보 조회는 proxy가 운영자 `KRX_API_KEY`를 사용하므로 사용자 키가 불필요하다.
123
+ - 부동산 실거래가 조회와 주유소 가격 조회도 hosted proxy 기본 경로에서는 사용자 upstream key가 불필요하다.
121
124
 
122
- 필요한 예:
125
+ ## 4. Verify the setup
123
126
 
124
- - SRT: `KSKILL_SRT_ID`, `KSKILL_SRT_PASSWORD`
125
- - KTX: `KSKILL_KTX_ID`, `KSKILL_KTX_PASSWORD`
126
- - 자연휴양림 빈 객실 조회: `KSKILL_FORESTTRIP_ID`, `KSKILL_FORESTTRIP_PASSWORD`
127
- - 한국 법령 검색: 사용자 시크릿 불필요 (기본 hosted proxy 사용, 운영자만 `LAW_OC`)
128
- - 한국 부동산 실거래가 조회: 사용자 시크릿 불필요 (기본 hosted proxy 사용)
129
- - 한국 특허 정보 검색: `KIPRIS_PLUS_API_KEY`
130
- - 한국 주식 정보 조회: 사용자 시크릿 불필요 (기본 hosted proxy 사용, 운영자만 `KRX_API_KEY`)
131
- - 생활쓰레기 배출정보 조회: 사용자 시크릿 불필요 (`serviceKey`는 proxy 서버 주입, 호출 시 `pageNo=1`·`numOfRows=100` 필수)
132
- - 학교 급식 식단 조회: 사용자 시크릿 불필요 (`KEDU_INFO_KEY`는 proxy 서버만)
133
- - 도서관 도서 조회: 사용자 시크릿 불필요 (`DATA4LIBRARY_AUTH_KEY`는 proxy 서버만)
134
- - 의약품 안전 체크: 사용자 시크릿 불필요 (`DATA_GO_KR_API_KEY`는 proxy 서버만)
135
- - 식품 안전 체크: 사용자 시크릿 불필요 (`DATA_GO_KR_API_KEY`와 선택적 `FOODSAFETYKOREA_API_KEY`는 proxy 서버만)
136
- - 창업진흥원 K-Startup 조회: 사용자 시크릿 불필요 (`DATA_GO_KR_API_KEY`는 proxy 서버만; `--direct` 호출 때만 `KSKILL_KSTARTUP_API_KEY`)
137
- - 전기차 충전소 위치·상태 조회: 사용자 시크릿 불필요 (hosted proxy 사용; `--direct` 때만 `KSKILL_EV_CHARGER_API_KEY` 또는 `DATA_GO_KR_API_KEY`)
138
- - 건축물대장 표제부 조회: 사용자 시크릿 불필요 (hosted proxy 사용; `--direct` 때만 `KSKILL_BUILDING_REGISTER_API_KEY` 또는 `DATA_GO_KR_API_KEY`)
139
- - KERIS/RISS 학술자료 검색: 사용자 본인 `KSKILL_RISS_API_KEY`(호환 `RISS_API_KEY`) 필요 (RISS 검색 API는 비영리 기관/대학 전용 키로 직접 호출, proxy 미사용)
140
- - 근처 가장 싼 주유소 찾기: 사용자 시크릿 불필요 (기본 hosted proxy 사용)
141
- - 서울 지하철: 사용자 시크릿 불필요 (기본 hosted proxy 사용, 운영자만 `SEOUL_OPEN_API_KEY`)
142
- - 서울 실시간 혼잡도: 사용자 시크릿 불필요 (기본 hosted proxy 사용, 운영자만 `SEOUL_OPEN_API_KEY`)
143
- - 한국 날씨: 사용자 시크릿 불필요 (기본 hosted proxy 사용, 운영자만 `KMA_OPEN_API_KEY`)
144
- - 사용자 위치 미세먼지 조회: `KSKILL_PROXY_BASE_URL` 또는 `AIR_KOREA_OPEN_API_KEY`
127
+ bundled 검증 helper를 CLI로 실행한다.
145
128
 
146
- 시크릿이 비어 있다는 이유로 다른 서비스나 비공식 우회 경로를 자동 선택하지 않는다.
129
+ ```bash
130
+ npx -y @nomadamas/k-skill@0 exec k-skill-setup scripts/check-setup.sh --
131
+ ```
147
132
 
148
- ### 2. Verify runtime environment
133
+ Generic mode에서 `secrets.env`가 필요하지 않은 구성이라면 파일 부재 자체를 전체 설치
134
+ 실패로 단정하지 않는다. 실제 사용할 스킬의 필수 환경변수와 CLI 실행 가능 여부를 함께
135
+ 확인한다.
149
136
 
150
- 스킬은 `SKILL.md` 단일 파일로 설치될 수 있으므로 별도 스크립트 파일에 의존하지 않고 아래 검증을 직접 실행한다.
137
+ 최소 확인:
151
138
 
152
139
  ```bash
153
- secrets_file="$HOME/.config/k-skill/secrets.env"
154
- if [ ! -f "$secrets_file" ]; then
155
- echo "missing secrets file: $secrets_file"
156
- echo "next steps:"
157
- echo " 1. create ~/.config/k-skill/secrets.env with your credentials"
158
- echo " 2. chmod 0600 ~/.config/k-skill/secrets.env"
159
- else
160
- perms=$(stat -f '%Lp' "$secrets_file" 2>/dev/null || stat -c '%a' "$secrets_file" 2>/dev/null)
161
- if [ "$perms" != "600" ]; then
162
- echo "insecure permissions on $secrets_file: $perms (expected 600)"
163
- echo "run: chmod 0600 $secrets_file"
164
- else
165
- echo "k-skill setup looks usable"
166
- fi
167
- fi
140
+ node --version
141
+ npx -y @nomadamas/k-skill@0 list
142
+ npx -y @nomadamas/k-skill@0 instruct k-skill-setup
168
143
  ```
169
144
 
170
- repo 전체를 clone받은 경우에는 같은 검증을 `npx -y @nomadamas/k-skill@0 exec k-skill-setup scripts/check-setup.sh --` 로 실행해도 된다.
145
+ 확인이 끝나면 다음만 짧게 보고한다.
171
146
 
172
- ### 3. Offer scheduled update checks
147
+ - 사용한 스킬 설치 방식 (`skills` 또는 Claude Code plugin)
148
+ - CLI 사용 방식 (`npx` 기본 또는 선택적 global install)
149
+ - 준비된 credential과 아직 필요한 환경변수 이름
150
+ - 검증 성공/실패와 사용자가 해야 할 다음 한 단계
173
151
 
174
- setup이 끝나면 사용자에게 주기적인 업데이트 확인 자동화를 원하는지 먼저 묻는다. 원하지 않으면 건너뛴다.
152
+ ## 5. Optional update checks
175
153
 
176
- 기본 정책:
154
+ 주기적인 업데이트 확인을 원하는지 먼저 묻는다. 원하지 않으면 건너뛴다.
177
155
 
178
- - 자동 설치가 아니라 `업데이트 확인` 만 기본으로 제안한다
179
- - 지속성 있는 시스템 변경(`crontab`, `launchd`, `schtasks`)은 동의 없이 적용하지 않는다
180
- - 기본 확인 명령은 `npx --yes skills check`
181
- - 사용자가 명시적으로 `자동 업데이트` 를 원할 때만 `npx --yes skills update` 기반 스케줄을 별도로 제안한다
182
- - 주의: `skills` CLI 버전에 따라 `check`에 `-g` 같은 옵션을 붙이면 확인을 넘어 설치본을 덮어쓸 수 있다. 자동화 스크립트에는 옵션 없는 `npx --yes skills check` 만 사용하고, 실제 업데이트 적용은 사용자가 검토 직접 실행하도록 안내한다
156
+ 정책:
157
+
158
+ - 기본 명령은 설치를 변경하지 않는 `npx --yes skills check`다.
159
+ - `check`에 `-g` 같은 추가 옵션을 붙이지 않는다.
160
+ - 자동 업데이트는 사용자가 명시적으로 요청한 경우에만 별도로 논의한다.
161
+ - 사용자가 승인한 확인 작업만 생성한다.
162
+ - 별도 요약 작업, helper script, `claude -p` 같은 AI/CLI 작업을 함께 만들지 않는다.
183
163
 
184
164
  macOS / Linux 예시:
185
165
 
@@ -210,44 +190,21 @@ npx --yes skills check >> "$HOME/.config/k-skill/logs/skills-check.log" 2>&1
210
190
  schtasks /Create /SC DAILY /TN "k-skill-update-check" /TR "\"$HOME/.config/k-skill/bin/check-skill-updates.cmd\"" /ST 09:00 /F
211
191
  ```
212
192
 
213
- 설정 후에는 로그 위치를 짧게 알려준다:
214
-
215
- - `~/.config/k-skill/logs/skills-check.log`
193
+ 사용자가 확인 작업 하나만 승인했다면 `k-skill-update-check` 외의 예약 작업이나
194
+ 추가 스크립트를 만들지 않는다.
216
195
 
217
- ### 4. Offer GitHub starring with explicit consent
196
+ ## 6. Optional GitHub star
218
197
 
219
- setup 마지막에는 다음처럼 짧게 묻는다.
198
+ 마지막에 번만 묻는다.
220
199
 
221
200
  ```text
222
201
  k-skill 저장소(NomaDamas/k-skill)에 GitHub star를 눌러드릴까요?
223
- 원하시면 `gh` 로 바로 처리하고, 원하지 않으면 건너뜁니다.
224
202
  ```
225
203
 
226
- 규칙:
227
-
228
- - 사용자가 명시적으로 동의하기 전에는 star API를 호출하지 않는다
229
- - `gh` 가 없거나 인증되지 않았으면 설치/로그인 안내만 하고 자동 우회하지 않는다
230
- - star 대상 저장소는 `NomaDamas/k-skill` 이다
231
-
232
- 동의했고 `gh auth status` 가 정상이면 GitHub API로 star를 실행한다. (`gh` CLI에는 `repo star` 서브커맨드가 없다.)
204
+ 동의한 경우에만 실행한다.
233
205
 
234
206
  ```bash
235
- # 이미 star 여부 확인: 204 = 이미 star, 404 = 아직
236
- gh api user/starred/NomaDamas/k-skill >/dev/null 2>&1 && echo "already starred" || echo "not starred yet"
237
-
238
- # star 실행
239
- gh api -X PUT user/starred/NomaDamas/k-skill
207
+ gh api -X PUT /user/starred/NomaDamas/k-skill
240
208
  ```
241
209
 
242
- 성공하면 짧게 완료만 알린다.
243
-
244
- ## Completion checklist
245
-
246
- - `~/.config/k-skill/secrets.env` exists with permission `0600` (또는 에이전트가 자체 vault로 credential을 관리 중)
247
- - 필요한 환경변수가 설정되어 있다
248
- - 사용자가 원한 경우에만 업데이트 확인 자동화 또는 GitHub star가 설정되었다
249
-
250
- ## Notes
251
-
252
- - 기본 흐름은 "전체 스킬 설치 → 이 setup skill 실행 → 개별 기능 사용" 이다
253
- - 저장소 안에는 secret file을 두지 않는다
210
+ 동의하지 않거나 `gh` 인증이 없으면 건너뛴다.
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "k-skill-setup",
3
- "description": "After installing the full k-skill bundle, configure and verify the shared cross-platform setup, then optionally wire update checks and GitHub starring with explicit user consent.",
3
+ "description": "Install the k-skill bundle, use the unified CLI, resolve credentials, verify the runtime, and optionally configure update checks and GitHub starring.",
4
4
  "profiles": [
5
5
  "proxy",
6
6
  "vault",
7
7
  "browser",
8
8
  "operations"
9
9
  ],
10
- "frontmatter": "name: k-skill-setup\ndescription: After installing the full k-skill bundle, configure and verify the shared cross-platform setup, then optionally wire update checks and GitHub starring with explicit user consent.\nlicense: MIT\nmetadata:\n category: setup\n locale: ko-KR\n phase: v1",
10
+ "frontmatter": "name: k-skill-setup\ndescription: Install the k-skill bundle, use the unified CLI, resolve credentials, verify the runtime, and optionally configure update checks and GitHub starring.\nlicense: MIT\nmetadata:\n category: setup\n locale: ko-KR\n phase: v1",
11
11
  "bundle": [
12
12
  {
13
13
  "from": "scripts/check-setup.sh",
@@ -18,7 +18,8 @@
18
18
  ## Design principles
19
19
 
20
20
  - 점수·등급 같은 해석 라벨을 만들지 않는다. 스냅샷 존재 사실 + 매칭 방법만 담는다.
21
- - 무인증 공개 파일 서버이므로 프록시를 거치지 않고 사용자 머신에서 직접 받는다.
21
+ - 무인증 공개 파일 서버를 사용자 머신에서 먼저 직접 호출한다. 직접 경로가 timeout/차단되면 GitHub Actions가 검증해 R2에 저장한 공개 미러를 fallback으로 사용한다.
22
+ - 미러 ZIP은 `latest.json`의 크기·SHA-256과 ZIP CRC/CSV 존재 검증을 모두 통과해야 캐시로 승격한다. 미러는 API 프록시가 아니라 공개 원본의 검증된 객체 복제본이다.
22
23
  - 최신 zip은 수백 MB이므로 1일 로컬 캐시(`~/.cache/k-skill/store-longevity-radar/`)한다. 반복 다운로드하지 않는다.
23
24
 
24
25
  ## When to use
@@ -46,6 +47,7 @@
46
47
  - `--old-csv`: (`match` 전용) 과거 스냅샷 CSV, 반복 지정. `'|'`/`','` 구분자 자동 감지
47
48
  - `--max-dist`: (`match` 전용) 동일 상호 허용 좌표 거리(m), 기본 150
48
49
  - `--out`, `--format`: 출력 파일/형식 (csv 기본, json 가능)
50
+ - `KSKILL_STORE_LONGEVITY_MIRROR_MANIFEST_URL`: 검증 미러 manifest override. 기본 `https://pub-c974105a1e4840bcaa264cb2a55d99a1.r2.dev/store-longevity-radar/latest.json`
49
51
 
50
52
  ## CLI examples
51
53
 
@@ -65,7 +67,7 @@ npx -y @nomadamas/k-skill@0 exec store-longevity-radar scripts/store_longevity_r
65
67
 
66
68
  ## Workflow
67
69
 
68
- 1. `current`부터 실행해 대상 업종 전수를 확보한다. zip 자동 다운로드는 수 분 걸릴 수 있음을 사용자에게 알린다.
70
+ 1. `current`부터 실행해 대상 업종 전수를 확보한다. zip 자동 다운로드는 수 분 걸릴 수 있음을 사용자에게 알린다. 원본 직접 다운로드를 먼저 시도하고 실패하면 크기·SHA-256이 명시된 검증 미러로 자동 전환한다.
69
71
  2. 과거 스냅샷 CSV가 있으면 `match`로 장수 점포를 추출한다. 기본 문구·완구 코드는 helper가 2022년 이전 `D08A01`/`D04A01`/`D04A02`를 자동 포함한다. 다른 업종은 현재 코드와 과거 코드를 `--code`로 함께 지정한다.
70
72
  3. 결과 전달 시 위 Honest limitations를 함께 요약한다.
71
73
  4. 후속 확인이 필요하면 `nts-business-registration`(폐업 확정), `localdata-business-status`(인허가 업력), `kakao-map`(전화번호·현재 등재)을 안내한다.
@@ -73,7 +75,8 @@ npx -y @nomadamas/k-skill@0 exec store-longevity-radar scripts/store_longevity_r
73
75
  ## Failure modes
74
76
 
75
77
  - 데이터셋 페이지에서 파일 ID 발견 실패 → `unavailable` + 수동 확인 URL 출력 (분기 개편 시 페이지 구조 변경 가능).
76
- - 공공데이터포털 접속/다운로드 timeout 또는 HTTP 실패 → `unavailable` + 원인 + 수동 확인 URL 출력.
78
+ - 공공데이터포털 접속/다운로드 timeout 또는 HTTP 실패 → 검증 미러 fallback.
79
+ - 미러 manifest/ZIP 접근 실패, 크기·SHA-256 불일치, ZIP 손상 → 캐시 미승격 + 직접/미러 양쪽 원인을 담은 `unavailable`.
77
80
  - 다운로드 중단 → `.part` 파일만 남고 캐시로 승격되지 않음. 재실행하면 이어서 새로 받는다.
78
81
  - `match`에 과거 CSV 미지정 → argparse 에러. 과거분 확보 방법을 사용자에게 안내한다.
79
82
  - 0건 매칭: 업종코드가 스냅샷 코드체계와 다를 수 있다. `--keyword`만으로 재시도한다.
@@ -82,6 +85,7 @@ npx -y @nomadamas/k-skill@0 exec store-longevity-radar scripts/store_longevity_r
82
85
 
83
86
  - 데이터셋: <https://www.data.go.kr/data/15083033/fileData.do>
84
87
  - 다운로드: `https://www.data.go.kr/cmm/cmm/fileDownload.do?atchFileId=<FILE_ID>&fileDetailSn=1` (무인증)
88
+ - 검증 미러 manifest: <https://pub-c974105a1e4840bcaa264cb2a55d99a1.r2.dev/store-longevity-radar/latest.json>
85
89
  - 관련 스킬: `nts-business-registration`, `localdata-business-status`, `kakao-map`
86
90
 
87
91
  ## Done when
@@ -0,0 +1,136 @@
1
+ """Download and verify the latest store-longevity snapshot."""
2
+
3
+ import hashlib
4
+ import json
5
+ import os
6
+ import re
7
+ import sys
8
+ import time
9
+ import urllib.error
10
+ import urllib.request
11
+ import zipfile
12
+
13
+ DATASET_PAGE = "https://www.data.go.kr/data/15083033/fileData.do"
14
+ DOWNLOAD_URL = "https://www.data.go.kr/cmm/cmm/fileDownload.do?atchFileId={fid}&fileDetailSn=1"
15
+ USER_AGENT = "Mozilla/5.0 (compatible; k-skill-store-longevity-radar)"
16
+ CACHE_DIR = os.path.join(os.path.expanduser("~"), ".cache", "k-skill", "store-longevity-radar")
17
+ CACHE_TTL = 24 * 3600
18
+ MIRROR_MANIFEST_URL = os.environ.get(
19
+ "KSKILL_STORE_LONGEVITY_MIRROR_MANIFEST_URL",
20
+ "https://pub-c974105a1e4840bcaa264cb2a55d99a1.r2.dev/store-longevity-radar/latest.json",
21
+ )
22
+
23
+
24
+ def log(message):
25
+ print(message, file=sys.stderr, flush=True)
26
+
27
+
28
+ def http_get(url, timeout=60):
29
+ req = urllib.request.Request(
30
+ url,
31
+ headers={"User-Agent": USER_AGENT, "Accept": "*/*"},
32
+ )
33
+ return urllib.request.urlopen(req, timeout=timeout)
34
+
35
+
36
+ def discover_atch_file_id():
37
+ html = http_get(DATASET_PAGE).read().decode("utf-8", "replace")
38
+ ids = re.findall(r"FILE_[0-9]{6,}", html)
39
+ if not ids:
40
+ raise ValueError(f"현재 파일 ID를 찾지 못함. 수동 확인: {DATASET_PAGE}")
41
+ return ids[0]
42
+
43
+
44
+ def download_to_path(url, path, timeout):
45
+ with http_get(url, timeout=timeout) as response, open(path, "wb") as output:
46
+ while chunk := response.read(1 << 20):
47
+ output.write(chunk)
48
+
49
+
50
+ def validate_snapshot_zip(path):
51
+ with zipfile.ZipFile(path) as archive:
52
+ corrupt_member = archive.testzip()
53
+ if corrupt_member is not None:
54
+ raise ValueError(f"손상된 ZIP 항목: {corrupt_member}")
55
+ if not any(info.filename.lower().endswith(".csv") for info in archive.infolist()):
56
+ raise ValueError("스냅샷 ZIP에 CSV가 없음")
57
+
58
+
59
+ def sha256_path(path):
60
+ digest = hashlib.sha256()
61
+ with open(path, "rb") as source:
62
+ while chunk := source.read(1 << 20):
63
+ digest.update(chunk)
64
+ return digest.hexdigest()
65
+
66
+
67
+ def download_mirror_zip(path):
68
+ with http_get(MIRROR_MANIFEST_URL, timeout=30) as response:
69
+ manifest = json.load(response)
70
+ if not isinstance(manifest, dict):
71
+ raise TypeError("미러 manifest가 JSON object가 아님")
72
+ object_url = manifest.get("object_url")
73
+ expected_size = manifest.get("size_bytes")
74
+ expected_sha256 = manifest.get("sha256")
75
+ if (
76
+ not isinstance(object_url, str)
77
+ or not object_url.startswith("https://")
78
+ or not isinstance(expected_size, int)
79
+ or expected_size <= 0
80
+ or not isinstance(expected_sha256, str)
81
+ or not re.fullmatch(r"[0-9a-f]{64}", expected_sha256)
82
+ ):
83
+ raise ValueError("미러 manifest 형식이 올바르지 않음")
84
+ tmp = path + ".mirror.part"
85
+ download_to_path(object_url, tmp, timeout=1800)
86
+ if os.path.getsize(tmp) != expected_size:
87
+ raise ValueError("미러 ZIP 크기 불일치")
88
+ if sha256_path(tmp) != expected_sha256:
89
+ raise ValueError("미러 ZIP SHA-256 불일치")
90
+ validate_snapshot_zip(tmp)
91
+ os.replace(tmp, path)
92
+ log(f"mirror cache: {object_url}")
93
+ return path
94
+
95
+
96
+ def download_latest_zip():
97
+ os.makedirs(CACHE_DIR, exist_ok=True)
98
+ path = os.path.join(CACHE_DIR, "sdc_latest.zip")
99
+ if os.path.exists(path) and time.time() - os.path.getmtime(path) < CACHE_TTL:
100
+ log(f"cache hit: {path}")
101
+ return path
102
+ try:
103
+ fid = discover_atch_file_id()
104
+ log(f"downloading {fid} (수백 MB, 수 분 소요) ...")
105
+ tmp = path + ".part"
106
+ download_to_path(DOWNLOAD_URL.format(fid=fid), tmp, timeout=1800)
107
+ validate_snapshot_zip(tmp)
108
+ os.replace(tmp, path)
109
+ except (
110
+ TimeoutError,
111
+ urllib.error.URLError,
112
+ OSError,
113
+ ValueError,
114
+ zipfile.BadZipFile,
115
+ ) as direct_exc:
116
+ log(f"direct download unavailable: {direct_exc}; trying verified mirror")
117
+ try:
118
+ return download_mirror_zip(path)
119
+ except (
120
+ TimeoutError,
121
+ urllib.error.URLError,
122
+ OSError,
123
+ TypeError,
124
+ ValueError,
125
+ json.JSONDecodeError,
126
+ zipfile.BadZipFile,
127
+ ) as mirror_exc:
128
+ note = (
129
+ f"공공데이터포털 직접 다운로드 실패: {direct_exc}. "
130
+ f"검증 미러 다운로드 실패: {mirror_exc}. 수동 확인: {DATASET_PAGE}"
131
+ )
132
+ raise SystemExit(json.dumps({
133
+ "status": "unavailable",
134
+ "note": note,
135
+ }, ensure_ascii=False)) from None
136
+ return path
@@ -15,19 +15,10 @@ import csv
15
15
  import io
16
16
  import json
17
17
  import math
18
- import os
19
18
  import re
20
19
  import sys
21
- import time
22
- import urllib.error
23
- import urllib.request
24
20
  import zipfile
25
-
26
- DATASET_PAGE = "https://www.data.go.kr/data/15083033/fileData.do"
27
- DOWNLOAD_URL = "https://www.data.go.kr/cmm/cmm/fileDownload.do?atchFileId={fid}&fileDetailSn=1"
28
- UA = "Mozilla/5.0 (compatible; k-skill-store-longevity-radar)"
29
- CACHE_DIR = os.path.join(os.path.expanduser("~"), ".cache", "k-skill", "store-longevity-radar")
30
- CACHE_TTL = 24 * 3600
21
+ from store_longevity_download import download_latest_zip
31
22
 
32
23
  DEFAULT_CODES = ["G21302", "G21306"] # 문구/회화용품 소매업, 장난감 소매업 (2022~ 코드체계)
33
24
  DEFAULT_KEYWORDS = ["문구", "문방구", "완구", "장난감"]
@@ -43,47 +34,6 @@ def log(msg):
43
34
  print(msg, file=sys.stderr)
44
35
 
45
36
 
46
- def http_get(url, timeout=60):
47
- req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "*/*"})
48
- return urllib.request.urlopen(req, timeout=timeout)
49
-
50
-
51
- def discover_atch_file_id():
52
- """데이터셋 페이지에서 현재 분기 파일 ID를 찾는다 (분기마다 갱신됨)."""
53
- html = http_get(DATASET_PAGE).read().decode("utf-8", "replace")
54
- ids = re.findall(r"FILE_[0-9]{6,}", html)
55
- if not ids:
56
- raise SystemExit(json.dumps({"status": "unavailable",
57
- "note": "데이터셋 페이지에서 파일 ID를 찾지 못함. 수동 확인: " + DATASET_PAGE},
58
- ensure_ascii=False))
59
- return ids[0]
60
-
61
-
62
- def download_latest_zip():
63
- os.makedirs(CACHE_DIR, exist_ok=True)
64
- path = os.path.join(CACHE_DIR, "sdc_latest.zip")
65
- if os.path.exists(path) and time.time() - os.path.getmtime(path) < CACHE_TTL:
66
- log(f"cache hit: {path}")
67
- return path
68
- try:
69
- fid = discover_atch_file_id()
70
- log(f"downloading {fid} (수백 MB, 수 분 소요) ...")
71
- tmp = path + ".part"
72
- with http_get(DOWNLOAD_URL.format(fid=fid), timeout=1800) as r, open(tmp, "wb") as f:
73
- while True:
74
- chunk = r.read(1 << 20)
75
- if not chunk:
76
- break
77
- f.write(chunk)
78
- os.replace(tmp, path)
79
- except (TimeoutError, urllib.error.URLError) as exc:
80
- raise SystemExit(json.dumps({
81
- "status": "unavailable",
82
- "note": f"공공데이터포털 접속 또는 다운로드 실패: {exc}. 수동 확인: {DATASET_PAGE}",
83
- }, ensure_ascii=False)) from None
84
- return path
85
-
86
-
87
37
  def norm_name(s):
88
38
  s = re.sub(r"[\s()\[\]{}\-_.·&']", "", s or "")
89
39
  return re.sub(r"(점|본점|지점)$", "", s)
@@ -1,109 +0,0 @@
1
- # Used Car Price Search
2
-
3
- ## What this skill does
4
-
5
- 한국의 대표 렌터카 업체를 먼저 비교하고, 현재는 **가장 기술적으로 구현이 쉬운 공급자**로 확인된 `SK렌터카 다이렉트 타고BUY`를 사용해 중고차 가격을 조회한다.
6
-
7
- - 한국의 주요 렌터카 업체로 `SK렌터카`, `롯데렌탈(롯데오토옥션)`, `레드캡렌터카`를 먼저 확인한다.
8
- - 각 업체의 공개 표면에서 **직접 API 제공 여부**, 웹 크롤링 난이도, 기존 **MCP / Skill** 존재 여부를 먼저 점검한다.
9
- - 이 저장소와 현재 세션에는 중고차 가격 조회용 전용 **MCP** 나 **Skill** 이 없으므로 새 스킬이 직접 조회를 담당한다.
10
- - 최종 선택 공급자는 `https://www.skdirect.co.kr/tb` 이다.
11
- - 이 페이지는 로그인 없이 열리고, HTML 안의 `__NEXT_DATA__` 에 현재 inventory snapshot 이 들어 있어 반복 조회가 쉽다.
12
- - 결과는 **월 렌트료**와 **인수가**를 함께 보여 준다.
13
-
14
- ## Provider survey
15
-
16
- | 업체 | 점검 결과 | v1 채택 여부 |
17
- | --- | --- | --- |
18
- | SK렌터카 다이렉트 `타고BUY` | `https://www.skdirect.co.kr/tb` 공개 HTML 에 `__NEXT_DATA__` inventory snapshot 포함. 로그인/세션 없이 반복 조회 가능. 별도 공개 API 문서는 못 찾았지만 SSR 데이터 추출이 가장 단순함. | 채택 |
19
- | 롯데렌탈 / 롯데오토옥션 | `https://www.lotteautoauction.net/hp/pub/cmm/viewMain.do` 공개 진입점은 열리지만, 일반 매물 검색은 legacy `.do` 흐름 중심이고 공개 목록 계약이 불명확했다. 추정 목록 URL은 404/에러 페이지가 섞여 v1 공급자로는 불안정했다. | 미채택 |
20
- | 레드캡렌터카 | 공식 진입점이 `https://biz.redcap.co.kr/rent/` business portal 로 이어졌고, 공개 중고차 inventory 검색 표면이나 직접 API를 확인하지 못했다. | 미채택 |
21
-
22
- ## When to use
23
-
24
- - "아반떼 중고차 가격 봐줘"
25
- - "SK렌터카 타고BUY에 K3 얼마야?"
26
- - "캐스퍼 인수가/월 렌트료 같이 알려줘"
27
- - "중고차 시세를 렌터카 업체 기준으로 보고 싶어"
28
-
29
- ## When not to use
30
-
31
- - 실제 구매/계약/상담 신청까지 자동화해야 하는 경우
32
- - 특정 VIN/성능기록부/사고이력 원문까지 강제해야 하는 경우
33
- - 여러 업체 통합 최저가 비교가 필요한 경우
34
-
35
- ## Prerequisites
36
-
37
- - 인터넷 연결
38
- - `node` 18+
39
- - `used-car-price-search` package 또는 동일 로직
40
-
41
- ## Required inputs
42
-
43
- ### 1. Ask the car model/keyword first if it is missing
44
-
45
- 차종 키워드가 없으면 먼저 물어본다.
46
-
47
- - 권장 질문: `어떤 차종을 찾을까요? 예: 아반떼, K3, 캐스퍼`
48
- - 너무 넓으면: `제조사나 차종을 조금 더 구체적으로 알려주세요. 예: 현대 아반떼, 기아 K3`
49
-
50
- ## Official surface used in v1
51
-
52
- - SK direct used-car inventory page: `https://www.skdirect.co.kr/tb`
53
-
54
- ## Workflow
55
-
56
- 1. 차종 키워드가 없으면 먼저 질문한다.
57
- 2. `SK렌터카`, `롯데렌탈`, `레드캡렌터카` 비교 결과를 짧게 기억하고, 현재 공급자는 `SK렌터카 다이렉트 타고BUY` 임을 유지한다.
58
- 3. `https://www.skdirect.co.kr/tb` HTML 을 가져온다.
59
- 4. HTML 의 `__NEXT_DATA__` JSON 에서 `carListProd` inventory snapshot 을 읽는다.
60
- 5. 차종 키워드로 inventory 를 필터링한다.
61
- 6. 상위 결과에서 `인수가`, `월 렌트료`, `연식`, `주행거리`, `연료`, `변속기`를 정리한다.
62
- 7. 같은 차종이라도 재고가 수시로 바뀔 수 있으므로 snapshot 기준 응답임을 짧게 알린다.
63
-
64
- ## Node.js example
65
-
66
- ```js
67
- const { lookupUsedCarPrices } = require("used-car-price-search")
68
-
69
- async function main() {
70
- const result = await lookupUsedCarPrices("아반떼", { limit: 5 })
71
-
72
- console.log({
73
- provider: result.provider,
74
- matchedCount: result.matchedCount,
75
- summary: result.summary,
76
- items: result.items
77
- })
78
- }
79
-
80
- main().catch((error) => {
81
- console.error(error)
82
- process.exitCode = 1
83
- })
84
- ```
85
-
86
- ## Respond conservatively
87
-
88
- 응답은 아래 순서로 짧게 정리한다.
89
-
90
- - 공급자: `SK렌터카 다이렉트 타고BUY`
91
- - 차종 키워드
92
- - 매칭된 차량 수
93
- - 인수가 범위
94
- - 월 렌트료 범위
95
- - 대표 차량 2~5개
96
- - `공개 inventory snapshot 기준이라 실시간 재고/가격은 바뀔 수 있다`는 안내
97
-
98
- ## Done when
99
-
100
- - 주요 렌터카 업체 비교와 공급자 선택 이유를 설명했다.
101
- - 차종 키워드 기준으로 결과를 최소 1건 이상 또는 보수적 빈 결과로 반환했다.
102
- - 결과에 `인수가` 와 `월 렌트료` 를 함께 담았다.
103
- - 라이브 검증에서 **최소 10회 이상** 반복 조회가 가능함을 확인했다.
104
-
105
- ## Failure modes
106
-
107
- - 공개 inventory snapshot 은 페이지 갱신 타이밍에 따라 달라질 수 있다.
108
- - 별도 공개 API 문서는 찾지 못했으므로 v1 은 HTML 내 `__NEXT_DATA__` 의 안정성에 의존한다.
109
- - 특정 차종 키워드가 너무 넓으면 유사 모델이 함께 섞일 수 있다.
@@ -1,9 +0,0 @@
1
- # 상표 사용 법적 고지 — `used-car-price-search`
2
-
3
- 이 스킬에서 `SK렌터카` 명칭은 중고차 재고·가격·인수가 조회의 **대상 판매·렌터카 서비스**를 식별하기 위해 사용한다. k-skill의 출처를 SK렌터카 운영사로 표시하려는 사용이 아니다.
4
-
5
- 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)은 타인의 표장을 출처표시가 아니라 상품 기능 또는 적용 기종을 밝히기 위해 사용하고 상표 사용으로 인식될 수 없는 경우 침해가 아니라고 판시했다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)와 대법원 [2011다18802](https://www.law.go.kr/LSW/precInfoP.do?precSeq=167457), [2019후10418](https://law.go.kr/LSW/precInfoP.do?mode=0&precSeq=230725) 판결에 따라 실제 거래계에서 출처표시로 기능하는지는 표시 태양과 사용 경위 등을 종합해 판단해야 한다.
6
-
7
- 따라서 이 명칭은 필요한 범위의 평문으로만 사용하고, 별도 근거 없이 로고, 공식·제휴·후원·인증·파트너 표현을 사용하지 않는다. 각 상표의 권리는 해당 권리자에게 있다. 이 문서는 차량정보의 저작권·데이터베이스권, 매매·렌탈 계약, 약관·계약, 소비자보호 또는 접근 방식의 적법성을 판단하지 않는다.
8
-
9
- 전체 검토: [제3자 상표의 기능 설명·호환 대상 표시 검토](https://github.com/NomaDamas/k-skill/blob/dev/docs/legal/trademark-use-review.md)
@@ -1,8 +0,0 @@
1
- {
2
- "name": "used-car-price-search",
3
- "description": "주요 한국 렌터카 업체를 비교한 뒤 SK렌터카 다이렉트 타고BUY inventory snapshot 으로 중고차 가격/인수가를 조회한다. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.",
4
- "profiles": [
5
- "action:commerce"
6
- ],
7
- "frontmatter": "name: used-car-price-search\ndescription: 주요 한국 렌터카 업체를 비교한 뒤 SK렌터카 다이렉트 타고BUY inventory snapshot 으로 중고차 가격/인수가를 조회한다. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.\nlicense: MIT\nmetadata:\n category: automotive\n locale: ko-KR\n phase: v1"
8
- }