daiso 1.0.5 → 1.0.7
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 +101 -7
- package/dist/api/actionsProxy.js +111 -21
- package/dist/api/configStatus.js +23 -0
- package/dist/api/gs25Handlers.js +68 -22
- package/dist/api/handlers.js +32 -3
- package/dist/api/healthChecks.js +233 -20
- package/dist/api/lottemartHandlers.js +17 -1
- package/dist/api/placesHandlers.js +44 -0
- package/dist/api/response.js +2 -0
- package/dist/api/routes/healthRoutes.js +20 -3
- package/dist/api/routes/placesRoutes.js +9 -0
- package/dist/bin.js +0 -0
- package/dist/cli/args.js +21 -0
- package/dist/cli/commandOptions.js +96 -0
- package/dist/cli/commands/convenience.js +73 -1
- package/dist/cli/commands/daiso.js +18 -2
- package/dist/cli/http.js +58 -0
- package/dist/cli/interactiveItemSearch.js +4 -2
- package/dist/cli/interactivePrompt.js +3 -2
- package/dist/cli.js +25 -1
- package/dist/cliHelp.js +20 -6
- package/dist/cliInteractive.js +75 -6
- package/dist/cliPicker.js +1 -0
- package/dist/cliRenderer.js +93 -3
- package/dist/core/errors.js +66 -0
- package/dist/core/registry.js +246 -3
- package/dist/index.js +19 -4
- package/dist/pages/openapiFullSpec.js +3 -0
- package/dist/pages/openapiSpecActions.js +308 -42
- package/dist/pages/openapiSpecPathsCu.js +7 -0
- package/dist/pages/openapiSpecPathsLotteMart.js +14 -0
- package/dist/pages/openapiSpecPathsOliveyoung.js +35 -0
- package/dist/pages/openapiSpecPathsPlaces.js +85 -0
- package/dist/pages/promptReferenceText.js +16 -7
- package/dist/pages/promptRetailCinemaText.js +24 -2
- package/dist/services/daiso/client.js +8 -0
- package/dist/services/daiso/index.js +2 -0
- package/dist/services/daiso/tools/checkInventory.js +4 -2
- package/dist/services/daiso/tools/findInventoryByName.js +222 -0
- package/dist/services/daiso/tools/getDisplayLocation.js +2 -2
- package/dist/services/emart24/client.js +9 -0
- package/dist/services/emart24/tools/searchProducts.js +27 -17
- package/dist/services/gs25/api.js +3 -0
- package/dist/services/gs25/client.js +216 -30
- package/dist/services/gs25/index.js +11 -3
- package/dist/services/gs25/tools/checkInventory.js +39 -12
- package/dist/services/gs25/tools/findNearbyStores.js +19 -5
- package/dist/services/gs25/tools/searchProducts.js +39 -25
- package/dist/services/lottemart/client.js +10 -1
- package/dist/services/lottemart/tools/searchProducts.js +8 -1
- package/dist/services/lottemart/zetta.js +1 -1
- package/dist/services/oliveyoung/client.js +206 -86
- package/dist/services/oliveyoung/tools/checkInventory.js +7 -2
- package/dist/services/places/client.js +116 -0
- package/dist/services/places/index.js +23 -0
- package/dist/services/places/tools/searchNearby.js +56 -0
- package/dist/services/places/types.js +1 -0
- package/dist/services/seveneleven/client.js +7 -0
- package/dist/services/seveneleven/tools/searchProducts.js +29 -18
- package/dist/utils/http.js +82 -10
- package/dist/utils/zyte.js +74 -26
- package/openapi.json +22 -3
- package/openapi.yaml +16 -3
- package/package.json +28 -9
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import * as z from 'zod';
|
|
5
5
|
import { searchSevenElevenProductsWithVariants } from '../productKeyword.js';
|
|
6
|
+
function buildTextResponse(payload) {
|
|
7
|
+
return {
|
|
8
|
+
content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],
|
|
9
|
+
structuredContent: payload,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
6
12
|
async function searchProducts(args) {
|
|
7
13
|
const { query, page = 1, size = 20, sort = 'recommend', timeoutMs = 15000 } = args;
|
|
8
14
|
if (!query || query.trim().length === 0) {
|
|
@@ -14,25 +20,29 @@ async function searchProducts(args) {
|
|
|
14
20
|
sort,
|
|
15
21
|
timeout: timeoutMs,
|
|
16
22
|
});
|
|
17
|
-
return {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
collectionIds: result.collectionIds,
|
|
29
|
-
appliedQueries: result.appliedQueries,
|
|
30
|
-
products: result.products,
|
|
31
|
-
}, null, 2),
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
};
|
|
23
|
+
return buildTextResponse({
|
|
24
|
+
query: result.query,
|
|
25
|
+
page,
|
|
26
|
+
size,
|
|
27
|
+
sort,
|
|
28
|
+
totalCount: result.totalCount,
|
|
29
|
+
count: result.products.length,
|
|
30
|
+
collectionIds: result.collectionIds,
|
|
31
|
+
appliedQueries: result.appliedQueries,
|
|
32
|
+
products: result.products,
|
|
33
|
+
});
|
|
35
34
|
}
|
|
35
|
+
const searchProductsOutputSchema = {
|
|
36
|
+
query: z.string().describe('적용된 검색어'),
|
|
37
|
+
page: z.number().describe('페이지 번호'),
|
|
38
|
+
size: z.number().describe('페이지 크기'),
|
|
39
|
+
sort: z.string().describe('정렬 기준'),
|
|
40
|
+
totalCount: z.number().describe('검색된 전체 상품 수'),
|
|
41
|
+
count: z.number().describe('반환된 상품 수'),
|
|
42
|
+
collectionIds: z.array(z.string()).describe('검색 컬렉션 ID 목록'),
|
|
43
|
+
appliedQueries: z.array(z.string()).describe('실제로 시도한 검색어 목록'),
|
|
44
|
+
products: z.array(z.unknown()).describe('세븐일레븐 상품 검색 결과'),
|
|
45
|
+
};
|
|
36
46
|
export function createSearchProductsTool() {
|
|
37
47
|
return {
|
|
38
48
|
name: 'seveneleven_search_products',
|
|
@@ -50,6 +60,7 @@ export function createSearchProductsTool() {
|
|
|
50
60
|
.describe('정렬 기준 (기본값: recommend)'),
|
|
51
61
|
timeoutMs: z.number().optional().default(15000).describe('요청 제한 시간(ms, 기본값: 15000)'),
|
|
52
62
|
},
|
|
63
|
+
outputSchema: searchProductsOutputSchema,
|
|
53
64
|
},
|
|
54
65
|
handler: searchProducts,
|
|
55
66
|
};
|
package/dist/utils/http.js
CHANGED
|
@@ -20,18 +20,90 @@ export function createTimeoutController(timeout) {
|
|
|
20
20
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
21
21
|
return { controller, timeoutId };
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
const DEFAULT_RETRY_STATUS_CODES = [408, 429, 500, 502, 503, 504, 522, 524];
|
|
24
|
+
const DEFAULT_RETRY_METHODS = ['GET', 'HEAD', 'OPTIONS'];
|
|
25
|
+
function isRetryableStatus(status, retryStatusCodes) {
|
|
26
|
+
return retryStatusCodes.includes(status);
|
|
27
|
+
}
|
|
28
|
+
function wait(ms) {
|
|
29
|
+
if (ms <= 0) {
|
|
30
|
+
return Promise.resolve();
|
|
31
|
+
}
|
|
32
|
+
return new Promise((resolve) => {
|
|
33
|
+
setTimeout(resolve, ms);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function normalizeMethod(method) {
|
|
37
|
+
return (method || 'GET').toUpperCase();
|
|
38
|
+
}
|
|
39
|
+
function canRetryMethod(method, retryMethods, retryUnsafeMethods) {
|
|
40
|
+
return retryUnsafeMethods || retryMethods.map((item) => item.toUpperCase()).includes(method);
|
|
41
|
+
}
|
|
42
|
+
function parseRetryAfterDelayMs(response) {
|
|
43
|
+
const retryAfter = response.headers.get('retry-after');
|
|
44
|
+
if (!retryAfter) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const seconds = Number.parseFloat(retryAfter);
|
|
48
|
+
if (Number.isFinite(seconds)) {
|
|
49
|
+
return Math.max(0, Math.trunc(seconds * 1000));
|
|
50
|
+
}
|
|
51
|
+
const retryDate = Date.parse(retryAfter);
|
|
52
|
+
if (Number.isFinite(retryDate)) {
|
|
53
|
+
return Math.max(0, retryDate - Date.now());
|
|
31
54
|
}
|
|
32
|
-
|
|
33
|
-
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
export async function fetchWithTimeout(url, options = {}) {
|
|
58
|
+
const { timeout = 10000, retries = 0, retryDelayMs = 250, retryStatusCodes = DEFAULT_RETRY_STATUS_CODES, retryUnsafeMethods = false, retryMethods = DEFAULT_RETRY_METHODS, onRetry, ...restOptions } = options;
|
|
59
|
+
const maxAttempts = Math.max(1, Math.trunc(retries) + 1);
|
|
60
|
+
const method = normalizeMethod(restOptions.method);
|
|
61
|
+
const retryAllowed = canRetryMethod(method, retryMethods, retryUnsafeMethods);
|
|
62
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
63
|
+
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
64
|
+
try {
|
|
65
|
+
const response = await fetch(url, {
|
|
66
|
+
...restOptions,
|
|
67
|
+
signal: controller.signal,
|
|
68
|
+
});
|
|
69
|
+
if (retryAllowed && attempt < maxAttempts && isRetryableStatus(response.status, retryStatusCodes)) {
|
|
70
|
+
const delayMs = parseRetryAfterDelayMs(response) ?? retryDelayMs;
|
|
71
|
+
onRetry?.({
|
|
72
|
+
attempt,
|
|
73
|
+
maxAttempts,
|
|
74
|
+
delayMs,
|
|
75
|
+
reason: 'status',
|
|
76
|
+
status: response.status,
|
|
77
|
+
method,
|
|
78
|
+
url,
|
|
79
|
+
});
|
|
80
|
+
await response.body?.cancel();
|
|
81
|
+
await wait(delayMs);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
return response;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (!retryAllowed || attempt >= maxAttempts) {
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
onRetry?.({
|
|
91
|
+
attempt,
|
|
92
|
+
maxAttempts,
|
|
93
|
+
delayMs: retryDelayMs,
|
|
94
|
+
reason: 'error',
|
|
95
|
+
error,
|
|
96
|
+
method,
|
|
97
|
+
url,
|
|
98
|
+
});
|
|
99
|
+
await wait(retryDelayMs);
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
clearTimeout(timeoutId);
|
|
103
|
+
}
|
|
34
104
|
}
|
|
105
|
+
/* v8 ignore next */
|
|
106
|
+
throw new Error('API 요청 재시도 처리 중 알 수 없는 오류가 발생했습니다.');
|
|
35
107
|
}
|
|
36
108
|
export async function fetchJson(url, options = {}) {
|
|
37
109
|
const response = await fetchWithTimeout(url, options);
|
package/dist/utils/zyte.js
CHANGED
|
@@ -37,36 +37,84 @@ export function decodeBase64(value) {
|
|
|
37
37
|
/* c8 ignore end */
|
|
38
38
|
throw new Error('Base64 디코딩을 지원하지 않는 런타임입니다.');
|
|
39
39
|
}
|
|
40
|
+
function isAbortError(error) {
|
|
41
|
+
return error instanceof Error && error.name === 'AbortError';
|
|
42
|
+
}
|
|
43
|
+
class RetryableZyteError extends Error {
|
|
44
|
+
}
|
|
45
|
+
function isRetryableZyteStatus(status) {
|
|
46
|
+
return status === 408 || status === 429 || status >= 500;
|
|
47
|
+
}
|
|
48
|
+
function isRetryableTargetStatus(statusCode) {
|
|
49
|
+
return typeof statusCode === 'number' && statusCode >= 500;
|
|
50
|
+
}
|
|
51
|
+
function isRetryableError(error) {
|
|
52
|
+
return isAbortError(error) || error instanceof RetryableZyteError;
|
|
53
|
+
}
|
|
54
|
+
function wait(ms) {
|
|
55
|
+
if (ms <= 0) {
|
|
56
|
+
return Promise.resolve();
|
|
57
|
+
}
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
setTimeout(resolve, ms);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
40
62
|
export async function requestByZyte(options) {
|
|
41
|
-
const { timeout = 15000, url, method = 'GET', headers = [], bodyText, apiKey } = options;
|
|
63
|
+
const { timeout = 15000, retries = 1, retryDelayMs = 250, url, method = 'GET', headers = [], bodyText, apiKey, } = options;
|
|
42
64
|
const auth = encodeBasicAuth(resolveZyteApiKey(apiKey));
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
const maxAttempts = Math.max(1, Math.trunc(retries) + 1);
|
|
66
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
67
|
+
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
68
|
+
try {
|
|
69
|
+
let response;
|
|
70
|
+
try {
|
|
71
|
+
response = await fetch('https://api.zyte.com/v1/extract', {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
headers: {
|
|
74
|
+
Authorization: `Basic ${auth}`,
|
|
75
|
+
'Content-Type': 'application/json',
|
|
76
|
+
Accept: 'application/json',
|
|
77
|
+
},
|
|
78
|
+
body: JSON.stringify({
|
|
79
|
+
url,
|
|
80
|
+
httpRequestMethod: method,
|
|
81
|
+
customHttpRequestHeaders: headers,
|
|
82
|
+
httpRequestText: bodyText,
|
|
83
|
+
httpResponseBody: true,
|
|
84
|
+
}),
|
|
85
|
+
signal: controller.signal,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error instanceof TypeError) {
|
|
90
|
+
throw new RetryableZyteError(error.message);
|
|
91
|
+
}
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
const result = (await response.json());
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
const message = `Zyte API 호출 실패: ${response.status} ${result.detail || result.title || ''}`.trim();
|
|
97
|
+
if (isRetryableZyteStatus(response.status)) {
|
|
98
|
+
throw new RetryableZyteError(message);
|
|
99
|
+
}
|
|
100
|
+
throw new Error(message);
|
|
101
|
+
}
|
|
102
|
+
if (isRetryableTargetStatus(result.statusCode) && attempt < maxAttempts) {
|
|
103
|
+
throw new RetryableZyteError(`Zyte target response failed: ${result.statusCode}`);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (!isRetryableError(error) || attempt >= maxAttempts) {
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
await wait(retryDelayMs);
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
clearTimeout(timeoutId);
|
|
64
115
|
}
|
|
65
|
-
return result;
|
|
66
|
-
}
|
|
67
|
-
finally {
|
|
68
|
-
clearTimeout(timeoutId);
|
|
69
116
|
}
|
|
117
|
+
throw new Error('Zyte API 호출 실패');
|
|
70
118
|
}
|
|
71
119
|
export function decodeZyteHttpBody(result) {
|
|
72
120
|
if (!result.httpResponseBody) {
|
package/openapi.json
CHANGED
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"sevenelevenCheckInventory",
|
|
54
54
|
"sevenelevenGetPopwords",
|
|
55
55
|
"sevenelevenGetCatalog",
|
|
56
|
+
"placesSearchNearby",
|
|
56
57
|
"megaboxFindTheaters",
|
|
57
58
|
"megaboxListMovies",
|
|
58
59
|
"megaboxGetSeats",
|
|
@@ -96,7 +97,7 @@
|
|
|
96
97
|
"name": "productId",
|
|
97
98
|
"in": "query",
|
|
98
99
|
"required": false,
|
|
99
|
-
"description": "제품 ID 또는 상세 조회용 path
|
|
100
|
+
"description": "제품 ID 또는 상세 조회용 path 파라미터. 상품명만 알면 먼저 daisoSearchProducts 또는 /api/daiso/products로 productId를 확인하세요.",
|
|
100
101
|
"schema": {
|
|
101
102
|
"type": "string"
|
|
102
103
|
}
|
|
@@ -110,6 +111,24 @@
|
|
|
110
111
|
"type": "string"
|
|
111
112
|
}
|
|
112
113
|
},
|
|
114
|
+
{
|
|
115
|
+
"name": "location",
|
|
116
|
+
"in": "query",
|
|
117
|
+
"required": false,
|
|
118
|
+
"description": "주변 장소 검색 지역/역/주소 키워드",
|
|
119
|
+
"schema": {
|
|
120
|
+
"type": "string"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"name": "category",
|
|
125
|
+
"in": "query",
|
|
126
|
+
"required": false,
|
|
127
|
+
"description": "주변 장소 카테고리(restaurant, cafe, food, dessert, all)",
|
|
128
|
+
"schema": {
|
|
129
|
+
"type": "string"
|
|
130
|
+
}
|
|
131
|
+
},
|
|
113
132
|
{
|
|
114
133
|
"name": "sido",
|
|
115
134
|
"in": "query",
|
|
@@ -278,7 +297,7 @@
|
|
|
278
297
|
"name": "storeCode",
|
|
279
298
|
"in": "query",
|
|
280
299
|
"required": false,
|
|
281
|
-
"description": "매장
|
|
300
|
+
"description": "매장 코드. 다이소 진열 위치는 /api/daiso/inventory 응답의 storeInventory.stores[].storeCode에서 확인하세요.",
|
|
282
301
|
"schema": {
|
|
283
302
|
"type": "string"
|
|
284
303
|
}
|
|
@@ -287,7 +306,7 @@
|
|
|
287
306
|
"name": "storeName",
|
|
288
307
|
"in": "query",
|
|
289
308
|
"required": false,
|
|
290
|
-
"description": "
|
|
309
|
+
"description": "매장명. 롯데마트 상품 조회에서 storeCode가 없을 때 사용하며, 모르면 먼저 lottemartFindNearbyStores 또는 /api/lottemart/stores로 확인하세요.",
|
|
291
310
|
"schema": {
|
|
292
311
|
"type": "string"
|
|
293
312
|
}
|
package/openapi.yaml
CHANGED
|
@@ -54,6 +54,7 @@ paths:
|
|
|
54
54
|
- sevenelevenCheckInventory
|
|
55
55
|
- sevenelevenGetPopwords
|
|
56
56
|
- sevenelevenGetCatalog
|
|
57
|
+
- placesSearchNearby
|
|
57
58
|
- megaboxFindTheaters
|
|
58
59
|
- megaboxListMovies
|
|
59
60
|
- megaboxGetSeats
|
|
@@ -84,7 +85,7 @@ paths:
|
|
|
84
85
|
- name: productId
|
|
85
86
|
in: query
|
|
86
87
|
required: false
|
|
87
|
-
description: 제품 ID 또는 상세 조회용 path
|
|
88
|
+
description: 제품 ID 또는 상세 조회용 path 파라미터. 상품명만 알면 먼저 daisoSearchProducts 또는 /api/daiso/products로 productId를 확인하세요.
|
|
88
89
|
schema:
|
|
89
90
|
type: string
|
|
90
91
|
- name: keyword
|
|
@@ -93,6 +94,18 @@ paths:
|
|
|
93
94
|
description: 공통 키워드 파라미터
|
|
94
95
|
schema:
|
|
95
96
|
type: string
|
|
97
|
+
- name: location
|
|
98
|
+
in: query
|
|
99
|
+
required: false
|
|
100
|
+
description: 주변 장소 검색 지역/역/주소 키워드
|
|
101
|
+
schema:
|
|
102
|
+
type: string
|
|
103
|
+
- name: category
|
|
104
|
+
in: query
|
|
105
|
+
required: false
|
|
106
|
+
description: 주변 장소 카테고리(restaurant, cafe, food, dessert, all)
|
|
107
|
+
schema:
|
|
108
|
+
type: string
|
|
96
109
|
- name: sido
|
|
97
110
|
in: query
|
|
98
111
|
required: false
|
|
@@ -206,13 +219,13 @@ paths:
|
|
|
206
219
|
- name: storeCode
|
|
207
220
|
in: query
|
|
208
221
|
required: false
|
|
209
|
-
description: 매장
|
|
222
|
+
description: 매장 코드. 다이소 진열 위치는 /api/daiso/inventory 응답의 storeInventory.stores[].storeCode에서 확인하세요.
|
|
210
223
|
schema:
|
|
211
224
|
type: string
|
|
212
225
|
- name: storeName
|
|
213
226
|
in: query
|
|
214
227
|
required: false
|
|
215
|
-
description:
|
|
228
|
+
description: 매장명. 롯데마트 상품 조회에서 storeCode가 없을 때 사용하며, 모르면 먼저 lottemartFindNearbyStores 또는 /api/lottemart/stores로 확인하세요.
|
|
216
229
|
schema:
|
|
217
230
|
type: string
|
|
218
231
|
- name: storeKeyword
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "daiso",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "Korean retail and cinema MCP server, CLI, and Codex Skill for Daiso, convenience stores, marts, Olive Young, and theaters",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"daiso": "dist/bin.js"
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
"hooks:install": "git config core.hooksPath .githooks && chmod +x .githooks/pre-push",
|
|
22
22
|
"dev": "wrangler dev",
|
|
23
23
|
"deploy": "wrangler deploy",
|
|
24
|
-
"build": "tsc && npx tsx scripts/generate-openapi.ts",
|
|
25
|
-
"build:openapi": "npx tsx scripts/generate-openapi.ts",
|
|
26
|
-
"cli:smoke": "npm run build && npx tsx scripts/cli-smoke.ts",
|
|
27
|
-
"
|
|
24
|
+
"build": "tsc && npx tsx scripts/ops/generate-openapi.ts",
|
|
25
|
+
"build:openapi": "npx tsx scripts/ops/generate-openapi.ts",
|
|
26
|
+
"cli:smoke": "npm run build && npx tsx scripts/ops/cli-smoke.ts",
|
|
27
|
+
"mcp:smoke": "npx tsx scripts/ops/mcp-smoke.ts",
|
|
28
|
+
"update:workers-chart": "npx tsx scripts/ops/update-workers-invocations-chart.ts",
|
|
28
29
|
"prepack": "npm run build",
|
|
29
30
|
"prepublishOnly": "npm run check && npm run build",
|
|
30
31
|
"release:dry-run": "npm pack --dry-run",
|
|
@@ -42,7 +43,24 @@
|
|
|
42
43
|
},
|
|
43
44
|
"keywords": [
|
|
44
45
|
"mcp",
|
|
46
|
+
"mcp-server",
|
|
45
47
|
"daiso",
|
|
48
|
+
"korea",
|
|
49
|
+
"korean-retail",
|
|
50
|
+
"retail",
|
|
51
|
+
"inventory",
|
|
52
|
+
"cli",
|
|
53
|
+
"codex-skill",
|
|
54
|
+
"clawhub",
|
|
55
|
+
"oliveyoung",
|
|
56
|
+
"gs25",
|
|
57
|
+
"cu",
|
|
58
|
+
"seveneleven",
|
|
59
|
+
"emart24",
|
|
60
|
+
"lottemart",
|
|
61
|
+
"cgv",
|
|
62
|
+
"megabox",
|
|
63
|
+
"lottecinema",
|
|
46
64
|
"cloudflare-workers",
|
|
47
65
|
"serverless"
|
|
48
66
|
],
|
|
@@ -50,14 +68,14 @@
|
|
|
50
68
|
"license": "MIT",
|
|
51
69
|
"repository": {
|
|
52
70
|
"type": "git",
|
|
53
|
-
"url": "https://github.com/hmmhmmhm/daiso-mcp.git"
|
|
71
|
+
"url": "git+https://github.com/hmmhmmhm/daiso-mcp.git"
|
|
54
72
|
},
|
|
55
73
|
"homepage": "https://github.com/hmmhmmhm/daiso-mcp#readme",
|
|
56
74
|
"bugs": {
|
|
57
75
|
"url": "https://github.com/hmmhmmhm/daiso-mcp/issues"
|
|
58
76
|
},
|
|
59
77
|
"engines": {
|
|
60
|
-
"node": ">=20
|
|
78
|
+
"node": ">=20"
|
|
61
79
|
},
|
|
62
80
|
"devDependencies": {
|
|
63
81
|
"@cloudflare/workers-types": "^4.20260316.1",
|
|
@@ -82,7 +100,8 @@
|
|
|
82
100
|
"overrides": {
|
|
83
101
|
"flatted": "3.4.2",
|
|
84
102
|
"undici": "7.24.0",
|
|
85
|
-
"brace-expansion": "5.0.6"
|
|
103
|
+
"brace-expansion": "5.0.6",
|
|
104
|
+
"ws": "8.20.1"
|
|
86
105
|
},
|
|
87
106
|
"dependencies": {
|
|
88
107
|
"@modelcontextprotocol/sdk": "^1.27.1",
|