@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mandujs/core",
3
- "version": "0.18.12",
3
+ "version": "0.18.14",
4
4
  "description": "Mandu Framework Core - Spec, Generator, Guard, Runtime",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -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 patterns = [
1016
- /(?:추가|구현|만들)(?:어|해)[줘요]?\s*[:\-]?\s*(.+)/,
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 patterns) {
1045
+ for (const pattern of englishPatterns) {
1022
1046
  const match = intent.match(pattern);
1023
1047
  if (match) {
1024
- return match[1]
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
- return intent
1034
- .split(/\s+/)[0]
1035
- .toLowerCase()
1036
- .replace(/[^a-z0-9]/g, "") || "feature";
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] || [];