@yoonion/mimi-seed-mcp 0.3.32 → 0.3.34
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/README.md +219 -219
- package/dist/ai/review.js +1 -1
- package/dist/auth/google-auth.js +1 -0
- package/dist/gsc/tools.d.ts +39 -0
- package/dist/gsc/tools.js +68 -0
- package/dist/index.js +2 -0
- package/dist/prompts.js +1 -1
- package/dist/registers/ai.js +1 -1
- package/dist/registers/gsc.d.ts +2 -0
- package/dist/registers/gsc.js +80 -0
- package/dist/resources.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# @yoonion/mimi-seed-mcp
|
|
2
|
-
|
|
1
|
+
# @yoonion/mimi-seed-mcp
|
|
2
|
+
|
|
3
3
|
**Mimi Seed** — Firebase · AdMob · Google Play · App Store Connect를 AI 콘솔에서 관리. Claude Code / Codex / Cursor / 기타 MCP 클라이언트에서 한 줄 등록으로 사용.
|
|
4
|
-
|
|
5
|
-
> 이 패키지는 Mimi Seed의 **로컬 MCP 서버**만 포함합니다. 웹 콘솔(Next.js 앱)은 <https://mimi-seed.pryzm.gg/tool>.
|
|
6
|
-
|
|
7
|
-
## 설치
|
|
8
|
-
|
|
4
|
+
|
|
5
|
+
> 이 패키지는 Mimi Seed의 **로컬 MCP 서버**만 포함합니다. 웹 콘솔(Next.js 앱)은 <https://mimi-seed.pryzm.gg/tool>.
|
|
6
|
+
|
|
7
|
+
## 설치
|
|
8
|
+
|
|
9
9
|
Claude Code:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
@@ -20,216 +20,216 @@ command = "npx"
|
|
|
20
20
|
args = ["-y", "@yoonion/mimi-seed-mcp"]
|
|
21
21
|
enabled = true
|
|
22
22
|
```
|
|
23
|
-
|
|
24
|
-
Claude Desktop (`claude_desktop_config.json`):
|
|
25
|
-
|
|
26
|
-
```json
|
|
27
|
-
{
|
|
28
|
-
"mcpServers": {
|
|
29
|
-
"mimi-seed": {
|
|
30
|
-
"command": "npx",
|
|
31
|
-
"args": ["-y", "@yoonion/mimi-seed-mcp"]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## 첫 사용 전 인증
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
브라우저가 열리면 Google 계정으로 로그인. 토큰은 `~/.mimi-seed/tokens.json`에 저장되고 자동 갱신됨.
|
|
44
|
-
|
|
45
|
-
플랫폼별 추가 인증 (필요한 것만):
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
npx -y @yoonion/mimi-seed-mcp mimi-seed-appstore-auth # App Store Connect (API Key)
|
|
49
|
-
npx -y @yoonion/mimi-seed-mcp mimi-seed-playstore-auth # Google Play 서비스 계정 JSON
|
|
50
|
-
npx -y @yoonion/mimi-seed-mcp mimi-seed-bigquery-auth # BigQuery (Crashlytics export 등)
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
- **App Store Connect**: Users and Access → Keys에서 API Key 생성 후 Issuer ID / Key ID / .p8 경로 입력 → `~/.mimi-seed/appstore.json`
|
|
54
|
-
- **Google Play**: Play Console 서비스 계정 JSON 경로 입력 (패키지별 등록)
|
|
55
|
-
- **BigQuery**: Google OAuth 또는 서비스 계정으로 데이터셋 조회 권한 부여
|
|
56
|
-
|
|
57
|
-
AI 기능(릴리즈 노트 생성, 리뷰 답변)을 쓰려면:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
export ANTHROPIC_API_KEY=sk-ant-...
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## 제공 도구 (110+개)
|
|
66
|
-
|
|
67
|
-
| 영역 | 도구 수 | 주요 도구 |
|
|
68
|
-
|------|---------|-----------|
|
|
69
|
-
| App Store Connect | 30 | `appstore_submit_for_review` / `appstore_upload_screenshot` / `appstore_update_whats_new` / `appstore_create_version` |
|
|
70
|
-
| Google Play | 26 | `playstore_submit_release` / `playstore_promote_release` / `playstore_replace_images` / `playstore_reply_review` / `playstore_verify_service_account` |
|
|
71
|
-
| Firebase | 17 | `firebase_create_android_app` / `firebase_get_android_config` / `firebase_create_ios_app` / `firebase_enable_service` |
|
|
72
|
-
| AdMob | 7 | `admob_list_apps` / `admob_create_ad_unit` / `admob_get_today_earnings` / `admob_get_report` |
|
|
73
|
-
| CI/CD (GitHub Actions · GitLab) | 6 | `ci_trigger_build` / `ci_get_build_status` / `ci_list_workflows` / `ci_cancel_build` |
|
|
74
|
-
| Facebook | 6 | `facebook_post_photo` / `facebook_post_multi_photo` / `facebook_list_pages` |
|
|
75
|
-
| Google Cloud IAM | 5 | `iam_create_service_account` / `iam_create_key` / `iam_add_iam_policy_binding` |
|
|
76
|
-
| BigQuery | 5 | `bigquery_run_query` / `bigquery_list_datasets` / `bigquery_get_table_schema` |
|
|
77
|
-
| 점검 / 위험 | 4 | `playstore_check_submission_risks` / `appstore_check_submission_risks` / `screenshot_validate` / `release_status` |
|
|
78
|
-
| Instagram | 4 | `instagram_post_image` / `instagram_post_carousel` / `instagram_save_config` |
|
|
79
|
-
| AI (Claude) | 2 | `generate_release_notes_from_commits` / `generate_review_reply` |
|
|
80
|
-
| 인증 | 2 | `mimi_seed_auth_start` / `mimi_seed_auth_status` |
|
|
81
|
-
|
|
82
|
-
> 인앱 결제(IAP·구독) 도구는 위 Play Store·App Store 카운트에 포함됩니다 — `playstore_create_subscription` · `appstore_create_inapp_purchase` 등 (`@onesub/providers` 위임).
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## 슬래시 커맨드 (MCP Prompts)
|
|
87
|
-
|
|
23
|
+
|
|
24
|
+
Claude Desktop (`claude_desktop_config.json`):
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"mimi-seed": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["-y", "@yoonion/mimi-seed-mcp"]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 첫 사용 전 인증
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
브라우저가 열리면 Google 계정으로 로그인. 토큰은 `~/.mimi-seed/tokens.json`에 저장되고 자동 갱신됨.
|
|
44
|
+
|
|
45
|
+
플랫폼별 추가 인증 (필요한 것만):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx -y @yoonion/mimi-seed-mcp mimi-seed-appstore-auth # App Store Connect (API Key)
|
|
49
|
+
npx -y @yoonion/mimi-seed-mcp mimi-seed-playstore-auth # Google Play 서비스 계정 JSON
|
|
50
|
+
npx -y @yoonion/mimi-seed-mcp mimi-seed-bigquery-auth # BigQuery (Crashlytics export 등)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- **App Store Connect**: Users and Access → Keys에서 API Key 생성 후 Issuer ID / Key ID / .p8 경로 입력 → `~/.mimi-seed/appstore.json`
|
|
54
|
+
- **Google Play**: Play Console 서비스 계정 JSON 경로 입력 (패키지별 등록)
|
|
55
|
+
- **BigQuery**: Google OAuth 또는 서비스 계정으로 데이터셋 조회 권한 부여
|
|
56
|
+
|
|
57
|
+
AI 기능(릴리즈 노트 생성, 리뷰 답변)을 쓰려면:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 제공 도구 (110+개)
|
|
66
|
+
|
|
67
|
+
| 영역 | 도구 수 | 주요 도구 |
|
|
68
|
+
|------|---------|-----------|
|
|
69
|
+
| App Store Connect | 30 | `appstore_submit_for_review` / `appstore_upload_screenshot` / `appstore_update_whats_new` / `appstore_create_version` |
|
|
70
|
+
| Google Play | 26 | `playstore_submit_release` / `playstore_promote_release` / `playstore_replace_images` / `playstore_reply_review` / `playstore_verify_service_account` |
|
|
71
|
+
| Firebase | 17 | `firebase_create_android_app` / `firebase_get_android_config` / `firebase_create_ios_app` / `firebase_enable_service` |
|
|
72
|
+
| AdMob | 7 | `admob_list_apps` / `admob_create_ad_unit` / `admob_get_today_earnings` / `admob_get_report` |
|
|
73
|
+
| CI/CD (GitHub Actions · GitLab) | 6 | `ci_trigger_build` / `ci_get_build_status` / `ci_list_workflows` / `ci_cancel_build` |
|
|
74
|
+
| Facebook | 6 | `facebook_post_photo` / `facebook_post_multi_photo` / `facebook_list_pages` |
|
|
75
|
+
| Google Cloud IAM | 5 | `iam_create_service_account` / `iam_create_key` / `iam_add_iam_policy_binding` |
|
|
76
|
+
| BigQuery | 5 | `bigquery_run_query` / `bigquery_list_datasets` / `bigquery_get_table_schema` |
|
|
77
|
+
| 점검 / 위험 | 4 | `playstore_check_submission_risks` / `appstore_check_submission_risks` / `screenshot_validate` / `release_status` |
|
|
78
|
+
| Instagram | 4 | `instagram_post_image` / `instagram_post_carousel` / `instagram_save_config` |
|
|
79
|
+
| AI (Claude) | 2 | `generate_release_notes_from_commits` / `generate_review_reply` |
|
|
80
|
+
| 인증 | 2 | `mimi_seed_auth_start` / `mimi_seed_auth_status` |
|
|
81
|
+
|
|
82
|
+
> 인앱 결제(IAP·구독) 도구는 위 Play Store·App Store 카운트에 포함됩니다 — `playstore_create_subscription` · `appstore_create_inapp_purchase` 등 (`@onesub/providers` 위임).
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 슬래시 커맨드 (MCP Prompts)
|
|
87
|
+
|
|
88
88
|
MCP 클라이언트(Claude Code, Codex 등)에서 슬래시 커맨드로 바로 노출됩니다.
|
|
89
|
-
|
|
90
|
-
| 커맨드 | 설명 |
|
|
91
|
-
|--------|------|
|
|
92
|
-
| `/mimi-seed:deploy` | 블로커 점검 → 릴리즈 노트 생성 → 스토어 적용을 한 번에 |
|
|
93
|
-
| `/mimi-seed:health` | 인증 상태 + 앱 출시 준비도 빠른 요약 |
|
|
94
|
-
| `/mimi-seed:review-inbox` | 미답변 리뷰 조회 → AI 답변 초안 생성 |
|
|
95
|
-
|
|
96
|
-
## MCP Resources
|
|
97
|
-
|
|
98
|
-
| URI | 설명 |
|
|
99
|
-
|-----|------|
|
|
100
|
-
| `mimi-seed://auth/status` | Google OAuth 토큰 상태 (JSON) |
|
|
101
|
-
| `mimi-seed://agent/guide` | 에이전트 역할 정의 — 출시 워크플로우·주의사항 (Markdown) |
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## 주요 기능
|
|
106
|
-
|
|
107
|
-
### 제출 위험 점검
|
|
108
|
-
|
|
109
|
-
출시 전 블로커와 경고를 자동으로 점검합니다.
|
|
110
|
-
|
|
111
|
-
```
|
|
112
|
-
"내 앱 출시 전 위험 요소 확인해줘"
|
|
113
|
-
→ playstore_check_submission_risks("com.example.myapp")
|
|
114
|
-
→ appstore_check_submission_risks("1234567890")
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
**점검 항목:**
|
|
118
|
-
- Google Play: 리스팅 완성도(제목/설명/짧은설명), 스크린샷 수, 아이콘, 내부 빌드 존재, 연락처
|
|
119
|
-
- App Store: What's New, 설명/키워드, 스크린샷 커버리지, TestFlight 빌드, 개인정보처리방침 URL
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
### 스크린샷 해상도 검증
|
|
124
|
-
|
|
125
|
-
업로드 전 로컬 파일을 스토어 규격과 비교합니다.
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
"이 스크린샷들이 App Store 규격에 맞는지 확인해줘"
|
|
129
|
-
→ screenshot_validate(["/path/to/screen1.png", "/path/to/screen2.png"], platform="ios", displayType="APP_IPHONE_69")
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
iOS displayType 예시: `APP_IPHONE_69`, `APP_IPHONE_67`, `APP_IPHONE_65`, `APP_IPAD_PRO_3GEN_129`
|
|
133
|
-
Android imageType 예시: `phoneScreenshots`, `sevenInchScreenshots`, `featureGraphic`
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
### AI 릴리즈 노트 생성 (ANTHROPIC_API_KEY 필요)
|
|
138
|
-
|
|
139
|
-
git 커밋 내역을 Claude가 사용자 친화적인 릴리즈 노트로 변환합니다.
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
"최근 커밋으로 릴리즈 노트 만들어줘"
|
|
143
|
-
→ generate_release_notes_from_commits(
|
|
144
|
-
commits=[{message: "feat: 다크모드 추가"}, ...],
|
|
145
|
-
appName="MyApp",
|
|
146
|
-
locales=["ko", "en-US", "ja"]
|
|
147
|
-
)
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
3가지 톤(간결/상세/마케팅) + 다국어를 한 번에 생성. 이후 `playstore_update_release_notes` 또는 `appstore_update_whats_new`로 바로 적용.
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
### AI 리뷰 답변 생성 (ANTHROPIC_API_KEY 필요)
|
|
155
|
-
|
|
156
|
-
스토어 리뷰에 대한 AI 답변 초안을 생성합니다.
|
|
157
|
-
|
|
158
|
-
```
|
|
159
|
-
"이 리뷰에 답변 작성해줘"
|
|
160
|
-
→ generate_review_reply(
|
|
161
|
-
reviewText="앱이 자꾸 튕겨요",
|
|
162
|
-
rating=2,
|
|
163
|
-
appName="MyApp",
|
|
164
|
-
tone="empathetic",
|
|
165
|
-
language="ko"
|
|
166
|
-
)
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
tone 옵션: `friendly`(친근) / `professional`(정중) / `empathetic`(공감) / `brief`(간결)
|
|
170
|
-
|
|
171
|
-
> ⚠ AI 생성 답변은 초안입니다. 게시 전 반드시 검토하세요.
|
|
172
|
-
> 답변 게시는 `
|
|
173
|
-
|
|
174
|
-
---
|
|
175
|
-
|
|
176
|
-
## End-to-end: 서비스 계정 → JSON 키 → Play Console 권한
|
|
177
|
-
|
|
178
|
-
서버(예: [onesub](https://github.com/jeonghwanko/onesub))가 Google Play 영수증을 백그라운드로 검증하려면 서비스 계정 JSON이 필요합니다. Claude에게 한 번에 시킬 수 있어요:
|
|
179
|
-
|
|
180
|
-
> 1. `my-project`에 `onesub-play-verifier` 서비스 계정 만들고
|
|
181
|
-
> 2. JSON 키 발급받아서
|
|
182
|
-
> 3. `com.yourapp.id`에 대해 검증
|
|
183
|
-
|
|
184
|
-
Claude가 연쇄 호출:
|
|
185
|
-
|
|
186
|
-
- `iam_create_service_account("my-project", "onesub-play-verifier", "onesub Play verifier")`
|
|
187
|
-
- `iam_create_key("onesub-play-verifier@my-project.iam.gserviceaccount.com")` → JSON 반환
|
|
188
|
-
- `playstore_verify_service_account(<json>, "com.yourapp.id")` → 아직 Play Console 권한이 없어서 403 반환 기대
|
|
189
|
-
|
|
190
|
-
그 다음 **Play Console에서 수동으로** (또는 별도 androidpublisher.users API 호출):
|
|
191
|
-
|
|
192
|
-
- Users and permissions → 서비스 계정 이메일 초대
|
|
193
|
-
- **View financial data, orders, and cancellation survey responses** 체크
|
|
194
|
-
- **~5분 대기** 후 `playstore_verify_service_account` 재실행 → ✓
|
|
195
|
-
|
|
196
|
-
마지막으로 JSON을 `GOOGLE_SERVICE_ACCOUNT_KEY` 서버 env에 넣으면 Play 영수증 검증 가능.
|
|
197
|
-
|
|
198
|
-
> Cloud IAM 역할과 Play Console 권한은 다릅니다. `iam_add_iam_policy_binding`은 Cloud IAM 역할(예: `roles/iam.serviceAccountTokenCreator`)만 부여 — Play Console의 "View financial data"는 별도.
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
## 환경변수
|
|
203
|
-
|
|
204
|
-
| 변수 | 설명 |
|
|
205
|
-
|------|------|
|
|
206
|
-
| `ANTHROPIC_API_KEY` | AI 릴리즈 노트 생성 / 리뷰 답변 활성화 (선택) |
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
## 레거시 호환성
|
|
211
|
-
|
|
212
|
-
Preseed 시절(`~/.preseed/`) 데이터는 자동으로 이어받음:
|
|
213
|
-
|
|
214
|
-
- `~/.preseed/tokens.json` 있으면 읽음 (재인증 불필요)
|
|
215
|
-
- `~/.preseed/appstore.json`도 동일
|
|
216
|
-
- 환경변수 `PRESEED_GOOGLE_CLIENT_ID` / `PRESEED_GOOGLE_CLIENT_SECRET` 계속 인식
|
|
217
|
-
|
|
218
|
-
새로 쓰는 건 `~/.mimi-seed/`.
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
## Links
|
|
223
|
-
|
|
224
|
-
- CLI 패키지: [`mimi-seed`](https://www.npmjs.com/package/mimi-seed)
|
|
225
|
-
- 웹 콘솔: <https://mimi-seed.pryzm.gg/tool>
|
|
226
|
-
- 저장소: <https://github.com/jeonghwanko/mimi-seed>
|
|
227
|
-
|
|
228
|
-
---
|
|
229
|
-
|
|
230
|
-
## License
|
|
231
|
-
|
|
232
|
-
[PolyForm Noncommercial License 1.0.0](../../LICENSE) — 비상업적 사용만 허용.
|
|
233
|
-
상업적 이용 문의: turbo08@gmail.com
|
|
234
|
-
|
|
235
|
-
**Required Notice:** Copyright 2026 Pryzm GG (https://mimi-seed.pryzm.gg)
|
|
89
|
+
|
|
90
|
+
| 커맨드 | 설명 |
|
|
91
|
+
|--------|------|
|
|
92
|
+
| `/mimi-seed:deploy` | 블로커 점검 → 릴리즈 노트 생성 → 스토어 적용을 한 번에 |
|
|
93
|
+
| `/mimi-seed:health` | 인증 상태 + 앱 출시 준비도 빠른 요약 |
|
|
94
|
+
| `/mimi-seed:review-inbox` | 미답변 리뷰 조회 → AI 답변 초안 생성 |
|
|
95
|
+
|
|
96
|
+
## MCP Resources
|
|
97
|
+
|
|
98
|
+
| URI | 설명 |
|
|
99
|
+
|-----|------|
|
|
100
|
+
| `mimi-seed://auth/status` | Google OAuth 토큰 상태 (JSON) |
|
|
101
|
+
| `mimi-seed://agent/guide` | 에이전트 역할 정의 — 출시 워크플로우·주의사항 (Markdown) |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 주요 기능
|
|
106
|
+
|
|
107
|
+
### 제출 위험 점검
|
|
108
|
+
|
|
109
|
+
출시 전 블로커와 경고를 자동으로 점검합니다.
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
"내 앱 출시 전 위험 요소 확인해줘"
|
|
113
|
+
→ playstore_check_submission_risks("com.example.myapp")
|
|
114
|
+
→ appstore_check_submission_risks("1234567890")
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**점검 항목:**
|
|
118
|
+
- Google Play: 리스팅 완성도(제목/설명/짧은설명), 스크린샷 수, 아이콘, 내부 빌드 존재, 연락처
|
|
119
|
+
- App Store: What's New, 설명/키워드, 스크린샷 커버리지, TestFlight 빌드, 개인정보처리방침 URL
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### 스크린샷 해상도 검증
|
|
124
|
+
|
|
125
|
+
업로드 전 로컬 파일을 스토어 규격과 비교합니다.
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
"이 스크린샷들이 App Store 규격에 맞는지 확인해줘"
|
|
129
|
+
→ screenshot_validate(["/path/to/screen1.png", "/path/to/screen2.png"], platform="ios", displayType="APP_IPHONE_69")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
iOS displayType 예시: `APP_IPHONE_69`, `APP_IPHONE_67`, `APP_IPHONE_65`, `APP_IPAD_PRO_3GEN_129`
|
|
133
|
+
Android imageType 예시: `phoneScreenshots`, `sevenInchScreenshots`, `featureGraphic`
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### AI 릴리즈 노트 생성 (ANTHROPIC_API_KEY 필요)
|
|
138
|
+
|
|
139
|
+
git 커밋 내역을 Claude가 사용자 친화적인 릴리즈 노트로 변환합니다.
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
"최근 커밋으로 릴리즈 노트 만들어줘"
|
|
143
|
+
→ generate_release_notes_from_commits(
|
|
144
|
+
commits=[{message: "feat: 다크모드 추가"}, ...],
|
|
145
|
+
appName="MyApp",
|
|
146
|
+
locales=["ko", "en-US", "ja"]
|
|
147
|
+
)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
3가지 톤(간결/상세/마케팅) + 다국어를 한 번에 생성. 이후 `playstore_update_release_notes` 또는 `appstore_update_whats_new`로 바로 적용.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
### AI 리뷰 답변 생성 (ANTHROPIC_API_KEY 필요)
|
|
155
|
+
|
|
156
|
+
스토어 리뷰에 대한 AI 답변 초안을 생성합니다.
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
"이 리뷰에 답변 작성해줘"
|
|
160
|
+
→ generate_review_reply(
|
|
161
|
+
reviewText="앱이 자꾸 튕겨요",
|
|
162
|
+
rating=2,
|
|
163
|
+
appName="MyApp",
|
|
164
|
+
tone="empathetic",
|
|
165
|
+
language="ko"
|
|
166
|
+
)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
tone 옵션: `friendly`(친근) / `professional`(정중) / `empathetic`(공감) / `brief`(간결)
|
|
170
|
+
|
|
171
|
+
> ⚠ AI 생성 답변은 초안입니다. 게시 전 반드시 검토하세요.
|
|
172
|
+
> 답변 게시는 `playstore_reply_review` 도구를 사용하세요.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## End-to-end: 서비스 계정 → JSON 키 → Play Console 권한
|
|
177
|
+
|
|
178
|
+
서버(예: [onesub](https://github.com/jeonghwanko/onesub))가 Google Play 영수증을 백그라운드로 검증하려면 서비스 계정 JSON이 필요합니다. Claude에게 한 번에 시킬 수 있어요:
|
|
179
|
+
|
|
180
|
+
> 1. `my-project`에 `onesub-play-verifier` 서비스 계정 만들고
|
|
181
|
+
> 2. JSON 키 발급받아서
|
|
182
|
+
> 3. `com.yourapp.id`에 대해 검증
|
|
183
|
+
|
|
184
|
+
Claude가 연쇄 호출:
|
|
185
|
+
|
|
186
|
+
- `iam_create_service_account("my-project", "onesub-play-verifier", "onesub Play verifier")`
|
|
187
|
+
- `iam_create_key("onesub-play-verifier@my-project.iam.gserviceaccount.com")` → JSON 반환
|
|
188
|
+
- `playstore_verify_service_account(<json>, "com.yourapp.id")` → 아직 Play Console 권한이 없어서 403 반환 기대
|
|
189
|
+
|
|
190
|
+
그 다음 **Play Console에서 수동으로** (또는 별도 androidpublisher.users API 호출):
|
|
191
|
+
|
|
192
|
+
- Users and permissions → 서비스 계정 이메일 초대
|
|
193
|
+
- **View financial data, orders, and cancellation survey responses** 체크
|
|
194
|
+
- **~5분 대기** 후 `playstore_verify_service_account` 재실행 → ✓
|
|
195
|
+
|
|
196
|
+
마지막으로 JSON을 `GOOGLE_SERVICE_ACCOUNT_KEY` 서버 env에 넣으면 Play 영수증 검증 가능.
|
|
197
|
+
|
|
198
|
+
> Cloud IAM 역할과 Play Console 권한은 다릅니다. `iam_add_iam_policy_binding`은 Cloud IAM 역할(예: `roles/iam.serviceAccountTokenCreator`)만 부여 — Play Console의 "View financial data"는 별도.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## 환경변수
|
|
203
|
+
|
|
204
|
+
| 변수 | 설명 |
|
|
205
|
+
|------|------|
|
|
206
|
+
| `ANTHROPIC_API_KEY` | AI 릴리즈 노트 생성 / 리뷰 답변 활성화 (선택) |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 레거시 호환성
|
|
211
|
+
|
|
212
|
+
Preseed 시절(`~/.preseed/`) 데이터는 자동으로 이어받음:
|
|
213
|
+
|
|
214
|
+
- `~/.preseed/tokens.json` 있으면 읽음 (재인증 불필요)
|
|
215
|
+
- `~/.preseed/appstore.json`도 동일
|
|
216
|
+
- 환경변수 `PRESEED_GOOGLE_CLIENT_ID` / `PRESEED_GOOGLE_CLIENT_SECRET` 계속 인식
|
|
217
|
+
|
|
218
|
+
새로 쓰는 건 `~/.mimi-seed/`.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Links
|
|
223
|
+
|
|
224
|
+
- CLI 패키지: [`mimi-seed`](https://www.npmjs.com/package/mimi-seed)
|
|
225
|
+
- 웹 콘솔: <https://mimi-seed.pryzm.gg/tool>
|
|
226
|
+
- 저장소: <https://github.com/jeonghwanko/mimi-seed>
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
[PolyForm Noncommercial License 1.0.0](../../LICENSE) — 비상업적 사용만 허용.
|
|
233
|
+
상업적 이용 문의: turbo08@gmail.com
|
|
234
|
+
|
|
235
|
+
**Required Notice:** Copyright 2026 Pryzm GG (https://mimi-seed.pryzm.gg)
|
package/dist/ai/review.js
CHANGED
package/dist/auth/google-auth.js
CHANGED
|
@@ -13,6 +13,7 @@ const SCOPES = [
|
|
|
13
13
|
'https://www.googleapis.com/auth/admob.monetization',
|
|
14
14
|
'https://www.googleapis.com/auth/androidpublisher',
|
|
15
15
|
'https://www.googleapis.com/auth/adwords', // Google Ads API (googleads_* tools)
|
|
16
|
+
'https://www.googleapis.com/auth/webmasters', // Search Console API (gsc_* tools, 사이트맵 제출 포함)
|
|
16
17
|
];
|
|
17
18
|
// Primary config dir. Legacy `~/.preseed` is read as a fallback during the
|
|
18
19
|
// rebrand so existing auth sessions don't force a re-login; new writes go to
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { OAuth2Client } from 'google-auth-library';
|
|
2
|
+
export type GscAuth = OAuth2Client;
|
|
3
|
+
export declare function listSites(auth: GscAuth): Promise<import("googleapis").searchconsole_v1.Schema$WmxSite[]>;
|
|
4
|
+
export declare function listSitemaps(auth: GscAuth, siteUrl: string, sitemapIndex?: string): Promise<import("googleapis").searchconsole_v1.Schema$WmxSitemap[]>;
|
|
5
|
+
export declare function getSitemap(auth: GscAuth, siteUrl: string, feedpath: string): Promise<import("googleapis").searchconsole_v1.Schema$WmxSitemap>;
|
|
6
|
+
/** 사이트맵 제출 — webmasters(read-write) 스코프 필요. 응답 본문은 없음(204). */
|
|
7
|
+
export declare function submitSitemap(auth: GscAuth, siteUrl: string, feedpath: string): Promise<{
|
|
8
|
+
submitted: string;
|
|
9
|
+
siteUrl: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function inspectUrl(auth: GscAuth, siteUrl: string, inspectionUrl: string, languageCode?: string): Promise<import("googleapis").searchconsole_v1.Schema$UrlInspectionResult>;
|
|
12
|
+
export interface SearchAnalyticsParams {
|
|
13
|
+
startDate: string;
|
|
14
|
+
endDate: string;
|
|
15
|
+
dimensions?: string[];
|
|
16
|
+
rowLimit?: number;
|
|
17
|
+
startRow?: number;
|
|
18
|
+
type?: 'web' | 'image' | 'video' | 'news' | 'discover' | 'googleNews';
|
|
19
|
+
}
|
|
20
|
+
export declare function searchAnalytics(auth: GscAuth, siteUrl: string, params: SearchAnalyticsParams): Promise<import("googleapis").searchconsole_v1.Schema$ApiDataRow[]>;
|
|
21
|
+
export interface SearchAnalyticsRow {
|
|
22
|
+
keys?: string[] | null;
|
|
23
|
+
clicks?: number | null;
|
|
24
|
+
impressions?: number | null;
|
|
25
|
+
ctr?: number | null;
|
|
26
|
+
position?: number | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Search Analytics rows 요약.
|
|
30
|
+
* position 은 노출수(impressions) 가중 평균으로 집계한다 — 단순 산술평균은
|
|
31
|
+
* 노출이 1인 행과 1000인 행을 동등 취급해 실제 평균 순위를 왜곡한다.
|
|
32
|
+
*/
|
|
33
|
+
export declare function summarizeRows(rows: SearchAnalyticsRow[]): {
|
|
34
|
+
rowCount: number;
|
|
35
|
+
totalClicks: number;
|
|
36
|
+
totalImpressions: number;
|
|
37
|
+
avgCtr: number;
|
|
38
|
+
avgPosition: number;
|
|
39
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { google } from 'googleapis';
|
|
2
|
+
/**
|
|
3
|
+
* Google Search Console (Webmasters) API v1 래퍼.
|
|
4
|
+
*
|
|
5
|
+
* `searchconsole('v1')` 은 구 `webmasters('v3')` 의 후속으로, sites/sitemaps/
|
|
6
|
+
* searchanalytics 에 더해 URL Inspection(`urlInspection.index.inspect`)을 포함한다.
|
|
7
|
+
* 인증은 mimi-seed OAuth 클라이언트(`requireAuth()`)를 그대로 사용 — webmasters 스코프 필요.
|
|
8
|
+
*/
|
|
9
|
+
const sc = () => google.searchconsole('v1');
|
|
10
|
+
// ─── 속성(사이트) 목록 ───
|
|
11
|
+
export async function listSites(auth) {
|
|
12
|
+
const res = await sc().sites.list({ auth });
|
|
13
|
+
return res.data.siteEntry ?? [];
|
|
14
|
+
}
|
|
15
|
+
// ─── 사이트맵 ───
|
|
16
|
+
export async function listSitemaps(auth, siteUrl, sitemapIndex) {
|
|
17
|
+
const res = await sc().sitemaps.list({ auth, siteUrl, sitemapIndex });
|
|
18
|
+
return res.data.sitemap ?? [];
|
|
19
|
+
}
|
|
20
|
+
export async function getSitemap(auth, siteUrl, feedpath) {
|
|
21
|
+
const res = await sc().sitemaps.get({ auth, siteUrl, feedpath });
|
|
22
|
+
return res.data;
|
|
23
|
+
}
|
|
24
|
+
/** 사이트맵 제출 — webmasters(read-write) 스코프 필요. 응답 본문은 없음(204). */
|
|
25
|
+
export async function submitSitemap(auth, siteUrl, feedpath) {
|
|
26
|
+
await sc().sitemaps.submit({ auth, siteUrl, feedpath });
|
|
27
|
+
return { submitted: feedpath, siteUrl };
|
|
28
|
+
}
|
|
29
|
+
// ─── URL 색인 검사 ───
|
|
30
|
+
export async function inspectUrl(auth, siteUrl, inspectionUrl, languageCode = 'en-US') {
|
|
31
|
+
const res = await sc().urlInspection.index.inspect({
|
|
32
|
+
auth,
|
|
33
|
+
requestBody: { siteUrl, inspectionUrl, languageCode },
|
|
34
|
+
});
|
|
35
|
+
return res.data.inspectionResult ?? {};
|
|
36
|
+
}
|
|
37
|
+
export async function searchAnalytics(auth, siteUrl, params) {
|
|
38
|
+
const res = await sc().searchanalytics.query({
|
|
39
|
+
auth,
|
|
40
|
+
siteUrl,
|
|
41
|
+
requestBody: {
|
|
42
|
+
startDate: params.startDate,
|
|
43
|
+
endDate: params.endDate,
|
|
44
|
+
dimensions: params.dimensions,
|
|
45
|
+
rowLimit: params.rowLimit ?? 1000,
|
|
46
|
+
startRow: params.startRow,
|
|
47
|
+
type: params.type,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
return res.data.rows ?? [];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Search Analytics rows 요약.
|
|
54
|
+
* position 은 노출수(impressions) 가중 평균으로 집계한다 — 단순 산술평균은
|
|
55
|
+
* 노출이 1인 행과 1000인 행을 동등 취급해 실제 평균 순위를 왜곡한다.
|
|
56
|
+
*/
|
|
57
|
+
export function summarizeRows(rows) {
|
|
58
|
+
const totalClicks = rows.reduce((s, r) => s + (r.clicks ?? 0), 0);
|
|
59
|
+
const totalImpressions = rows.reduce((s, r) => s + (r.impressions ?? 0), 0);
|
|
60
|
+
const weightedPos = rows.reduce((s, r) => s + (r.position ?? 0) * (r.impressions ?? 0), 0);
|
|
61
|
+
return {
|
|
62
|
+
rowCount: rows.length,
|
|
63
|
+
totalClicks,
|
|
64
|
+
totalImpressions,
|
|
65
|
+
avgCtr: totalImpressions > 0 ? Math.round((totalClicks / totalImpressions) * 10000) / 10000 : 0,
|
|
66
|
+
avgPosition: totalImpressions > 0 ? Math.round((weightedPos / totalImpressions) * 100) / 100 : 0,
|
|
67
|
+
};
|
|
68
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { registerCiTools } from './registers/ci.js';
|
|
|
15
15
|
import { registerInstagramTools } from './registers/instagram.js';
|
|
16
16
|
import { registerFacebookTools } from './registers/facebook.js';
|
|
17
17
|
import { registerGoogleAdsTools } from './registers/googleads.js';
|
|
18
|
+
import { registerGscTools } from './registers/gsc.js';
|
|
18
19
|
import { registerPrompts } from './prompts.js';
|
|
19
20
|
import { registerResources } from './resources.js';
|
|
20
21
|
// dist/index.js 기준 ../package.json — npm 패키지 루트의 버전을 단일 출처로 사용.
|
|
@@ -37,6 +38,7 @@ registerCiTools(server);
|
|
|
37
38
|
registerInstagramTools(server);
|
|
38
39
|
registerFacebookTools(server);
|
|
39
40
|
registerGoogleAdsTools(server);
|
|
41
|
+
registerGscTools(server);
|
|
40
42
|
registerPrompts(server);
|
|
41
43
|
registerResources(server);
|
|
42
44
|
// `npx -y @yoonion/mimi-seed-mcp <subcommand>` 처리.
|
package/dist/prompts.js
CHANGED
|
@@ -61,7 +61,7 @@ export function registerPrompts(server) {
|
|
|
61
61
|
'3. 각 리뷰에 generate_review_reply 로 답변 초안 생성',
|
|
62
62
|
` 톤: ${tone ?? 'empathetic'}`,
|
|
63
63
|
'4. 초안 보여주고 게시 여부 확인 (비가역 — 반드시 동의 받을 것)',
|
|
64
|
-
'5. 확인 후
|
|
64
|
+
'5. 확인 후 playstore_reply_review 로 게시',
|
|
65
65
|
'',
|
|
66
66
|
'⚠️ AI 생성 답변은 초안입니다. 게시 전 반드시 검토하세요.',
|
|
67
67
|
].join('\n'),
|
package/dist/registers/ai.js
CHANGED
|
@@ -32,7 +32,7 @@ export function registerAiTools(server) {
|
|
|
32
32
|
'tone: friendly(친근) / professional(정중) / empathetic(공감) / brief(간결) — 기본: friendly',
|
|
33
33
|
'language: ko / en / ja / zh 등 — 기본: ko',
|
|
34
34
|
'⚠ 생성된 답변은 초안입니다. 게시 전 반드시 검토하세요.',
|
|
35
|
-
'답변 게시는
|
|
35
|
+
'답변 게시는 playstore_reply_review 도구를 사용하세요.',
|
|
36
36
|
].join(' '), {
|
|
37
37
|
reviewText: z.string().describe('리뷰 원문'),
|
|
38
38
|
rating: z.number().min(1).max(5).optional().describe('별점 (1~5)'),
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { requireAuth } from '../helpers.js';
|
|
3
|
+
import * as gsc from '../gsc/tools.js';
|
|
4
|
+
const SITE_URL_DESC = "Search Console 속성 식별자. 도메인 속성은 'sc-domain:example.com', URL 접두어 속성은 'https://example.com/' 형식.";
|
|
5
|
+
export function registerGscTools(server) {
|
|
6
|
+
server.tool('gsc_list_sites', 'Search Console에 등록된(권한 있는) 속성 목록 + 권한 레벨 조회. siteUrl 값을 확인할 때 먼저 호출.', {}, async () => {
|
|
7
|
+
const auth = await requireAuth();
|
|
8
|
+
const sites = await gsc.listSites(auth);
|
|
9
|
+
return { content: [{ type: 'text', text: JSON.stringify(sites, null, 2) }] };
|
|
10
|
+
});
|
|
11
|
+
server.tool('gsc_list_sitemaps', '속성에 제출된 사이트맵 목록 (마지막 다운로드 시각, 경고/오류 수, submitted/indexed 카운트). ⚠️ 사이트맵 리포트의 indexed 수치는 신뢰도 낮음 — 실제 색인 여부는 gsc_inspect_url 로 확인.', {
|
|
12
|
+
siteUrl: z.string().describe(SITE_URL_DESC),
|
|
13
|
+
sitemapIndex: z.string().optional().describe('사이트맵 인덱스 URL — 인덱스 하위 사이트맵만 보고 싶을 때'),
|
|
14
|
+
}, async ({ siteUrl, sitemapIndex }) => {
|
|
15
|
+
const auth = await requireAuth();
|
|
16
|
+
const sitemaps = await gsc.listSitemaps(auth, siteUrl, sitemapIndex);
|
|
17
|
+
return { content: [{ type: 'text', text: JSON.stringify(sitemaps, null, 2) }] };
|
|
18
|
+
});
|
|
19
|
+
server.tool('gsc_get_sitemap', '특정 사이트맵 1개의 상세(타입별 submitted/indexed, 경고/오류, 처리 시각) 조회.', {
|
|
20
|
+
siteUrl: z.string().describe(SITE_URL_DESC),
|
|
21
|
+
feedpath: z.string().describe('사이트맵 전체 URL (예: https://example.com/sitemap.xml)'),
|
|
22
|
+
}, async ({ siteUrl, feedpath }) => {
|
|
23
|
+
const auth = await requireAuth();
|
|
24
|
+
const sitemap = await gsc.getSitemap(auth, siteUrl, feedpath);
|
|
25
|
+
return { content: [{ type: 'text', text: JSON.stringify(sitemap, null, 2) }] };
|
|
26
|
+
});
|
|
27
|
+
server.tool('gsc_submit_sitemap', '사이트맵을 Search Console에 제출(또는 재제출)해 재크롤을 유도. webmasters read-write 스코프 필요.', {
|
|
28
|
+
siteUrl: z.string().describe(SITE_URL_DESC),
|
|
29
|
+
feedpath: z.string().describe('제출할 사이트맵 전체 URL (예: https://example.com/sitemap.xml)'),
|
|
30
|
+
}, async ({ siteUrl, feedpath }) => {
|
|
31
|
+
const auth = await requireAuth();
|
|
32
|
+
const result = await gsc.submitSitemap(auth, siteUrl, feedpath);
|
|
33
|
+
return {
|
|
34
|
+
content: [{
|
|
35
|
+
type: 'text',
|
|
36
|
+
text: `✅ 사이트맵 제출 완료.\n ${result.submitted}\n\n반영까지 수 분~수 시간 걸려. gsc_list_sitemaps 로 lastDownloaded 갱신을 확인해.`,
|
|
37
|
+
}],
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
server.tool('gsc_inspect_url', 'URL 1개의 실제 색인 상태 검사 (coverageState, robots.txt 허용 여부, 마지막 크롤 시각, 정규 URL, 리치 결과). 사이트맵 리포트보다 정확한 색인 진단의 단일 출처.', {
|
|
41
|
+
siteUrl: z.string().describe(SITE_URL_DESC),
|
|
42
|
+
inspectionUrl: z.string().describe("검사할 전체 URL — 반드시 siteUrl 속성 하위여야 함 (예: 'https://example.com/page')"),
|
|
43
|
+
languageCode: z.string().optional().describe("이슈 메시지 언어 (BCP-47, 예: 'ko', 'en-US'). 기본 en-US"),
|
|
44
|
+
}, async ({ siteUrl, inspectionUrl, languageCode }) => {
|
|
45
|
+
const auth = await requireAuth();
|
|
46
|
+
const result = await gsc.inspectUrl(auth, siteUrl, inspectionUrl, languageCode ?? 'en-US');
|
|
47
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
48
|
+
});
|
|
49
|
+
server.tool('gsc_search_analytics', '검색 성과 데이터 조회 (클릭·노출·CTR·평균순위). dimensions로 query/page/country/device/date/searchAppearance 별 분해. 요약(가중 평균순위 포함) + rows 반환.', {
|
|
50
|
+
siteUrl: z.string().describe(SITE_URL_DESC),
|
|
51
|
+
startDate: z.string().describe('시작일 (YYYY-MM-DD)'),
|
|
52
|
+
endDate: z.string().describe('종료일 (YYYY-MM-DD)'),
|
|
53
|
+
dimensions: z.string().optional().describe('쉼표 구분 분해 차원: query,page,country,device,date,searchAppearance (생략 시 전체 합계)'),
|
|
54
|
+
rowLimit: z.number().int().min(1).max(25000).optional().describe('최대 행 수 (기본 1000, 최대 25000)'),
|
|
55
|
+
type: z.enum(['web', 'image', 'video', 'news', 'discover', 'googleNews']).optional().describe('검색 유형 필터 (기본 web)'),
|
|
56
|
+
}, async ({ siteUrl, startDate, endDate, dimensions, rowLimit, type }) => {
|
|
57
|
+
const auth = await requireAuth();
|
|
58
|
+
const dims = dimensions
|
|
59
|
+
? dimensions.split(',').map((d) => d.trim()).filter(Boolean)
|
|
60
|
+
: undefined;
|
|
61
|
+
const rows = await gsc.searchAnalytics(auth, siteUrl, {
|
|
62
|
+
startDate,
|
|
63
|
+
endDate,
|
|
64
|
+
dimensions: dims,
|
|
65
|
+
rowLimit,
|
|
66
|
+
type,
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
content: [{
|
|
70
|
+
type: 'text',
|
|
71
|
+
text: JSON.stringify({
|
|
72
|
+
period: { startDate, endDate },
|
|
73
|
+
dimensions: dims ?? [],
|
|
74
|
+
summary: gsc.summarizeRows(rows),
|
|
75
|
+
rows,
|
|
76
|
+
}, null, 2),
|
|
77
|
+
}],
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
package/dist/resources.js
CHANGED
|
@@ -44,7 +44,7 @@ export function registerResources(server) {
|
|
|
44
44
|
'',
|
|
45
45
|
'- `playstore_submit_release(status=completed)` — 비가역, 반드시 명시 동의 필요',
|
|
46
46
|
'- `appstore_submit_for_review` — 비가역, 반드시 명시 동의 필요',
|
|
47
|
-
'- `
|
|
47
|
+
'- `playstore_reply_review` — 공개 게시, 반드시 검토 후 동의 필요',
|
|
48
48
|
].join('\n'),
|
|
49
49
|
}],
|
|
50
50
|
}));
|
package/package.json
CHANGED