@nomadamas/k-skill 0.9.2 → 0.10.2
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/bin/k-skill.js +64 -43
- package/package.json +2 -2
- package/skills/biz-health-check/instruction.md +2 -0
- package/skills/company-analysis/instruction.md +68 -0
- package/skills/company-analysis/references/source-contract.md +75 -0
- package/skills/company-analysis/scripts/dart-rows.js +52 -0
- package/skills/company-analysis/scripts/dart-rows.ts +48 -0
- package/skills/company-analysis/scripts/evidence.js +567 -0
- package/skills/company-analysis/scripts/evidence.ts +520 -0
- package/skills/company-analysis/scripts/fetch-public.js +85 -0
- package/skills/company-analysis/scripts/fetch-public.ts +75 -0
- package/skills/company-analysis/skill.json +6 -0
- package/skills/express-bus-booking/scripts/kobus_express_booking.py +46 -18
- package/skills/fine-dust-location/scripts/fine_dust.py +4 -1
- package/skills/foresttrip-vacancy/scripts/run_foresttrip_vacancy.py +53 -3
- package/skills/g2b-order-plan-search/instruction.md +17 -0
- package/skills/g2b-sanctioned-supplier/instruction.md +10 -1
- package/skills/g2b-sanctioned-supplier/scripts/g2b_sanctioned_supplier.py +8 -4
- package/skills/g2b-sanctioned-supplier/scripts/test_g2b_sanctioned_supplier.py +19 -0
- package/skills/government-bond-analysis/instruction.md +216 -0
- package/skills/government-bond-analysis/references/methodology.md +63 -0
- package/skills/government-bond-analysis/scripts/cli.mjs +268 -0
- package/skills/government-bond-analysis/scripts/collect.mjs +171 -0
- package/skills/government-bond-analysis/scripts/core.mjs +224 -0
- package/skills/government-bond-analysis/scripts/dual.mjs +178 -0
- package/skills/government-bond-analysis/scripts/harness.mjs +406 -0
- package/skills/government-bond-analysis/scripts/modes.mjs +136 -0
- package/skills/government-bond-analysis/scripts/news.mjs +113 -0
- package/skills/government-bond-analysis/scripts/render.mjs +120 -0
- package/skills/government-bond-analysis/scripts/schedule.mjs +96 -0
- package/skills/government-bond-analysis/scripts/ust.mjs +204 -0
- package/skills/government-bond-analysis/skill.json +8 -0
- package/skills/heyyumi/instruction.md +133 -0
- package/skills/heyyumi/skill.json +9 -0
- package/skills/kamis-food-price/scripts/run_kamis.py +1 -1
- package/skills/korean-bond-search/instruction.md +122 -0
- package/skills/korean-bond-search/references/fields.md +48 -0
- package/skills/korean-bond-search/references/source-notes.md +11 -0
- package/skills/korean-bond-search/scripts/bond_search.py +906 -0
- package/skills/korean-bond-search/skill.json +9 -0
- package/skills/korean-transit-route/instruction.md +1 -1
- package/skills/market-event-impact/instruction.md +150 -0
- package/skills/market-event-impact/references/event-taxonomy.md +74 -0
- package/skills/market-event-impact/references/methodology.md +98 -0
- package/skills/market-event-impact/references/research-contract.md +120 -0
- package/skills/market-event-impact/references/source-priority.md +25 -0
- package/skills/market-event-impact/scripts/adapters.py +32 -0
- package/skills/market-event-impact/scripts/asset_selector.py +120 -0
- package/skills/market-event-impact/scripts/calendars.py +179 -0
- package/skills/market-event-impact/scripts/event_resolver.py +260 -0
- package/skills/market-event-impact/scripts/event_study.py +171 -0
- package/skills/market-event-impact/scripts/market_data.py +204 -0
- package/skills/market-event-impact/scripts/market_event.py +1065 -0
- package/skills/market-event-impact/scripts/research.py +389 -0
- package/skills/market-event-impact/skill.json +9 -0
- package/skills/mofa-travel-safety/scripts/run_mofa_travel_safety.py +1 -1
- package/skills/store-longevity-radar/scripts/__pycache__/store_longevity_download.cpython-312.pyc +0 -0
- package/src/analytics-policy.json +18 -0
- package/src/analytics.js +106 -0
- package/src/metrics.js +49 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# HeyYumi (헤이유미) 예약 가능한 맛집 검색 · 식당 예약
|
|
2
|
+
|
|
3
|
+
## What this skill does
|
|
4
|
+
|
|
5
|
+
헤이유미 공식 CLI(`heyyumi`, npm, https://github.com/hmp-dev/heyyumi-cli)로 한국 식당·카페·바를 찾고, **예약 가능한 매장에는 예약 요청을 보낸 뒤 사장님의 수락/거절/만료까지 확인**한다. 같은 CLI로 "지금 자리 있어요? 웨이팅 몇 분이에요?" 같은 실시간 문의도 사장님에게 보낸다.
|
|
6
|
+
|
|
7
|
+
- 구글 로그인 한 번이면 쓴다. 로그인할 때 사용자 전용 키가 자동으로 만들어진다. 직접 키를 발급하거나 붙여 넣을 필요 없다.
|
|
8
|
+
- 공식 CLI만 쓴다. 크롤링·화면 스크래핑은 하지 않고, k-skill-proxy도 쓰지 않는다. 호출은 사용자 머신에서 헤이유미 서버로 직접 간다.
|
|
9
|
+
- 예약은 선결제가 없다. 요청은 매장 사장님에게 가며 약 5분 안에 수락/거절이 정해진다.
|
|
10
|
+
|
|
11
|
+
## When to use
|
|
12
|
+
|
|
13
|
+
- "을지로 힙한 카페 찾아서 예약해줘", "홍제동 저녁 2명 파스타집 예약 가능한 곳"
|
|
14
|
+
- "이 식당 예약돼? 지금 10명 앉을 수 있어? 웨이팅 몇 분이야?"
|
|
15
|
+
- 예약 가능한 곳만 골라 달라는 요청, 주차·채식·영어 응대·분위기 조건 검색
|
|
16
|
+
|
|
17
|
+
쓰지 않는 경우: 매출 기반 순위가 목적이면 `bccard-eatpl-search`, 길찾기·지도는 `kakao-map`, KTX·버스 예약은 해당 스킬. 영업시간·주차 같은 정적 정보는 검색 결과로 답하고 실시간 문의로 사장님을 귀찮게 하지 않는다.
|
|
18
|
+
|
|
19
|
+
## Run
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx -y heyyumi@0 <command> [flags]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
출력은 stdout의 JSON이고(파이프 시 한 줄, `--pretty`로 들여쓰기) 진행 로그는 stderr로 간다. 종료 코드: `0` 정상, `1` 서버/도구 오류, `2` 사용법 오류, `3` 로그인 필요. 오류 JSON은 `error.code`, `error.message`, `error.next`를 가진다.
|
|
26
|
+
|
|
27
|
+
### 1. 로그인 (머신당 한 번)
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx -y heyyumi@0 status # signedIn 여부 확인
|
|
31
|
+
npx -y heyyumi@0 login # 브라우저에서 구글 로그인, 끝나면 스스로 종료
|
|
32
|
+
npx -y heyyumi@0 login --no-browser # 로그인 URL만 stderr로 출력(원격/에이전트 환경)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`status`가 `signedIn:false`거나 어떤 명령이 종료 코드 3(`login_required`)을 내면 `login`을 실행한다. **로그인과 약관 동의는 사용자가 직접 한다.** 에이전트가 구글 로그인 화면을 대신 누르지 않는다. `--no-browser`로 띄우면 stderr에 `https://heyyumi.ai/oauth/authorize?...` URL이 나오니 그 URL을 사용자에게 주고 같은 컴퓨터의 브라우저에서 열게 한다(콜백이 `127.0.0.1`로 돌아오므로 원격 셸에서는 안 된다). 로그인이 끝나면 프로세스가 스스로 끝난다(기본 5분 대기, `--timeout`). 토큰은 `~/.config/heyyumi/credentials.json`(0600)에 저장되고 자동 갱신된다. `logout`으로 지운다.
|
|
36
|
+
|
|
37
|
+
이미 대시보드 키(`hmp_...`)가 있으면 `HEYYUMI_API_KEY`로 넘겨도 된다(로그인 생략). 키·토큰은 채팅에 출력하지 않는다.
|
|
38
|
+
|
|
39
|
+
### 2. 후보 찾기 (부작용 없음)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx -y heyyumi@0 regions 을지로 # 지역 확인(좌표, placeCount)
|
|
43
|
+
npx -y heyyumi@0 search --region 을지로 --subtype coffee --atmosphere trendy --reservation_channel yumi --page-size 8
|
|
44
|
+
npx -y heyyumi@0 search 파스타 --region 홍제동 --reservation_channel yumi --open_at "2026-10-25 19:00"
|
|
45
|
+
npx -y heyyumi@0 nearby --lat 37.5662 --lng 126.991 --radius 800
|
|
46
|
+
npx -y heyyumi@0 place 324146172 --fields quality,contact_hours,edge
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- **예약 가능한 곳만 보려면 `--reservation_channel yumi`.** 이것이 "여기서 예약 요청을 받는 매장"(`yumiBooking.canRequest=true`)이다. `--reservable true`는 예약 의사 표현일 뿐 요청 가능 보장이 아니다. 0건이면 서버가 조건을 넓히고 `meta.reservationFallback`에 안내문을 넣으니 그대로 사용자에게 전한다.
|
|
50
|
+
- 검색은 지역/음식과 함께 쓴다. 지역 없이 파트너 전체를 나열하면 `partner_scope_required`가 나온다.
|
|
51
|
+
- 플래그는 도구 필터 이름 그대로다(`--region`→`region_name`). 오타는 CLI가 거절하고 비슷한 이름을 알려 준다. 전체 어휘는 `npx -y heyyumi@0 tools search_places`.
|
|
52
|
+
- 자주 쓰는 값: `--subtype`(`coffee`, `dessert`, `bakery`, `brunch`, `korean`, `italian`, `cocktail_bar`, `korean_bbq` …, 쉼표=OR, 한국어도 됨), `--atmosphere`(`trendy`, `cozy`, `quiet`, `lively`, `view`, `spacious` …), `--recommended_for`(`date`, `group_dining`, `business_meeting` …), `--open_at`(한국시간 `"2026-10-25 19:00"`), 불리언은 값 없이 `--parking`.
|
|
53
|
+
- **`--atmosphere`는 순위 가중치일 뿐 걸러내지 않는다.** `meta.softenedFilters`에 나열된 조건은 "확정 매칭이 아니라 선호 정렬"이라고 사용자에게 알린다. "힙한" 같은 요청은 `atmosphere`에 `trendy`가 있는지, `aiSummary`, 메뉴, 리뷰 수, 인스타(`snsLinks`)로 근거를 보여 준다.
|
|
54
|
+
- 응답: 검색은 `{success, data:[...], meta, locationNote}`, 상세는 `{success, data:{...}}`. 매장 id는 `data[].id`.
|
|
55
|
+
- 결과 해석: `confidence`(0~1, 높을수록 신뢰), `freshnessScore`(0~1, 높을수록 최근), `possiblyClosed`/`closureSignal`이 있으면 알린다. `openNow`와 `hours`는 한국시간. 점수가 낮다고 폐업으로 단정하지 않는다.
|
|
56
|
+
- `locationNote`는 어느 지역을 검색했는지 한 줄로 알리라는 지시다. 행정동 코드·"읍/면" 같은 용어 없이 "을지로 상권을 찾았어요"처럼 말하고, 같은 이름의 다른 지역일 수 있으면 짧게 되묻는다.
|
|
57
|
+
- 후보는 이름, 주소, 가까운 역, 오늘/해당 시각 영업 여부, 예약 가능 여부(파트너 여부와 `requestHours`), `placeUrl`을 붙여 2~5곳으로 정리한다.
|
|
58
|
+
|
|
59
|
+
### 3. 예약 가능 여부 판단
|
|
60
|
+
|
|
61
|
+
검색·상세 결과의 `yumiBooking`을 읽는다.
|
|
62
|
+
|
|
63
|
+
| 값 | 의미 |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| `canRequest: true, partner: true, requestHours: "anytime"` | 유미 파트너. 언제든 요청 가능, 응답이 빠르고 실시간 문의도 가능 |
|
|
66
|
+
| `canRequest: true, partner: null, requestHours: "11:00-21:00 KST"` | 비파트너. **매일 11:00~21:00 KST에만 요청을 받는다.** 그 밖 시간이면 `reservation_requests_closed`와 `retryAfter` |
|
|
67
|
+
| `canRequest: false` 또는 `yumiBooking` 없음 | 이 CLI로는 예약 요청 불가. `reservationChannels`/`phone`/`bookingUrl`로 전화·외부 예약을 안내 |
|
|
68
|
+
|
|
69
|
+
예약 요청 가능 시각과 매장 영업시간은 별개다. 영업 요일·시간(`hours`, `openNow`)도 확인하고, 휴무 요일이나 영업 외 시간이면 사용자에게 알리고 시각을 바꾼다.
|
|
70
|
+
|
|
71
|
+
### 4. 예약 정보 모으기
|
|
72
|
+
|
|
73
|
+
필수: 매장(`PLACE_ID`), 날짜·시각(한국시간), 인원(`--party`), **예약자 휴대폰 번호(`--phone`)**. 이름(`--name`)은 강하게 권장하고, `--note`(알레르기·기념일·좌석)와 `--lang`은 선택이다. 한국 번호가 아니면 **`--email`이 필수**다(문자를 못 보내 이메일로 결과를 보낸다). 한국 번호 사용자에게는 이메일을 묻지 않는다.
|
|
74
|
+
|
|
75
|
+
빠진 값은 사용자에게 묻는다. 지어내지 않는다. "내일", "토요일"은 오늘 날짜 기준 절대 날짜로 바꿔 확인한다. `--time`은 `"2026-10-25 19:00"` 형식(한국시간)이며 날짜 없이 `"19:00"`만 주면 CLI가 거절한다. CLI에는 전송 없는 미리보기나 샌드박스가 없으므로 **`reserve`를 실행하는 순간이 곧 전송이다.**
|
|
76
|
+
|
|
77
|
+
### 5. 승인(`clarify`) → 전송
|
|
78
|
+
|
|
79
|
+
1. **`clarify`로 정확한 매장명·주소, 날짜·시각(요일 포함), 인원, 예약자 이름·번호(·이메일), 요청사항을 보여 주고 "이 내용으로 사장님에게 예약 요청을 보낼까요? 선결제는 없고 실제 매장으로 전달됩니다"라고 승인받는다.** 승인 전에는 `reserve`를 실행하지 않는다. 사장님 푸시와 손님 문자는 취소할 수 없다.
|
|
80
|
+
2. 승인 후에만 실행한다.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx -y heyyumi@0 reserve 324146172 --time "2026-10-25 19:00" --party 2 --name "홍길동" --phone 010-1234-5678 --note "창가 자리"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
3. 응답에 `reservationId`와 `cli.next`(`heyyumi wait <id>`)가 오면 **요청이 접수됐을 뿐 확정이 아니다.** 같은 요청을 다시 보내야 할 때(네트워크 오류 등)는 `--idempotency-key`를 같은 값으로 줘서 중복 예약을 막는다. 값이 다르면 새 예약이다.
|
|
87
|
+
|
|
88
|
+
### 6. 결과 확인
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx -y heyyumi@0 wait RESERVATION_ID --timeout 110
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`confirmed` / `cancelled` / `expired` 중 하나가 나올 때까지 기다린다(사장님 응답 최대 약 5분). 끝나지 않고 `cli.next`가 오면 같은 명령을 다시 실행한다. 한 번 상태만 볼 때는 `reservation RESERVATION_ID`. 확정이면 매장·시각·인원을 다시 적어 알리고, 거절·만료면 다른 시각이나 다른 후보를 제안한다. **같은 시간을 자동으로 재요청하지 않는다.** `pending`에서 멈춘 채 "예약 완료"라고 말하지 않는다.
|
|
95
|
+
|
|
96
|
+
### 7. 실시간 문의 (선택, 사장님에게 푸시가 간다)
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx -y heyyumi@0 live PLACE_ID --kind wait --topic "웨이팅"
|
|
100
|
+
npx -y heyyumi@0 live PLACE_ID --kind seats --topic "party of 10"
|
|
101
|
+
npx -y heyyumi@0 live PLACE_ID --kind item --topic "바스크 치즈케이크"
|
|
102
|
+
npx -y heyyumi@0 live-wait QUERY_ID --timeout 110
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
예약과 같이 `clarify` 승인 후 실행한다. `--topic`은 문장이 아니라 짧은 토큰(실제 메뉴명, `웨이팅`)이다. 답에는 상태(`available`, `limited`, `unavailable`, `soon`, `not_offered`, `no_response`)와 확인 시각, 사장님 메모(예: 웨이팅 20분)가 있으니 함께 전한다. 파트너 매장에서만 된다.
|
|
106
|
+
|
|
107
|
+
## Done when
|
|
108
|
+
|
|
109
|
+
- 검색 요청: 조건에 맞는 후보를 신뢰도·최신성·예약 가능 여부와 함께 제시했다. 선호 정렬로만 반영된 조건은 그렇게 밝혔다.
|
|
110
|
+
- 예약 요청: 사용자 승인 후 `reserve`를 보냈고, `wait`로 **`confirmed`/`cancelled`/`expired`** 를 확인해 보고했다.
|
|
111
|
+
- 사용자가 승인하지 않았거나 필수 정보가 비어 있으면 **미전송 상태로 끝냈다**고 명시한다.
|
|
112
|
+
|
|
113
|
+
## Failure modes
|
|
114
|
+
|
|
115
|
+
| 증상 | 의미 | 처리 |
|
|
116
|
+
| --- | --- | --- |
|
|
117
|
+
| 종료 코드 3, `login_required` | 로그인 안 됨/만료/거절 | `login` 안내(사용자가 구글 로그인) |
|
|
118
|
+
| `invalid_api_key` | `HEYYUMI_API_KEY` 거절 | 키를 확인하거나 unset 후 `login` |
|
|
119
|
+
| 종료 코드 2, `usage`/`unknown_option` | 인자 오류·오타 | 메시지의 제안대로 수정. 오타 난 `--nme`가 이름 없는 예약이 되지 않도록 CLI가 거절한다 |
|
|
120
|
+
| `reservation_not_available` | 이 매장은 헤이유미로 예약 불가 | **재시도 금지.** 전화·외부 예약 안내 |
|
|
121
|
+
| `reservation_requests_closed` | 비파트너 매장 요청 시간(11:00~21:00 KST) 밖 | `retryAfter` 이후에 다시 안내 |
|
|
122
|
+
| `venue_closed_at_requested_time` | 요청 시각이 휴무/영업 외 | 다른 시각 제안 |
|
|
123
|
+
| `reservation_time_past` | 지난 시각 | 시각 확인 |
|
|
124
|
+
| `guest_phone_required` / `guest_email_required` | 연락처 누락 | 사용자에게 다시 묻기 |
|
|
125
|
+
| `live_status_not_available` | 사장님 앱이 없는 매장 | 재시도 금지, 검색 결과의 영업시간으로 답 |
|
|
126
|
+
| `partner_scope_required` | 지역 없이 파트너 나열 | 지역이나 음식을 받아 다시 검색 |
|
|
127
|
+
| `http_error`/`rpc_error`, 종료 코드 1 | 서버 오류·한도 | 메시지를 그대로 알리고 잠시 후 한 번만 재시도 |
|
|
128
|
+
|
|
129
|
+
## Boundaries
|
|
130
|
+
|
|
131
|
+
- 개인의 대화형 사용을 위한 스킬이다. 무료는 개인 사용 기준이며 하루 질문 한도가 있다. 회사 제품·서비스에 넣는 상업 이용과 대량 수집은 헤이유미 별도 라이선스 대상이라 이 스킬로 하지 않는다. 대량 목록 요청이 `bulk_export_required`로 막히면 조건을 좁힌다.
|
|
132
|
+
- 토큰·키·연락처를 저장소, 로그, 채팅에 남기지 않는다. 결제·카드 정보는 다루지 않는다(선결제 없음).
|
|
133
|
+
- 이 스킬은 헤이유미 공식 기능이 아니며 제휴 관계를 주장하지 않는다. 출처를 "헤이유미(HeyYumi)"로 표기한다.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "heyyumi",
|
|
3
|
+
"description": "한국 식당·카페·바를 검색하고, 예약 가능한 매장이면 그 자리에서 예약 요청까지 보내 사장님 수락/거절을 확인하는 헤이유미(HeyYumi) 스킬. 예약 가능한 식당 찾기, 식당 예약, 테이블 예약, 맛집 예약, 카페 예약, 예약 가능 여부 확인, 지금 자리 있나·웨이팅 몇 분인지 사장님에게 물어보기가 필요할 때 사용한다. Use when the user wants to find a Korean restaurant, cafe, or bar that takes reservations (예약 가능), book a table or send a reservation request via HeyYumi, or ask a venue about current wait time or seat availability.",
|
|
4
|
+
"profiles": [
|
|
5
|
+
"vault",
|
|
6
|
+
"action:booking"
|
|
7
|
+
],
|
|
8
|
+
"frontmatter": "name: heyyumi\ndescription: 한국 식당·카페·바를 검색하고, 예약 가능한 매장이면 그 자리에서 예약 요청까지 보내 사장님 수락/거절을 확인하는 헤이유미(HeyYumi) 스킬. 예약 가능한 식당 찾기, 식당 예약, 테이블 예약, 맛집 예약, 카페 예약, 예약 가능 여부 확인, 지금 자리 있나·웨이팅 몇 분인지 사장님에게 물어보기가 필요할 때 사용한다. Use when the user wants to find a Korean restaurant, cafe, or bar that takes reservations (예약 가능), book a table or send a reservation request via HeyYumi, or ask a venue about current wait time or seat availability.\nlicense: MIT\nmetadata:\n category: food\n locale: ko-KR\n phase: v1"
|
|
9
|
+
}
|
|
@@ -91,7 +91,7 @@ def main(argv=None):
|
|
|
91
91
|
return 0
|
|
92
92
|
|
|
93
93
|
try:
|
|
94
|
-
with urllib.request.urlopen(urllib.request.Request(url, headers={"accept": "application/json"}), timeout=30) as response:
|
|
94
|
+
with urllib.request.urlopen(urllib.request.Request(url, headers={"accept": "application/json", "user-agent": "k-skill/kamis-food-price"}), timeout=30) as response:
|
|
95
95
|
payload = json.loads(response.read())
|
|
96
96
|
except (OSError, ValueError, urllib.error.HTTPError) as error:
|
|
97
97
|
print(f"[error] KAMIS request failed: {error}", file=sys.stderr)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# 한국 채권 종목 조회·비교
|
|
2
|
+
|
|
3
|
+
## What this skill does
|
|
4
|
+
|
|
5
|
+
SEIBro에서 확인한 한국 채권을 종목명·발행사·ISIN으로 좁혀 발행조건과 옵션을 같은 형식으로 비교·상세 조회하는 한국어 대화형 스킬이다. GS Quant의 Instrument/Data 구조화 방식에서 영감을 받아 표준 Bond Instrument 필드를 설계했으며, 코드를 복제하거나 공식 제휴·연계를 주장하지 않는다. 조회 전용이고 실시간 호가·수익률·적정 스프레드·신용판단·매매 추천은 제공하지 않는다.
|
|
6
|
+
|
|
7
|
+
## Interview first
|
|
8
|
+
|
|
9
|
+
사용자 문장에서 이미 주어진 조건은 다시 묻지 않는다. 다음 중 하나도 없을 때만 종목명/발행사/ISIN을 짧게 묻는다.
|
|
10
|
+
|
|
11
|
+
- 종목명 또는 발행사
|
|
12
|
+
- ISIN
|
|
13
|
+
- 만기 범위와 채권 유형 같은 식별 조건
|
|
14
|
+
|
|
15
|
+
후보가 둘 이상이면 임의로 하나를 선택하지 않는다. 최대 5개를 `종목명 · ISIN · 발행사 · 만기 · 표면금리`로 제시하고, 사용자가 만기·회차·ISIN으로 고르게 한다. 정확한 ISIN이 있으면 바로 상세 조회한다.
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
### 1. 한 번의 공식 조회 경로 선택
|
|
20
|
+
|
|
21
|
+
SEIBro 채권정보를 1차 원천으로 삼되, 매 조회마다 **검색·브라우저 UI·helper를 중복 실행하지 말고 필요한 경로 하나만** 고른다.
|
|
22
|
+
|
|
23
|
+
- 정확한 ISIN이 있으면 SEIBro 모바일 상세 페이지를 직접 연다: `https://m.seibro.or.kr/cnts/bond/selectDetailSearch.do?txt_code=<ISIN>`.
|
|
24
|
+
- 종목명/발행사만 있으면 사용 가능한 읽기 전용 웹 검색으로 공식 SEIBro 페이지를 한 번 찾는다. 검색 결과는 후보 발견에만 쓰고, 답변에 넣을 값은 열린 공식 상세 페이지에서 확인한다. 페이지에서 결과 범위를 확인할 수 없다면 “확인된 후보”라고 표현하고 전체 목록처럼 단정하지 않는다.
|
|
25
|
+
- 검색 기능이 없거나 공식 상세 페이지로 연결되지 않을 때만 SEIBro 모바일 검색 화면을 사용한다. PC WebSquare 메인 진입점은 기본 경로로 쓰지 않는다.
|
|
26
|
+
- 현재 열려 있고 요청 종목과 일치하는 공식 SEIBro 페이지가 있으면 그 페이지를 재사용한다. 별도 컴퓨터 유즈는 사이트 검색 등 UI 조작이 꼭 필요한 경우에만 보조 경로로 쓴다.
|
|
27
|
+
- 공식 페이지의 도메인·종목코드(ISIN)·종목명을 맞춰 보고 필요한 항목만 기록한다. 검색 스니펫만으로 쿠폰·만기·잔액·옵션을 확정하지 않는다. 검색 결과가 다른 ISIN을 가리키거나 상세 화면에 해당 항목이 없으면 다시 추정하지 않고 `미확인`으로 둔다.
|
|
28
|
+
- 첫 경로에서 오류가 나면 무작정 탭을 재탐색하거나 같은 조회를 반복하지 않는다. 가능한 대체 경로를 한 번만 시도하고, 그래도 공식 값을 확인할 수 없으면 SEIBro 내보내기 파일을 요청한다. 기존 브라우저 탭을 쓸 때는 현재 유효한 페이지 핸들을 유지하고, 만료된 탭 ID를 반복해서 찾지 않는다.
|
|
29
|
+
- CAPTCHA·로그인벽·차단을 우회하거나 대량 수집하지 않는다. 테스트 픽스처·예시 데이터·사용자가 준 임의 JSON은 동작 검증에만 쓰고 실제 채권 결과로 제시하지 않는다.
|
|
30
|
+
|
|
31
|
+
화면에서 직접 확인한 공식 상세 페이지로 충분한 답을 만들 수 있으면 helper 실행이나 수기 export 파일을 만들지 않는다. helper는 사용자가 제공했거나 SEIBro에서 실제 내려받은 JSON/CSV/TSV/HTML을 정규화·비교할 때 사용한다. `--input`을 생략하면 `KSKILL_SEIBRO_EXPORT`를 사용한다.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx -y @nomadamas/k-skill@0 exec korean-bond-search scripts/bond_search.py -- \
|
|
35
|
+
search --input /path/to/seibro-export.csv --issuer "현대자동차" \
|
|
36
|
+
--observed-at 2026-09-24T09:00:00+09:00 --verified-source
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx -y @nomadamas/k-skill@0 exec korean-bond-search scripts/bond_search.py -- \
|
|
41
|
+
search --input /path/to/seibro-export.json --name "현대차" \
|
|
42
|
+
--maturity-from 2028-01-01 --maturity-to 2030-12-31 --observed-at 2026-09-24T09:00:00+09:00 --verified-source
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx -y @nomadamas/k-skill@0 exec korean-bond-search scripts/bond_search.py -- \
|
|
47
|
+
detail --input /path/to/seibro-export.html --isin "$BOND_ISIN" --observed-at 2026-09-24T09:00:00+09:00 --verified-source
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx -y @nomadamas/k-skill@0 exec korean-bond-search scripts/bond_search.py -- \
|
|
52
|
+
options --input /path/to/seibro-export.json --isin "$BOND_ISIN" --observed-at 2026-09-24T09:00:00+09:00 --verified-source
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
지원 입력은 UTF-8/CP949/EUC-KR JSON·CSV·TSV와 표 형태 HTML이다. JSON은 배열 또는 `items` 배열을 받는다. 원천 헤더 대응표가 필요하면 다음을 읽는다.
|
|
56
|
+
|
|
57
|
+
상세/옵션 명령의 `"$BOND_ISIN"`은 실제로 확인한 12자리 ISIN으로 바꾼다. helper는 형식뿐 아니라 ISIN 체크디지트도 검사한다.
|
|
58
|
+
|
|
59
|
+
재현 가능한 결과에는 실제 원천을 확인한 시각을 `--observed-at` ISO 8601 값으로 지정하고 `--verified-source`를 함께 준다. 두 조건은 해당 파일의 종목·조건을 SEIBro에서 실제로 대조했을 때만 사용한다. 확인하지 않은 파일에는 이 플래그를 붙이지 않는다. 시각을 전달했어도 `--verified-source`가 없으면 helper는 원천 확인시각이라고 단정하지 않는다. 생략하면 입력 파일 수정시각을 대신 기록하지만, 이를 원천 확인시각으로 표현하지 않는다. 검색 결과는 고정된 compact schema만 반환하고, 원본 필드는 `detail`에서만 펼친다.
|
|
60
|
+
|
|
61
|
+
원천 확인 플래그가 없으면 helper가 SEIBro 링크나 조회 사실을 자동으로 주장하지 않는다. 대화 최종 답변에는 이번에 실제로 확인한 공식 원천 링크를 붙인다. `input_file` 메타데이터에는 파일명만 포함하고 로컬 디렉터리 경로는 노출하지 않는다.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx -y @nomadamas/k-skill@0 read korean-bond-search references/fields.md
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 2. 보강과 검증
|
|
68
|
+
|
|
69
|
+
- CB/EB/BW는 종목명에 붙은 명시적 표기, SEIBro의 `주식관련`·권리행사 정보, 조기상환 옵션을 각각 확인한다. `채권분류=일반회사채`, `옵션해당없음`, 빈 `주식관련` 칸만으로 CB/EB/BW가 없다고 판단하지 않는다.
|
|
70
|
+
- CB/EB/BW가 중요하지만 SEIBro 상세에서 구분되지 않을 때만 정확한 종목명/ISIN으로 DART를 한 번 찾아 발행결정 원문을 확인한다. 원문에서 종류가 확인되지 않으면 `미확인`으로 남긴다. PUT 등 옵션의 존재만으로 CB/EB/BW를 추정하지 않는다.
|
|
71
|
+
- 상장 여부가 필요하고 SEIBro 필드가 비어 있을 때만 KRX를 보조로 확인한다.
|
|
72
|
+
- 보조 원천은 누락값을 추정하는 데 쓰지 않고, 해당 원천이 직접 확인한 필드만 채운다.
|
|
73
|
+
- 날짜·금리·금액 원문과 정규화값이 충돌하면 원문을 보존하고 해당 필드를 `null`로 둔다.
|
|
74
|
+
- `issue_amount_krw`·`outstanding_amount_krw`는 통화가 명시적으로 KRW일 때만 채운다. 외화 또는 통화 미확인 금액은 원화로 표시하지 않고 원문에서만 확인한다.
|
|
75
|
+
- 같은 ISIN의 정규화 레코드가 서로 다른 조건을 가지면 하나를 고르지 않고 충돌로 알린다. 원천 화면/내보내기를 다시 대조한다.
|
|
76
|
+
|
|
77
|
+
### 3. 답변
|
|
78
|
+
|
|
79
|
+
helper의 기본 출력은 사용자용 `chat`이다. JSON은 계산 검증이나 후처리가 필요할 때만 `--format json`으로 요청한다. **JSON 객체, `schema_version`, `null`, 내부 failure 배열을 최종 답변에 그대로 붙이지 않는다.**
|
|
80
|
+
|
|
81
|
+
기본 검색 결과는 최대 5개이며 아래처럼 짧은 설명과 표로 보여준다.
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
종목명 | ISIN | 발행사 | 유형 | 표면금리 | 만기 | 발행잔액 | CALL/PUT | CB/EB/BW
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
표 뒤에는 후보 선택 방법을 한 문장으로 안내한다. 상세 요청일 때 발행조건과 옵션 일정을 펼친다. 금액은 조·억·만 단위로 나누어 반올림 없이 표시한다. 확인되지 않은 값은 `null`이 아니라 `미확인`으로 쓴다. 실제로 검증한 경우에만 클릭 가능한 공식 원천과 원천 확인시각을 붙인다. 열린 공식 화면에서 직접 확인한 답변은 확인한 시각을 기록한다. 입력 파일만으로 답한 경우에는 그 사실과 시각 기준을 분명히 쓰고 SEIBro 화면을 확인했다고 주장하지 않는다. 파일 수정시각을 대신 쓴 경우 실제 조회시각과 혼동하지 않도록 표시한다. 도구·helper 실행 여부 같은 내부 절차를 사용자 답변에 불필요하게 늘어놓지 않는다.
|
|
88
|
+
|
|
89
|
+
## Internal data contract
|
|
90
|
+
|
|
91
|
+
- 내부값이 없으면 추정하지 않고 `null`; 사용자 답변에서는 `미확인`
|
|
92
|
+
- `--format json` 출력 최상단에 `schema_version: "1.0"`
|
|
93
|
+
- 금리는 퍼센트 숫자, 금액은 원, 날짜는 `YYYY-MM-DD`
|
|
94
|
+
- `callable`, `putable`, `convertible`, `exchangeable`, `warrant_attached`는 확인된 경우에만 불리언
|
|
95
|
+
- 검색 결과 없음은 `empty`; 원천 장애는 `source_failure`; 파싱 실패는 `parse_failure`; 같은 ISIN 조건 충돌은 `ambiguous`
|
|
96
|
+
- 결과가 없다고 채권이 존재하지 않는다고 단정하지 않는다.
|
|
97
|
+
|
|
98
|
+
사용자용 결과는 제목 → 한 줄 요약 → 후보 표 또는 상세 조건 → 다음 선택 안내 → 출처·확인시각 순서를 유지한다.
|
|
99
|
+
|
|
100
|
+
## Failure modes
|
|
101
|
+
|
|
102
|
+
| 상황 | 동작 |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| 입력 파일 없음 | `source_failure`와 SEIBro 진입점 반환 |
|
|
105
|
+
| 빈/비정상 HTML | `parse_failure`; 브라우저에서 실제 표가 보이는지 확인 |
|
|
106
|
+
| 후보 없음 | `empty`; “제공된 조회 원천에서 확인되지 않음”이라고 표현 |
|
|
107
|
+
| 동일 종목명 충돌 | ISIN을 확인한 뒤 상세 조회 |
|
|
108
|
+
| 동일 ISIN의 발행조건 충돌 | 임의 선택 금지; 충돌 레코드를 요약하고 최신 원천에서 재확인 |
|
|
109
|
+
| CSV/HTML 헤더 중복 또는 행 길이 불일치 | 레코드를 버리거나 이어 붙이지 말고 `parse_failure` |
|
|
110
|
+
| 필드 누락·모순 | `null` 유지, 추정 금지 |
|
|
111
|
+
| 한 보조 원천 장애 | 해당 보강만 생략하고 SEIBro 결과 유지 |
|
|
112
|
+
|
|
113
|
+
CALL은 발행사 또는 제3자의 매도청구권, PUT은 사채권자의 조기상환청구권으로 구분한다. `상환청구권`만 있고 권리 주체나 조기상환 문맥이 확인되지 않으면 어느 쪽에도 분류하지 않는다. 옵션 없음이 명시되어도 CB/EB/BW 여부가 따로 확인되지 않았다면 주식연계 구조까지 없다고 확대 해석하지 않는다.
|
|
114
|
+
|
|
115
|
+
## Done when
|
|
116
|
+
|
|
117
|
+
- 모호한 요청은 최대 5개 후보로 좁혔다.
|
|
118
|
+
- 선택된 채권을 canonical schema로 정리했다.
|
|
119
|
+
- 옵션과 CB/EB/BW를 확인된 범위에서만 표시했다.
|
|
120
|
+
- 후보 검색이 전체 목록임을 입증하지 못하면 일부 확인 결과라고 밝혔다.
|
|
121
|
+
- 같은 사실을 확인하기 위한 불필요한 검색·UI·helper 중복 실행을 피했다.
|
|
122
|
+
- 원천명·조회시각·누락 또는 실패를 함께 밝혔다.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# SEIBro 필드 정규화
|
|
2
|
+
|
|
3
|
+
helper는 공백·괄호·대소문자를 정리한 뒤 아래 별칭을 인식한다. 인식하지 못한 필드는 `raw`에 남긴다.
|
|
4
|
+
|
|
5
|
+
| Canonical | 대표 원천 헤더 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `isin` | ISIN, 종목코드, 표준코드 |
|
|
8
|
+
| `name` | 종목명, 채권명 |
|
|
9
|
+
| `issuer` | 발행자, 발행사, 발행기관 |
|
|
10
|
+
| `bond_type` | 채권분류, 채권유형 |
|
|
11
|
+
| `currency` | 발행통화, 통화 |
|
|
12
|
+
| `issue_date` | 발행일 |
|
|
13
|
+
| `maturity_date` | 만기일, 상환일 |
|
|
14
|
+
| `coupon_rate_pct` | 표면금리, 이율, 쿠폰금리 |
|
|
15
|
+
| `coupon_type` | 이자지급방식, 금리유형 |
|
|
16
|
+
| `issue_amount_krw` | 발행금액, 발행액 |
|
|
17
|
+
| `outstanding_amount_krw` | 발행잔액, 잔액 |
|
|
18
|
+
| `offering_type` | 공모/사모, 모집방법 |
|
|
19
|
+
| `seniority` | 선후순위, 변제순위 |
|
|
20
|
+
| `guarantee` | 보증/무보증, 보증구분 |
|
|
21
|
+
| `listed` | 상장여부, 상장일 |
|
|
22
|
+
| `option_schedule` | 옵션일정, CALL/PUT 일정 |
|
|
23
|
+
|
|
24
|
+
ISIN은 12자리 형식과 국제 체크디지트를 검증한다. 입력 레코드의 체크디지트가 맞지 않거나 발행일이 만기일보다 늦으면 자료를 파싱 오류로 중단한다.
|
|
25
|
+
|
|
26
|
+
## 단위
|
|
27
|
+
|
|
28
|
+
- `3.25%`, `3.25` → `3.25`
|
|
29
|
+
- `1,500억원` → `150000000000`
|
|
30
|
+
- `1.2조원` → `1200000000000`
|
|
31
|
+
- `1억 5천만원` → `150000000`
|
|
32
|
+
- `1천만원` → `10000000`
|
|
33
|
+
- 헤더가 `발행금액(백만원)`이고 값이 `1500`이면 → `1500000000`
|
|
34
|
+
- `325bp` → 표면금리 `3.25`
|
|
35
|
+
- 단위 없는 금액 숫자는 원 단위로 해석한다. 숫자·단위를 일부만 파싱할 수 있는 문자열은 오독하지 않도록 미확인으로 둔다.
|
|
36
|
+
- 금액의 canonical 필드는 KRW이므로 `발행통화`가 명시적으로 `KRW`일 때만 채운다. 외화 또는 통화 미확인 금액은 원화로 재표시하지 않는다.
|
|
37
|
+
- 날짜는 `YYYY-MM-DD`, `YYYY.MM.DD`, `YYYY/MM/DD`, `YYYYMMDD`만 변환한다.
|
|
38
|
+
|
|
39
|
+
## 옵션·주식관련채
|
|
40
|
+
|
|
41
|
+
- 발행사/제3자의 `매도청구권`, `콜옵션`, `CALL`이 확인되면 `callable: true`
|
|
42
|
+
- 사채권자의 `조기상환청구권`, `풋옵션`, `PUT`이 확인되면 `putable: true`
|
|
43
|
+
- `상환청구권`만으로 권리 주체나 조기상환 여부가 확인되지 않으면 CALL/PUT을 추정하지 않는다.
|
|
44
|
+
- 옵션 필드에 옵션 없음이 명시되면 CALL과 PUT은 `false`; 옵션 필드 자체가 없으면 `null`. 다른 옵션 일정과 충돌하면 `null`로 둔다.
|
|
45
|
+
- `전환사채`/`CB`, `교환사채`/`EB`, `신주인수권부사채`/`BW`는 각각 별도 필드로 표시한다.
|
|
46
|
+
- 약어는 독립 토큰일 때만 인식한다. 회사명 일부 문자열과 우연히 겹친 경우는 판정하지 않는다.
|
|
47
|
+
- `채권분류=일반회사채`는 넓은 분류이므로 plain bond 또는 CB/EB/BW 부재를 뜻하지 않는다. `주식관련` 필드가 비었거나 옵션 일정이 없다는 이유만으로 세 구조를 `false`로 바꾸지 않는다.
|
|
48
|
+
- 세 구조가 요청의 핵심인데 SEIBro 명칭·주식관련 권리 정보로 확인되지 않으면 정확한 종목의 DART 발행결정 원문을 보조 확인한다. 원문도 확인할 수 없으면 `null`/사용자 답변의 `미확인`을 유지한다.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# 원천 메모
|
|
2
|
+
|
|
3
|
+
1. SEIBro 채권정보를 1차 원천으로 사용한다. ISIN을 알면 모바일 상세 페이지 `https://m.seibro.or.kr/cnts/bond/selectDetailSearch.do?txt_code=<ISIN>`를 직접 연다.
|
|
4
|
+
2. 종목명/발행사 검색은 사용 가능한 읽기 전용 검색 도구로 SEIBro 공식 상세 페이지를 찾는 것이 우선이다. 검색 결과는 후보 발견용이며 최종 필드 값은 열린 공식 상세 페이지에서 확인한다. 결과가 완전한지 증명되지 않으면 전수 목록처럼 말하지 않는다.
|
|
5
|
+
3. 검색 도구로 공식 상세 페이지를 열 수 없거나 대화형 입력이 꼭 필요할 때만 SEIBro 모바일 UI/브라우저 자동화를 사용한다. PC WebSquare 화면은 기본 경로가 아니다. 한 조회에서 출처 경로를 여러 개 중복 실행하지 말고, 한 번의 대체 시도 뒤에도 막히면 내보내기 파일을 요청한다.
|
|
6
|
+
4. WebSquare 화면은 단순 HTTP 요청에서 오류 안내 HTML이나 빈 껍데기를 반환할 수 있다. HTTP 200만으로 성공 판정하지 않는다. 화면에서 직접 확인한 값은 helper용 export로 수기 변환하지 않는다.
|
|
7
|
+
5. 실제 내려받은 JSON/CSV/TSV/HTML 또는 사용자 제공 export만 helper로 정규화한다. DART는 CB/EB/BW 발행결정 원문의 보조 검증에, KRX는 상장 보강에만 사용한다. 금융투자협회는 v1의 실시간 호가나 YTM 원천으로 쓰지 않는다.
|
|
8
|
+
|
|
9
|
+
각 레코드에는 `source.name`, `source.url`, `source.observed_at`, `source.observed_at_basis`를 유지한다. 기본 상태에서는 `source.name`을 `입력 자료`, `source.url`을 비움으로 저장한다. 사용자가 임의 JSON을 넣거나 테스트 픽스처를 실행해도 SEIBro 출처를 가장하지 않게 하기 위함이다.
|
|
10
|
+
|
|
11
|
+
원천 화면과 해당 입력 파일을 이번 실행에서 직접 대조한 경우에만 `--observed-at <ISO-8601> --verified-source`를 지정한다. 이때만 `source.name: "SEIBro"`, 공식 URL 및 `observed_at_basis: "source_verified"`로 기록한다. 시각만 `--observed-at`으로 전달하면 `observed_at_basis: "provided"`로 남기고 원천 확인 여부 미검증으로 표시한다. 시각 생략 시 파일 수정시각 대체값을 `file_mtime_fallback`으로 표시하며, 원천 확인시각이라고 부르지 않는다. `input_file`에는 파일명만 저장하고 로컬 경로는 보존하지 않는다. 어느 시각도 발행일과 혼동하지 않는다.
|