@mandujs/core 0.18.12 → 0.18.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/guard/negotiation.ts +41 -15
package/package.json
CHANGED
package/src/guard/negotiation.ts
CHANGED
|
@@ -37,6 +37,13 @@ export interface NegotiationRequest {
|
|
|
37
37
|
/** 구현하려는 기능의 의도 */
|
|
38
38
|
intent: string;
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* 영문 feature name slug (에이전트가 제공).
|
|
42
|
+
* 제공되면 extractFeatureName()을 건너뛰고 이 값을 그대로 사용.
|
|
43
|
+
* 예: "chat", "user-auth", "payment", "file-upload"
|
|
44
|
+
*/
|
|
45
|
+
featureName?: string;
|
|
46
|
+
|
|
40
47
|
/** 요구사항 목록 */
|
|
41
48
|
requirements?: string[];
|
|
42
49
|
|
|
@@ -1010,30 +1017,49 @@ function toCamelCase(str: string): string {
|
|
|
1010
1017
|
.replace(/^(.)/, (_, c) => c.toLowerCase());
|
|
1011
1018
|
}
|
|
1012
1019
|
|
|
1020
|
+
/** 에이전트 제공 slug 정리: lowercase kebab-case, 빈 문자열이면 falsy */
|
|
1021
|
+
function sanitizeSlug(slug: string | undefined): string {
|
|
1022
|
+
if (!slug) return "";
|
|
1023
|
+
return slug
|
|
1024
|
+
.trim()
|
|
1025
|
+
.toLowerCase()
|
|
1026
|
+
.replace(/\s+/g, "-")
|
|
1027
|
+
.replace(/[^a-z0-9-]/g, "")
|
|
1028
|
+
.replace(/-{2,}/g, "-")
|
|
1029
|
+
.replace(/^-+|-+$/g, "");
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/**
|
|
1033
|
+
* intent에서 feature name 추출 (featureName 미제공 시 fallback)
|
|
1034
|
+
*
|
|
1035
|
+
* MCP 에이전트는 항상 featureName을 영문으로 제공하므로,
|
|
1036
|
+
* 이 함수는 CLI/프로그래밍 직접 호출 시 fallback으로만 사용.
|
|
1037
|
+
*/
|
|
1013
1038
|
function extractFeatureName(intent: string): string {
|
|
1014
|
-
//
|
|
1015
|
-
const
|
|
1016
|
-
/(
|
|
1017
|
-
/(.+?)\s
|
|
1018
|
-
/(?:add|implement|create)\s+(.+)/i,
|
|
1039
|
+
// 1. 영문 패턴 추출
|
|
1040
|
+
const englishPatterns = [
|
|
1041
|
+
/(?:add|implement|create|build)\s+(.+)/i,
|
|
1042
|
+
/(.+?)\s+(?:feature|system|module|service)/i,
|
|
1019
1043
|
];
|
|
1020
1044
|
|
|
1021
|
-
for (const pattern of
|
|
1045
|
+
for (const pattern of englishPatterns) {
|
|
1022
1046
|
const match = intent.match(pattern);
|
|
1023
1047
|
if (match) {
|
|
1024
|
-
|
|
1048
|
+
const slug = match[1]
|
|
1025
1049
|
.trim()
|
|
1026
1050
|
.toLowerCase()
|
|
1027
1051
|
.replace(/\s+/g, "-")
|
|
1028
|
-
.replace(/[^a-z0-9-]/g, "")
|
|
1052
|
+
.replace(/[^a-z0-9-]/g, "")
|
|
1053
|
+
.replace(/^-+|-+$/g, "");
|
|
1054
|
+
if (slug) return slug;
|
|
1029
1055
|
}
|
|
1030
1056
|
}
|
|
1031
1057
|
|
|
1032
|
-
//
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1058
|
+
// 2. intent 내 영문 단어 추출
|
|
1059
|
+
const englishWord = intent.match(/[a-z][a-z0-9-]{2,}/i)?.[0]?.toLowerCase();
|
|
1060
|
+
if (englishWord) return englishWord;
|
|
1061
|
+
|
|
1062
|
+
return "feature";
|
|
1037
1063
|
}
|
|
1038
1064
|
|
|
1039
1065
|
/**
|
|
@@ -1131,8 +1157,8 @@ export async function negotiate(
|
|
|
1131
1157
|
// 1. 카테고리 감지
|
|
1132
1158
|
const category = request.category || detectCategory(intent);
|
|
1133
1159
|
|
|
1134
|
-
// 2. 기능
|
|
1135
|
-
const featureName = extractFeatureName(intent);
|
|
1160
|
+
// 2. 기능 이름: 에이전트 제공 값 우선, 없으면 자동 추출
|
|
1161
|
+
const featureName = sanitizeSlug(request.featureName) || extractFeatureName(intent);
|
|
1136
1162
|
|
|
1137
1163
|
// 3. 관련 결정 검색
|
|
1138
1164
|
const categoryTags = CATEGORY_KEYWORDS[category] || [];
|