daiso 1.0.8 → 1.0.9
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 +83 -7
- package/dist/api/actionsProxy.js +5 -0
- package/dist/api/configStatus.js +8 -0
- package/dist/api/feedbackHandlers.js +60 -0
- package/dist/api/healthCheckDefinitions.js +170 -0
- package/dist/api/healthCheckShape.js +106 -0
- package/dist/api/healthCheckTypes.js +4 -0
- package/dist/api/healthChecks.js +3 -271
- package/dist/api/opinetHandlers.js +91 -0
- package/dist/api/routes/feedbackRoutes.js +5 -0
- package/dist/api/routes/healthRoutes.js +17 -1
- package/dist/api/routes/opinetRoutes.js +24 -0
- package/dist/bin.js +0 -0
- package/dist/cli/commandOptions.js +23 -2
- package/dist/cli/commands/apiCommand.js +24 -0
- package/dist/cli/commands/cinema.js +65 -0
- package/dist/cli/commands/convenience.js +57 -100
- package/dist/cli/http.js +1 -1
- package/dist/cli.js +10 -1
- package/dist/cliHelp.js +44 -8
- package/dist/core/outputSchema.js +141 -0
- package/dist/core/registry.js +1 -138
- package/dist/index.js +92 -29
- package/dist/pages/openapiFullSpec.js +5 -0
- package/dist/pages/openapiSpecActions.js +63 -0
- package/dist/pages/openapiSpecPathsFeedback.js +95 -0
- package/dist/pages/openapiSpecPathsOpinet.js +81 -0
- package/dist/pages/promptReferenceText.js +15 -0
- package/dist/services/feedback/client.js +109 -0
- package/dist/services/feedback/index.js +22 -0
- package/dist/services/feedback/tools/submitDeveloperRequest.js +54 -0
- package/dist/services/feedback/types.js +3 -0
- package/dist/services/gs25/client.js +1 -84
- package/dist/services/gs25/productSearch.js +97 -0
- package/dist/services/oliveyoung/client.js +1 -55
- package/dist/services/oliveyoung/normalize.js +58 -0
- package/dist/services/opinet/client.js +231 -0
- package/dist/services/opinet/index.js +26 -0
- package/dist/services/opinet/location.js +119 -0
- package/dist/services/opinet/tools.js +80 -0
- package/dist/services/opinet/types.js +1 -0
- package/openapi.json +82 -0
- package/openapi.yaml +55 -0
- package/package.json +18 -17
|
@@ -6,6 +6,7 @@ import { printCommandHelp } from '../../cliHelp.js';
|
|
|
6
6
|
import { parseCliArgs, toUrl, applyOptionsToQuery, toQueryOptions } from '../args.js';
|
|
7
7
|
import { validateCommandOptions } from '../commandOptions.js';
|
|
8
8
|
import { requestAndPrintResponse } from '../http.js';
|
|
9
|
+
import { runApiCommand } from './apiCommand.js';
|
|
9
10
|
export async function handleCompareProducts(options, deps) {
|
|
10
11
|
const parsed = parseCliArgs(options);
|
|
11
12
|
if (parsed.options.help === 'true') {
|
|
@@ -222,110 +223,66 @@ export async function handleGs25Inventory(options, deps) {
|
|
|
222
223
|
return await requestAndPrintResponse(deps.fetchImpl, deps.writeOut, deps.writeErr, targetUrl, 'gs25-inventory', parsed.options.json === 'true');
|
|
223
224
|
}
|
|
224
225
|
export async function handleSevenElevenProducts(options, deps) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
applyOptionsToQuery(targetUrl, toQueryOptions(parsed.options));
|
|
240
|
-
return await requestAndPrintResponse(deps.fetchImpl, deps.writeOut, deps.writeErr, targetUrl, 'seveneleven-products', parsed.options.json === 'true');
|
|
226
|
+
return await runApiCommand({
|
|
227
|
+
command: 'seveneleven-products',
|
|
228
|
+
options,
|
|
229
|
+
deps,
|
|
230
|
+
path: '/api/seveneleven/products',
|
|
231
|
+
configure: (parsed) => {
|
|
232
|
+
const query = parsed.positionals[0];
|
|
233
|
+
if (!query) {
|
|
234
|
+
return 'seveneleven-products 명령은 검색어가 필요합니다. 예: daiso seveneleven-products 삼각김밥';
|
|
235
|
+
}
|
|
236
|
+
parsed.options.query = query;
|
|
237
|
+
return null;
|
|
238
|
+
},
|
|
239
|
+
});
|
|
241
240
|
}
|
|
242
241
|
export async function handleSevenElevenStores(options, deps) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
242
|
+
return await runApiCommand({
|
|
243
|
+
command: 'seveneleven-stores',
|
|
244
|
+
options,
|
|
245
|
+
deps,
|
|
246
|
+
path: '/api/seveneleven/stores',
|
|
247
|
+
configure: (parsed) => {
|
|
248
|
+
const keyword = parsed.positionals[0];
|
|
249
|
+
if (!keyword) {
|
|
250
|
+
return 'seveneleven-stores 명령은 검색어가 필요합니다. 예: daiso seveneleven-stores 안산 중앙역';
|
|
251
|
+
}
|
|
252
|
+
parsed.options.keyword = keyword;
|
|
253
|
+
return null;
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
export async function handleSevenElevenInventory(options, deps) {
|
|
258
|
+
return await runApiCommand({
|
|
259
|
+
command: 'seveneleven-inventory',
|
|
260
|
+
options,
|
|
261
|
+
deps,
|
|
262
|
+
path: '/api/seveneleven/inventory',
|
|
263
|
+
configure: (parsed) => {
|
|
264
|
+
const keyword = parsed.positionals[0] || parsed.options.keyword;
|
|
265
|
+
if (!keyword) {
|
|
266
|
+
return 'seveneleven-inventory 명령은 검색어가 필요합니다. 예: daiso seveneleven-inventory 핫식스 --storeKeyword "안산 중앙역"';
|
|
267
|
+
}
|
|
268
|
+
parsed.options.keyword = keyword;
|
|
269
|
+
return null;
|
|
270
|
+
},
|
|
271
|
+
});
|
|
259
272
|
}
|
|
260
273
|
export async function handleSevenElevenPopwords(options, deps) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
const targetUrl = toUrl('/api/seveneleven/popwords');
|
|
269
|
-
applyOptionsToQuery(targetUrl, toQueryOptions(parsed.options));
|
|
270
|
-
return await requestAndPrintResponse(deps.fetchImpl, deps.writeOut, deps.writeErr, targetUrl, 'seveneleven-popwords', parsed.options.json === 'true');
|
|
274
|
+
return await runApiCommand({
|
|
275
|
+
command: 'seveneleven-popwords',
|
|
276
|
+
options,
|
|
277
|
+
deps,
|
|
278
|
+
path: '/api/seveneleven/popwords',
|
|
279
|
+
});
|
|
271
280
|
}
|
|
272
281
|
export async function handleSevenElevenCatalog(options, deps) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
const targetUrl = toUrl('/api/seveneleven/catalog');
|
|
281
|
-
applyOptionsToQuery(targetUrl, toQueryOptions(parsed.options));
|
|
282
|
-
return await requestAndPrintResponse(deps.fetchImpl, deps.writeOut, deps.writeErr, targetUrl, 'seveneleven-catalog', parsed.options.json === 'true');
|
|
283
|
-
}
|
|
284
|
-
export async function handleLottecinemaTheaters(options, deps) {
|
|
285
|
-
const parsed = parseCliArgs(options);
|
|
286
|
-
if (parsed.options.help === 'true') {
|
|
287
|
-
return printCommandHelp('lottecinema-theaters', deps.writeOut, deps.writeErr);
|
|
288
|
-
}
|
|
289
|
-
const keyword = parsed.positionals[0];
|
|
290
|
-
if (keyword) {
|
|
291
|
-
parsed.options.keyword = keyword;
|
|
292
|
-
}
|
|
293
|
-
if (validateCommandOptions('lottecinema-theaters', parsed.options, deps.writeErr)) {
|
|
294
|
-
return 1;
|
|
295
|
-
}
|
|
296
|
-
const targetUrl = toUrl('/api/lottecinema/theaters');
|
|
297
|
-
applyOptionsToQuery(targetUrl, toQueryOptions(parsed.options));
|
|
298
|
-
return await requestAndPrintResponse(deps.fetchImpl, deps.writeOut, deps.writeErr, targetUrl, 'lottecinema-theaters', parsed.options.json === 'true');
|
|
299
|
-
}
|
|
300
|
-
export async function handleLottecinemaMovies(options, deps) {
|
|
301
|
-
const parsed = parseCliArgs(options);
|
|
302
|
-
if (parsed.options.help === 'true') {
|
|
303
|
-
return printCommandHelp('lottecinema-movies', deps.writeOut, deps.writeErr);
|
|
304
|
-
}
|
|
305
|
-
const keyword = parsed.positionals[0];
|
|
306
|
-
if (keyword) {
|
|
307
|
-
parsed.options.keyword = keyword;
|
|
308
|
-
}
|
|
309
|
-
if (validateCommandOptions('lottecinema-movies', parsed.options, deps.writeErr)) {
|
|
310
|
-
return 1;
|
|
311
|
-
}
|
|
312
|
-
const targetUrl = toUrl('/api/lottecinema/movies');
|
|
313
|
-
applyOptionsToQuery(targetUrl, toQueryOptions(parsed.options));
|
|
314
|
-
return await requestAndPrintResponse(deps.fetchImpl, deps.writeOut, deps.writeErr, targetUrl, 'lottecinema-movies', parsed.options.json === 'true');
|
|
315
|
-
}
|
|
316
|
-
export async function handleLottecinemaSeats(options, deps) {
|
|
317
|
-
const parsed = parseCliArgs(options);
|
|
318
|
-
if (parsed.options.help === 'true') {
|
|
319
|
-
return printCommandHelp('lottecinema-seats', deps.writeOut, deps.writeErr);
|
|
320
|
-
}
|
|
321
|
-
const keyword = parsed.positionals[0];
|
|
322
|
-
if (keyword) {
|
|
323
|
-
parsed.options.keyword = keyword;
|
|
324
|
-
}
|
|
325
|
-
if (validateCommandOptions('lottecinema-seats', parsed.options, deps.writeErr)) {
|
|
326
|
-
return 1;
|
|
327
|
-
}
|
|
328
|
-
const targetUrl = toUrl('/api/lottecinema/seats');
|
|
329
|
-
applyOptionsToQuery(targetUrl, toQueryOptions(parsed.options));
|
|
330
|
-
return await requestAndPrintResponse(deps.fetchImpl, deps.writeOut, deps.writeErr, targetUrl, 'lottecinema-seats', parsed.options.json === 'true');
|
|
282
|
+
return await runApiCommand({
|
|
283
|
+
command: 'seveneleven-catalog',
|
|
284
|
+
options,
|
|
285
|
+
deps,
|
|
286
|
+
path: '/api/seveneleven/catalog',
|
|
287
|
+
});
|
|
331
288
|
}
|
package/dist/cli/http.js
CHANGED
|
@@ -54,7 +54,7 @@ function buildCliHint(command, url, bodyText) {
|
|
|
54
54
|
if (url.pathname === '/api/seveneleven/inventory') {
|
|
55
55
|
return [
|
|
56
56
|
'힌트: 세븐일레븐 재고는 매장 키워드가 필요합니다.',
|
|
57
|
-
'다음 명령 예시: daiso
|
|
57
|
+
'다음 명령 예시: daiso seveneleven-inventory <상품명> --storeKeyword 강남',
|
|
58
58
|
];
|
|
59
59
|
}
|
|
60
60
|
return [];
|
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,8 @@ import { DEFAULT_BASE_URL, DEFAULT_MCP_URL } from './cli/constants.js';
|
|
|
12
12
|
import { parseCliArgs } from './cli/args.js';
|
|
13
13
|
import { validateCommandOptions } from './cli/commandOptions.js';
|
|
14
14
|
import { handleGet, handleProducts, handleProduct, handleStores, handleInventory, handleDisplayLocation, } from './cli/commands/daiso.js';
|
|
15
|
-
import { handleCuStores, handleCuInventory, handleEmart24Stores, handleEmart24Products, handleEmart24Inventory, handleLotteMartStores, handleLotteMartProducts, handleCompareProducts, handlePlaces, handleGs25Stores, handleGs25Products, handleGs25Inventory, handleSevenElevenProducts, handleSevenElevenStores, handleSevenElevenPopwords, handleSevenElevenCatalog,
|
|
15
|
+
import { handleCuStores, handleCuInventory, handleEmart24Stores, handleEmart24Products, handleEmart24Inventory, handleLotteMartStores, handleLotteMartProducts, handleCompareProducts, handlePlaces, handleGs25Stores, handleGs25Products, handleGs25Inventory, handleSevenElevenProducts, handleSevenElevenStores, handleSevenElevenInventory, handleSevenElevenPopwords, handleSevenElevenCatalog, } from './cli/commands/convenience.js';
|
|
16
|
+
import { handleCgvTheaters, handleCgvMovies, handleCgvTimetable, handleLottecinemaTheaters, handleLottecinemaMovies, handleLottecinemaSeats, } from './cli/commands/cinema.js';
|
|
16
17
|
function rejectTopLevelUnknownOptions(options, command, deps) {
|
|
17
18
|
const parsed = parseCliArgs(options);
|
|
18
19
|
return validateCommandOptions(command, parsed.options, deps.writeErr);
|
|
@@ -120,6 +121,12 @@ export async function runCli(argv, deps) {
|
|
|
120
121
|
return await handleCuStores(options, resolvedDeps);
|
|
121
122
|
if (command === 'cu-inventory')
|
|
122
123
|
return await handleCuInventory(options, resolvedDeps);
|
|
124
|
+
if (command === 'cgv-theaters')
|
|
125
|
+
return await handleCgvTheaters(options, resolvedDeps);
|
|
126
|
+
if (command === 'cgv-movies')
|
|
127
|
+
return await handleCgvMovies(options, resolvedDeps);
|
|
128
|
+
if (command === 'cgv-timetable')
|
|
129
|
+
return await handleCgvTimetable(options, resolvedDeps);
|
|
123
130
|
if (command === 'lottecinema-theaters')
|
|
124
131
|
return await handleLottecinemaTheaters(options, resolvedDeps);
|
|
125
132
|
if (command === 'lottecinema-movies')
|
|
@@ -146,6 +153,8 @@ export async function runCli(argv, deps) {
|
|
|
146
153
|
return await handleSevenElevenProducts(options, resolvedDeps);
|
|
147
154
|
if (command === 'seveneleven-stores')
|
|
148
155
|
return await handleSevenElevenStores(options, resolvedDeps);
|
|
156
|
+
if (command === 'seveneleven-inventory')
|
|
157
|
+
return await handleSevenElevenInventory(options, resolvedDeps);
|
|
149
158
|
if (command === 'seveneleven-popwords')
|
|
150
159
|
return await handleSevenElevenPopwords(options, resolvedDeps);
|
|
151
160
|
if (command === 'seveneleven-catalog')
|
package/dist/cliHelp.js
CHANGED
|
@@ -17,6 +17,9 @@ export const COMMAND_LIST = [
|
|
|
17
17
|
'places',
|
|
18
18
|
'cu-stores',
|
|
19
19
|
'cu-inventory',
|
|
20
|
+
'cgv-theaters',
|
|
21
|
+
'cgv-movies',
|
|
22
|
+
'cgv-timetable',
|
|
20
23
|
'lottecinema-theaters',
|
|
21
24
|
'lottecinema-movies',
|
|
22
25
|
'lottecinema-seats',
|
|
@@ -30,6 +33,7 @@ export const COMMAND_LIST = [
|
|
|
30
33
|
'gs25-inventory',
|
|
31
34
|
'seveneleven-products',
|
|
32
35
|
'seveneleven-stores',
|
|
36
|
+
'seveneleven-inventory',
|
|
33
37
|
'seveneleven-popwords',
|
|
34
38
|
'seveneleven-catalog',
|
|
35
39
|
];
|
|
@@ -49,6 +53,9 @@ const COMMAND_SUMMARY = {
|
|
|
49
53
|
places: '음식점/카페 등 주변 장소 검색',
|
|
50
54
|
'cu-stores': 'CU 매장 검색',
|
|
51
55
|
'cu-inventory': 'CU 재고 조회',
|
|
56
|
+
'cgv-theaters': 'CGV 극장 검색',
|
|
57
|
+
'cgv-movies': 'CGV 영화 검색',
|
|
58
|
+
'cgv-timetable': 'CGV 시간표 조회',
|
|
52
59
|
'lottecinema-theaters': '롯데시네마 주변 지점 조회',
|
|
53
60
|
'lottecinema-movies': '롯데시네마 영화/회차 조회',
|
|
54
61
|
'lottecinema-seats': '롯데시네마 잔여 좌석 조회',
|
|
@@ -62,6 +69,7 @@ const COMMAND_SUMMARY = {
|
|
|
62
69
|
'gs25-inventory': 'GS25 재고 조회',
|
|
63
70
|
'seveneleven-products': '세븐일레븐 상품 검색',
|
|
64
71
|
'seveneleven-stores': '세븐일레븐 매장 검색',
|
|
72
|
+
'seveneleven-inventory': '세븐일레븐 재고 조회',
|
|
65
73
|
'seveneleven-popwords': '세븐일레븐 인기 검색어 조회',
|
|
66
74
|
'seveneleven-catalog': '세븐일레븐 카탈로그 스냅샷 조회',
|
|
67
75
|
};
|
|
@@ -176,6 +184,30 @@ const COMMAND_DETAIL = {
|
|
|
176
184
|
'예시: daiso cu-inventory 과자',
|
|
177
185
|
'예시: daiso cu-inventory 컵라면 --storeKeyword 강남 --size 10',
|
|
178
186
|
],
|
|
187
|
+
'cgv-theaters': [
|
|
188
|
+
'명령: cgv-theaters',
|
|
189
|
+
'설명: CGV 극장 검색 API를 호출합니다.',
|
|
190
|
+
'사용법: daiso cgv-theaters [keyword] [--regionCode 값] [--playDate YYYYMMDD] [--lat 값] [--lng 값] [--limit N] [--json]',
|
|
191
|
+
'옵션: --keyword, --regionCode, --playDate, --lat, --lng, --limit, --json',
|
|
192
|
+
'예시: daiso cgv-theaters 강남 --limit 5',
|
|
193
|
+
'예시: daiso cgv-theaters --regionCode 01 --playDate 20260304',
|
|
194
|
+
],
|
|
195
|
+
'cgv-movies': [
|
|
196
|
+
'명령: cgv-movies',
|
|
197
|
+
'설명: CGV 영화 검색 API를 호출합니다.',
|
|
198
|
+
'사용법: daiso cgv-movies [keyword] [--playDate YYYYMMDD] [--theaterCode 값] [--movieCode 값] [--lat 값] [--lng 값] [--json]',
|
|
199
|
+
'옵션: --keyword, --playDate, --theaterCode, --movieCode, --lat, --lng, --json',
|
|
200
|
+
'예시: daiso cgv-movies 강남 --playDate 20260304',
|
|
201
|
+
'예시: daiso cgv-movies --playDate 20260304 --theaterCode 0056',
|
|
202
|
+
],
|
|
203
|
+
'cgv-timetable': [
|
|
204
|
+
'명령: cgv-timetable',
|
|
205
|
+
'설명: CGV 시간표 API를 호출합니다.',
|
|
206
|
+
'사용법: daiso cgv-timetable [keyword] [--playDate YYYYMMDD] [--theaterCode 값] [--movieCode 값] [--lat 값] [--lng 값] [--json]',
|
|
207
|
+
'옵션: --keyword, --playDate, --theaterCode, --movieCode, --lat, --lng, --json',
|
|
208
|
+
'예시: daiso cgv-timetable 강남 --playDate 20260304',
|
|
209
|
+
'예시: daiso cgv-timetable --playDate 20260304 --theaterCode 0056',
|
|
210
|
+
],
|
|
179
211
|
'lottecinema-theaters': [
|
|
180
212
|
'명령: lottecinema-theaters',
|
|
181
213
|
'설명: 롯데시네마 주변 지점 API를 호출합니다.',
|
|
@@ -282,6 +314,14 @@ const COMMAND_DETAIL = {
|
|
|
282
314
|
'옵션: --limit, --json',
|
|
283
315
|
'예시: daiso seveneleven-stores 안산 중앙역 --limit 10',
|
|
284
316
|
],
|
|
317
|
+
'seveneleven-inventory': [
|
|
318
|
+
'명령: seveneleven-inventory',
|
|
319
|
+
'설명: 세븐일레븐 재고 API를 호출합니다.',
|
|
320
|
+
'사용법: daiso seveneleven-inventory <keyword> [--storeKeyword 값] [--storeLimit N] [--page N] [--size N] [--json]',
|
|
321
|
+
'필수: <keyword>',
|
|
322
|
+
'옵션: --keyword, --storeKeyword, --storeLimit, --page, --size, --json',
|
|
323
|
+
'예시: daiso seveneleven-inventory 핫식스 --storeKeyword "안산 중앙역" --storeLimit 10',
|
|
324
|
+
],
|
|
285
325
|
'seveneleven-popwords': [
|
|
286
326
|
'명령: seveneleven-popwords',
|
|
287
327
|
'설명: 세븐일레븐 인기 검색어 API를 호출합니다.',
|
|
@@ -323,24 +363,20 @@ export function printHelp(writeOut) {
|
|
|
323
363
|
writeOut(' npx daiso inventory 1034604 --keyword 강남역');
|
|
324
364
|
writeOut(' npx daiso display-location 1034604 04515');
|
|
325
365
|
writeOut(' npx daiso places 강남역 --category cafe --limit 5');
|
|
326
|
-
writeOut(' npx daiso cu-stores 강남');
|
|
327
366
|
writeOut(' npx daiso cu-inventory 과자 --storeKeyword 강남');
|
|
367
|
+
writeOut(' npx daiso cgv-theaters 강남 --limit 5');
|
|
368
|
+
writeOut(' npx daiso cgv-timetable --playDate 20260307 --theaterCode 0056');
|
|
328
369
|
writeOut(' npx daiso lottecinema-theaters --keyword "안산 중앙역" --limit 5');
|
|
329
|
-
writeOut(' npx daiso lottecinema-movies --playDate 20260310 --keyword "안산 중앙역"');
|
|
330
|
-
writeOut(' npx daiso lottecinema-seats --playDate 20260310 --keyword "안산 중앙역" --movieId 23816');
|
|
331
370
|
writeOut(' npx daiso lottemart-stores 잠실 --area 서울 --limit 10');
|
|
332
371
|
writeOut(' npx daiso lottemart-products 콜라 --storeName 강변점 --area 서울');
|
|
333
|
-
writeOut(' npx daiso emart24-stores 강남 --limit 10');
|
|
334
372
|
writeOut(' npx daiso emart24-products 두바이 --pageSize 20');
|
|
335
|
-
writeOut(' npx daiso emart24-inventory 8800244010504 --bizNoArr 28339,05015');
|
|
336
|
-
writeOut(' npx daiso gs25-stores 강남 --limit 10');
|
|
337
373
|
writeOut(' npx daiso gs25-products 오감자');
|
|
338
374
|
writeOut(' npx daiso gs25-inventory 오감자 --storeKeyword 강남');
|
|
339
375
|
writeOut(' npx daiso seveneleven-products 삼각김밥 --size 20');
|
|
340
376
|
writeOut(' npx daiso seveneleven-stores 안산 중앙역 --limit 10');
|
|
377
|
+
writeOut(' npx daiso seveneleven-inventory 핫식스 --storeKeyword "안산 중앙역"');
|
|
341
378
|
writeOut(' npx daiso seveneleven-popwords --label home');
|
|
342
379
|
writeOut(' npx daiso seveneleven-catalog --limit 10');
|
|
343
|
-
writeOut(' npx daiso get /api/cgv/movies --playDate 20260307 --theaterCode 0056');
|
|
344
380
|
writeOut('');
|
|
345
381
|
writeOut('정보가 부족할 때:');
|
|
346
382
|
writeOut(' 제품명을 먼저 검색해 productId를 확인: npx daiso products 수납박스');
|
|
@@ -354,7 +390,7 @@ export function printHelp(writeOut) {
|
|
|
354
390
|
export function printCommandHelp(command, writeOut, writeErr) {
|
|
355
391
|
if (!Object.hasOwn(COMMAND_DETAIL, command)) {
|
|
356
392
|
writeErr(`도움말을 찾을 수 없는 명령어: ${command}`);
|
|
357
|
-
writeErr(
|
|
393
|
+
writeErr(`사용 가능한 명령어: ${COMMAND_LIST.join(', ')}`);
|
|
358
394
|
return 1;
|
|
359
395
|
}
|
|
360
396
|
const detail = COMMAND_DETAIL[command];
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP 도구 outputSchema 생성
|
|
3
|
+
*/
|
|
4
|
+
import * as z from 'zod';
|
|
5
|
+
const DEFAULT_OUTPUT_SCHEMA = z.object({}).loose().describe('도구 실행 결과(JSON 객체)');
|
|
6
|
+
function createFallbackOutputSchema(toolName) {
|
|
7
|
+
if (toolName.includes('compare')) {
|
|
8
|
+
return {
|
|
9
|
+
keyword: z.string().optional(),
|
|
10
|
+
services: z.array(z.string()).optional(),
|
|
11
|
+
serviceCount: z.number().optional(),
|
|
12
|
+
resultCount: z.number().optional(),
|
|
13
|
+
bestPrice: z.unknown().optional(),
|
|
14
|
+
results: z.array(z.unknown()).optional(),
|
|
15
|
+
errors: z.array(z.unknown()).optional(),
|
|
16
|
+
note: z.string().optional(),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (toolName.includes('search_products') ||
|
|
20
|
+
toolName.includes('searchProducts') ||
|
|
21
|
+
toolName.endsWith('_products')) {
|
|
22
|
+
return {
|
|
23
|
+
keyword: z.string().optional(),
|
|
24
|
+
query: z.string().optional(),
|
|
25
|
+
page: z.number().optional(),
|
|
26
|
+
pageSize: z.number().optional(),
|
|
27
|
+
totalCount: z.number().optional(),
|
|
28
|
+
count: z.number().optional(),
|
|
29
|
+
products: z.array(z.unknown()).optional(),
|
|
30
|
+
note: z.string().optional(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (toolName.includes('find_stores') ||
|
|
34
|
+
toolName.includes('nearby_stores') ||
|
|
35
|
+
toolName.includes('search_stores')) {
|
|
36
|
+
return {
|
|
37
|
+
keyword: z.string().optional(),
|
|
38
|
+
searchParams: z.unknown().optional(),
|
|
39
|
+
location: z.unknown().optional(),
|
|
40
|
+
totalCount: z.number().optional(),
|
|
41
|
+
filteredCount: z.number().optional(),
|
|
42
|
+
count: z.number().optional(),
|
|
43
|
+
stores: z.array(z.unknown()).optional(),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (toolName.includes('places')) {
|
|
47
|
+
return {
|
|
48
|
+
provider: z.string().optional(),
|
|
49
|
+
searchMode: z.string().optional(),
|
|
50
|
+
query: z.string().optional(),
|
|
51
|
+
category: z.string().optional(),
|
|
52
|
+
location: z.string().optional(),
|
|
53
|
+
totalCount: z.number().optional(),
|
|
54
|
+
count: z.number().optional(),
|
|
55
|
+
places: z.array(z.unknown()).optional(),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (toolName.includes('inventory')) {
|
|
59
|
+
return {
|
|
60
|
+
productId: z.string().optional(),
|
|
61
|
+
keyword: z.string().optional(),
|
|
62
|
+
itemCode: z.string().nullable().optional(),
|
|
63
|
+
location: z.unknown().optional(),
|
|
64
|
+
product: z.unknown().optional(),
|
|
65
|
+
onlineStock: z.number().optional(),
|
|
66
|
+
inventory: z.unknown().optional(),
|
|
67
|
+
storeInventory: z.unknown().optional(),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (toolName.includes('display_location')) {
|
|
71
|
+
return {
|
|
72
|
+
productId: z.string().optional(),
|
|
73
|
+
storeCode: z.string().optional(),
|
|
74
|
+
displayLocation: z.unknown().optional(),
|
|
75
|
+
locations: z.array(z.unknown()).optional(),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (toolName.includes('price_info')) {
|
|
79
|
+
return {
|
|
80
|
+
productId: z.string().optional(),
|
|
81
|
+
productName: z.string().optional(),
|
|
82
|
+
product: z.unknown().optional(),
|
|
83
|
+
price: z.number().optional(),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (toolName.includes('theater')) {
|
|
87
|
+
return {
|
|
88
|
+
keyword: z.string().optional(),
|
|
89
|
+
location: z.unknown().optional(),
|
|
90
|
+
count: z.number().optional(),
|
|
91
|
+
theaters: z.array(z.unknown()).optional(),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (toolName.includes('movie') || toolName.includes('now_showing')) {
|
|
95
|
+
return {
|
|
96
|
+
keyword: z.string().optional(),
|
|
97
|
+
playDate: z.string().optional(),
|
|
98
|
+
theaterCode: z.string().optional(),
|
|
99
|
+
count: z.number().optional(),
|
|
100
|
+
movies: z.array(z.unknown()).optional(),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (toolName.includes('timetable') || toolName.includes('remaining_seats')) {
|
|
104
|
+
return {
|
|
105
|
+
playDate: z.string().optional(),
|
|
106
|
+
theaterCode: z.string().optional(),
|
|
107
|
+
movieCode: z.string().optional(),
|
|
108
|
+
count: z.number().optional(),
|
|
109
|
+
showtimes: z.array(z.unknown()).optional(),
|
|
110
|
+
seats: z.array(z.unknown()).optional(),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (toolName.includes('popwords')) {
|
|
114
|
+
return {
|
|
115
|
+
label: z.string().optional(),
|
|
116
|
+
keywords: z.array(z.string()).optional(),
|
|
117
|
+
count: z.number().optional(),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (toolName.includes('catalog')) {
|
|
121
|
+
return {
|
|
122
|
+
pages: z.array(z.unknown()).optional(),
|
|
123
|
+
issues: z.array(z.unknown()).optional(),
|
|
124
|
+
exhibitions: z.array(z.unknown()).optional(),
|
|
125
|
+
count: z.number().optional(),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return {};
|
|
129
|
+
}
|
|
130
|
+
export function createToolOutputSchema(toolName, outputSchema) {
|
|
131
|
+
const schema = outputSchema || createFallbackOutputSchema(toolName);
|
|
132
|
+
if (Object.keys(schema).length === 0) {
|
|
133
|
+
return DEFAULT_OUTPUT_SCHEMA;
|
|
134
|
+
}
|
|
135
|
+
return z
|
|
136
|
+
.object({
|
|
137
|
+
...schema,
|
|
138
|
+
standard: z.unknown().optional().describe('서비스 공통 상품/매장/영화관 정규화 결과'),
|
|
139
|
+
})
|
|
140
|
+
.loose();
|
|
141
|
+
}
|
package/dist/core/registry.js
CHANGED
|
@@ -3,145 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 서비스 프로바이더를 등록하고 MCP 서버에 도구를 연결합니다.
|
|
5
5
|
*/
|
|
6
|
-
import * as z from 'zod';
|
|
7
6
|
import { getErrorMessage, toStandardErrorDiagnostics } from './errors.js';
|
|
8
|
-
|
|
9
|
-
function createFallbackOutputSchema(toolName) {
|
|
10
|
-
if (toolName.includes('compare')) {
|
|
11
|
-
return {
|
|
12
|
-
keyword: z.string().optional(),
|
|
13
|
-
services: z.array(z.string()).optional(),
|
|
14
|
-
serviceCount: z.number().optional(),
|
|
15
|
-
resultCount: z.number().optional(),
|
|
16
|
-
bestPrice: z.unknown().optional(),
|
|
17
|
-
results: z.array(z.unknown()).optional(),
|
|
18
|
-
errors: z.array(z.unknown()).optional(),
|
|
19
|
-
note: z.string().optional(),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
if (toolName.includes('search_products') ||
|
|
23
|
-
toolName.includes('searchProducts') ||
|
|
24
|
-
toolName.endsWith('_products')) {
|
|
25
|
-
return {
|
|
26
|
-
keyword: z.string().optional(),
|
|
27
|
-
query: z.string().optional(),
|
|
28
|
-
page: z.number().optional(),
|
|
29
|
-
pageSize: z.number().optional(),
|
|
30
|
-
totalCount: z.number().optional(),
|
|
31
|
-
count: z.number().optional(),
|
|
32
|
-
products: z.array(z.unknown()).optional(),
|
|
33
|
-
note: z.string().optional(),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
if (toolName.includes('find_stores') ||
|
|
37
|
-
toolName.includes('nearby_stores') ||
|
|
38
|
-
toolName.includes('search_stores')) {
|
|
39
|
-
return {
|
|
40
|
-
keyword: z.string().optional(),
|
|
41
|
-
searchParams: z.unknown().optional(),
|
|
42
|
-
location: z.unknown().optional(),
|
|
43
|
-
totalCount: z.number().optional(),
|
|
44
|
-
filteredCount: z.number().optional(),
|
|
45
|
-
count: z.number().optional(),
|
|
46
|
-
stores: z.array(z.unknown()).optional(),
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
if (toolName.includes('places')) {
|
|
50
|
-
return {
|
|
51
|
-
provider: z.string().optional(),
|
|
52
|
-
searchMode: z.string().optional(),
|
|
53
|
-
query: z.string().optional(),
|
|
54
|
-
category: z.string().optional(),
|
|
55
|
-
location: z.string().optional(),
|
|
56
|
-
totalCount: z.number().optional(),
|
|
57
|
-
count: z.number().optional(),
|
|
58
|
-
places: z.array(z.unknown()).optional(),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
if (toolName.includes('inventory')) {
|
|
62
|
-
return {
|
|
63
|
-
productId: z.string().optional(),
|
|
64
|
-
keyword: z.string().optional(),
|
|
65
|
-
itemCode: z.string().nullable().optional(),
|
|
66
|
-
location: z.unknown().optional(),
|
|
67
|
-
product: z.unknown().optional(),
|
|
68
|
-
onlineStock: z.number().optional(),
|
|
69
|
-
inventory: z.unknown().optional(),
|
|
70
|
-
storeInventory: z.unknown().optional(),
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
if (toolName.includes('display_location')) {
|
|
74
|
-
return {
|
|
75
|
-
productId: z.string().optional(),
|
|
76
|
-
storeCode: z.string().optional(),
|
|
77
|
-
displayLocation: z.unknown().optional(),
|
|
78
|
-
locations: z.array(z.unknown()).optional(),
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
if (toolName.includes('price_info')) {
|
|
82
|
-
return {
|
|
83
|
-
productId: z.string().optional(),
|
|
84
|
-
productName: z.string().optional(),
|
|
85
|
-
product: z.unknown().optional(),
|
|
86
|
-
price: z.number().optional(),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
if (toolName.includes('theater')) {
|
|
90
|
-
return {
|
|
91
|
-
keyword: z.string().optional(),
|
|
92
|
-
location: z.unknown().optional(),
|
|
93
|
-
count: z.number().optional(),
|
|
94
|
-
theaters: z.array(z.unknown()).optional(),
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
if (toolName.includes('movie') || toolName.includes('now_showing')) {
|
|
98
|
-
return {
|
|
99
|
-
keyword: z.string().optional(),
|
|
100
|
-
playDate: z.string().optional(),
|
|
101
|
-
theaterCode: z.string().optional(),
|
|
102
|
-
count: z.number().optional(),
|
|
103
|
-
movies: z.array(z.unknown()).optional(),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
if (toolName.includes('timetable') || toolName.includes('remaining_seats')) {
|
|
107
|
-
return {
|
|
108
|
-
playDate: z.string().optional(),
|
|
109
|
-
theaterCode: z.string().optional(),
|
|
110
|
-
movieCode: z.string().optional(),
|
|
111
|
-
count: z.number().optional(),
|
|
112
|
-
showtimes: z.array(z.unknown()).optional(),
|
|
113
|
-
seats: z.array(z.unknown()).optional(),
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
if (toolName.includes('popwords')) {
|
|
117
|
-
return {
|
|
118
|
-
label: z.string().optional(),
|
|
119
|
-
keywords: z.array(z.string()).optional(),
|
|
120
|
-
count: z.number().optional(),
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
if (toolName.includes('catalog')) {
|
|
124
|
-
return {
|
|
125
|
-
pages: z.array(z.unknown()).optional(),
|
|
126
|
-
issues: z.array(z.unknown()).optional(),
|
|
127
|
-
exhibitions: z.array(z.unknown()).optional(),
|
|
128
|
-
count: z.number().optional(),
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
return {};
|
|
132
|
-
}
|
|
133
|
-
function createToolOutputSchema(toolName, outputSchema) {
|
|
134
|
-
const schema = outputSchema || createFallbackOutputSchema(toolName);
|
|
135
|
-
if (Object.keys(schema).length === 0) {
|
|
136
|
-
return DEFAULT_OUTPUT_SCHEMA;
|
|
137
|
-
}
|
|
138
|
-
return z
|
|
139
|
-
.object({
|
|
140
|
-
...schema,
|
|
141
|
-
standard: z.unknown().optional().describe('서비스 공통 상품/매장/영화관 정규화 결과'),
|
|
142
|
-
})
|
|
143
|
-
.loose();
|
|
144
|
-
}
|
|
7
|
+
import { createToolOutputSchema } from './outputSchema.js';
|
|
145
8
|
function parseJsonText(text) {
|
|
146
9
|
try {
|
|
147
10
|
const parsed = JSON.parse(text);
|