@ncds/ui-admin-mcp 1.0.0-alpha.21 → 1.0.0-alpha.23
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/bin/components.bundle.js +8 -8
- package/bin/definitions/instructions.md +6 -3
- package/bin/definitions/js-api.json +80 -0
- package/bin/definitions/rules.json +8 -4
- package/bin/overrides/composition.json +328 -25
- package/bin/server.js +6 -3
- package/bin/tools/renderToHtml.js +2 -1
- package/bin/types.d.ts +2 -0
- package/bin/utils/tokenValidator.js +33 -3
- package/bin/version.d.ts +1 -1
- package/bin/version.js +1 -1
- package/data/_icons.json +26 -1
- package/data/badge-group.json +11 -11
- package/data/badge.json +20 -16
- package/data/bread-crumb.json +2 -1
- package/data/button.json +2 -2
- package/data/combo-box.json +4 -3
- package/data/context-tab.json +119 -0
- package/data/date-picker.json +1 -1
- package/data/dropdown.json +6 -4
- package/data/empty-state.json +3 -3
- package/data/file-input.json +4 -2
- package/data/horizontal-tab.json +7 -5
- package/data/image-file-input.json +4 -2
- package/data/modal.json +1 -1
- package/data/notification.json +2 -1
- package/data/page-title.json +2 -1
- package/data/progress-bar.json +2 -1
- package/data/range-date-picker-with-buttons.json +7 -6
- package/data/range-date-picker.json +5 -5
- package/data/select-box.json +4 -3
- package/data/select.json +3 -2
- package/data/table.json +4 -2
- package/data/tag.json +1 -1
- package/data/vertical-tab.json +7 -5
- package/package.json +2 -2
- package/bin/tools/listSidecarOverrides.d.ts +0 -54
- package/bin/tools/listSidecarOverrides.js +0 -96
package/data/notification.json
CHANGED
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
"actions": {
|
|
46
46
|
"type": "object",
|
|
47
47
|
"required": false,
|
|
48
|
-
"rawType": "import(\"/
|
|
48
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/overlays/notification/Notification\").NotificationAction[] | undefined",
|
|
49
|
+
"isArray": true,
|
|
49
50
|
"properties": {
|
|
50
51
|
"label": {
|
|
51
52
|
"type": "string",
|
package/data/page-title.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"breadcrumbItems": {
|
|
57
57
|
"type": "object",
|
|
58
58
|
"required": false,
|
|
59
|
-
"rawType": "import(\"/
|
|
59
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/layout/page-title/PageTitle\").PageTitleBreadcrumbItem[] | undefined",
|
|
60
|
+
"isArray": true,
|
|
60
61
|
"properties": {
|
|
61
62
|
"label": {
|
|
62
63
|
"type": "string",
|
package/data/progress-bar.json
CHANGED
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
"segments": {
|
|
53
53
|
"type": "object",
|
|
54
54
|
"required": false,
|
|
55
|
-
"rawType": "import(\"/
|
|
55
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/feedback-and-status/progress-bar/types\").ProgressSegment[] | undefined",
|
|
56
|
+
"isArray": true,
|
|
56
57
|
"properties": {
|
|
57
58
|
"value": {
|
|
58
59
|
"type": "number",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "range-date-picker-with-buttons",
|
|
3
3
|
"exportName": "RangeDatePickerWithButtons",
|
|
4
4
|
"importPath": "@ncds/ui-admin",
|
|
5
|
-
"jsRequired":
|
|
5
|
+
"jsRequired": true,
|
|
6
6
|
"category": "forms-and-input",
|
|
7
7
|
"description": "기간 옵션 버튼이 내장된 RangeDatePicker 확장 컴포넌트로 빠른 기간 설정을 지원합니다",
|
|
8
8
|
"aliases": [
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"endDateOptions": {
|
|
62
62
|
"type": "object",
|
|
63
63
|
"required": true,
|
|
64
|
-
"rawType": "import(\"/
|
|
64
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/forms-and-input/date-picker/DatePicker\").DatePickerProps",
|
|
65
65
|
"properties": {
|
|
66
66
|
"size": {
|
|
67
67
|
"type": "enum",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"datePickerOptions": {
|
|
83
83
|
"type": "object",
|
|
84
84
|
"required": false,
|
|
85
|
-
"rawType": "Partial<import(\"/
|
|
85
|
+
"rawType": "Partial<import(\"/home/runner/_work/ncds/ncds/node_modules/.pnpm/flatpickr@4.6.13/node_modules/flatpickr/dist/types/options\").BaseOptions> | undefined"
|
|
86
86
|
},
|
|
87
87
|
"destructive": {
|
|
88
88
|
"type": "string",
|
|
@@ -126,7 +126,8 @@
|
|
|
126
126
|
"periodKeys": {
|
|
127
127
|
"type": "object",
|
|
128
128
|
"required": true,
|
|
129
|
-
"rawType": "(keyof T & string)[]"
|
|
129
|
+
"rawType": "(keyof T & string)[]",
|
|
130
|
+
"isArray": true
|
|
130
131
|
},
|
|
131
132
|
"setCurrentButtonId": {
|
|
132
133
|
"type": "function",
|
|
@@ -144,7 +145,7 @@
|
|
|
144
145
|
"startDateOptions": {
|
|
145
146
|
"type": "object",
|
|
146
147
|
"required": true,
|
|
147
|
-
"rawType": "import(\"/
|
|
148
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/forms-and-input/date-picker/DatePicker\").DatePickerProps",
|
|
148
149
|
"properties": {
|
|
149
150
|
"size": {
|
|
150
151
|
"type": "enum",
|
|
@@ -165,7 +166,7 @@
|
|
|
165
166
|
"datePickerOptions": {
|
|
166
167
|
"type": "object",
|
|
167
168
|
"required": false,
|
|
168
|
-
"rawType": "Partial<import(\"/
|
|
169
|
+
"rawType": "Partial<import(\"/home/runner/_work/ncds/ncds/node_modules/.pnpm/flatpickr@4.6.13/node_modules/flatpickr/dist/types/options\").BaseOptions> | undefined"
|
|
169
170
|
},
|
|
170
171
|
"destructive": {
|
|
171
172
|
"type": "string",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "range-date-picker",
|
|
3
3
|
"exportName": "RangeDatePicker",
|
|
4
4
|
"importPath": "@ncds/ui-admin",
|
|
5
|
-
"jsRequired":
|
|
5
|
+
"jsRequired": true,
|
|
6
6
|
"category": "forms-and-input",
|
|
7
7
|
"description": "RangeDatePicker는 시작일~종료일 기간 범위를 선택해야 하는 경우 사용하는 복합 선택 위젯입니다. 검색 기간 설정, 노출 기간 설정, 이벤트 기간 설정 등 두 날짜의 쌍(Pair)이 필요한 모든 상황에서 사용합니다.",
|
|
8
8
|
"aliases": [
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"endDateOptions": {
|
|
67
67
|
"type": "object",
|
|
68
68
|
"required": true,
|
|
69
|
-
"rawType": "import(\"/
|
|
69
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/forms-and-input/date-picker/DatePicker\").DatePickerProps",
|
|
70
70
|
"properties": {
|
|
71
71
|
"size": {
|
|
72
72
|
"type": "enum",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"datePickerOptions": {
|
|
88
88
|
"type": "object",
|
|
89
89
|
"required": false,
|
|
90
|
-
"rawType": "Partial<import(\"/
|
|
90
|
+
"rawType": "Partial<import(\"/home/runner/_work/ncds/ncds/node_modules/.pnpm/flatpickr@4.6.13/node_modules/flatpickr/dist/types/options\").BaseOptions> | undefined"
|
|
91
91
|
},
|
|
92
92
|
"destructive": {
|
|
93
93
|
"type": "string",
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
"startDateOptions": {
|
|
136
136
|
"type": "object",
|
|
137
137
|
"required": true,
|
|
138
|
-
"rawType": "import(\"/
|
|
138
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/forms-and-input/date-picker/DatePicker\").DatePickerProps",
|
|
139
139
|
"properties": {
|
|
140
140
|
"size": {
|
|
141
141
|
"type": "enum",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
"datePickerOptions": {
|
|
157
157
|
"type": "object",
|
|
158
158
|
"required": false,
|
|
159
|
-
"rawType": "Partial<import(\"/
|
|
159
|
+
"rawType": "Partial<import(\"/home/runner/_work/ncds/ncds/node_modules/.pnpm/flatpickr@4.6.13/node_modules/flatpickr/dist/types/options\").BaseOptions> | undefined"
|
|
160
160
|
},
|
|
161
161
|
"destructive": {
|
|
162
162
|
"type": "string",
|
package/data/select-box.json
CHANGED
|
@@ -120,7 +120,8 @@
|
|
|
120
120
|
"optionItems": {
|
|
121
121
|
"type": "object",
|
|
122
122
|
"required": false,
|
|
123
|
-
"rawType": "import(\"/
|
|
123
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/types/dropdown/option\").OptionType[] | undefined",
|
|
124
|
+
"isArray": true,
|
|
124
125
|
"properties": {
|
|
125
126
|
"id": {
|
|
126
127
|
"type": "string",
|
|
@@ -147,7 +148,7 @@
|
|
|
147
148
|
"register": {
|
|
148
149
|
"type": "object",
|
|
149
150
|
"required": false,
|
|
150
|
-
"rawType": "import(\"/
|
|
151
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/node_modules/.pnpm/react-hook-form@7.72.0_react@18.2.0/node_modules/react-hook-form/dist/types/form\").UseFormRegisterReturn | undefined"
|
|
151
152
|
},
|
|
152
153
|
"size": {
|
|
153
154
|
"type": "enum",
|
|
@@ -175,7 +176,7 @@
|
|
|
175
176
|
"value": {
|
|
176
177
|
"type": "object",
|
|
177
178
|
"required": false,
|
|
178
|
-
"rawType": "import(\"/
|
|
179
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/types/dropdown/option\").OptionValue | undefined"
|
|
179
180
|
}
|
|
180
181
|
},
|
|
181
182
|
"html": {},
|
package/data/select.json
CHANGED
|
@@ -57,7 +57,8 @@
|
|
|
57
57
|
"optionItems": {
|
|
58
58
|
"type": "object",
|
|
59
59
|
"required": false,
|
|
60
|
-
"rawType": "import(\"/
|
|
60
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/types/dropdown/option\").OptionType[] | undefined",
|
|
61
|
+
"isArray": true,
|
|
61
62
|
"properties": {
|
|
62
63
|
"id": {
|
|
63
64
|
"type": "string",
|
|
@@ -82,7 +83,7 @@
|
|
|
82
83
|
"register": {
|
|
83
84
|
"type": "object",
|
|
84
85
|
"required": false,
|
|
85
|
-
"rawType": "import(\"/
|
|
86
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/node_modules/.pnpm/react-hook-form@7.72.0_react@18.2.0/node_modules/react-hook-form/dist/types/form\").UseFormRegisterReturn | undefined"
|
|
86
87
|
},
|
|
87
88
|
"size": {
|
|
88
89
|
"type": "enum",
|
package/data/table.json
CHANGED
|
@@ -226,12 +226,14 @@
|
|
|
226
226
|
"minWidths": {
|
|
227
227
|
"type": "object",
|
|
228
228
|
"required": false,
|
|
229
|
-
"rawType": "(string | number)[] | undefined"
|
|
229
|
+
"rawType": "(string | number)[] | undefined",
|
|
230
|
+
"isArray": true
|
|
230
231
|
},
|
|
231
232
|
"widths": {
|
|
232
233
|
"type": "object",
|
|
233
234
|
"required": true,
|
|
234
|
-
"rawType": "(string | number)[]"
|
|
235
|
+
"rawType": "(string | number)[]",
|
|
236
|
+
"isArray": true
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
239
|
},
|
package/data/tag.json
CHANGED
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"icon": {
|
|
58
58
|
"type": "object",
|
|
59
59
|
"required": false,
|
|
60
|
-
"rawType": "import(\"/
|
|
60
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
61
61
|
"properties": {
|
|
62
62
|
"type": {
|
|
63
63
|
"type": "string",
|
package/data/vertical-tab.json
CHANGED
|
@@ -59,7 +59,8 @@
|
|
|
59
59
|
"menus": {
|
|
60
60
|
"type": "object",
|
|
61
61
|
"required": false,
|
|
62
|
-
"rawType": "import(\"/
|
|
62
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/tab/TabButton\").TabButtonProps[] | undefined",
|
|
63
|
+
"isArray": true,
|
|
63
64
|
"properties": {
|
|
64
65
|
"id": {
|
|
65
66
|
"type": "string",
|
|
@@ -96,16 +97,17 @@
|
|
|
96
97
|
"badgeInfo": {
|
|
97
98
|
"type": "object",
|
|
98
99
|
"required": false,
|
|
99
|
-
"rawType": "import(\"/
|
|
100
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/feedback-and-status/badge/Badge\").BadgeProps | undefined",
|
|
100
101
|
"properties": {
|
|
101
102
|
"label": {
|
|
102
103
|
"type": "string",
|
|
103
|
-
"required":
|
|
104
|
+
"required": false
|
|
104
105
|
},
|
|
105
106
|
"type": {
|
|
106
107
|
"type": "enum",
|
|
107
108
|
"required": false,
|
|
108
109
|
"values": [
|
|
110
|
+
"new-badge",
|
|
109
111
|
"pill-dark-color",
|
|
110
112
|
"pill-outline"
|
|
111
113
|
]
|
|
@@ -130,7 +132,7 @@
|
|
|
130
132
|
"leadingIcon": {
|
|
131
133
|
"type": "object",
|
|
132
134
|
"required": false,
|
|
133
|
-
"rawType": "import(\"/
|
|
135
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
134
136
|
"properties": {
|
|
135
137
|
"type": {
|
|
136
138
|
"type": "string",
|
|
@@ -193,7 +195,7 @@
|
|
|
193
195
|
"trailingIcon": {
|
|
194
196
|
"type": "object",
|
|
195
197
|
"required": false,
|
|
196
|
-
"rawType": "import(\"/
|
|
198
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
197
199
|
"properties": {
|
|
198
200
|
"type": {
|
|
199
201
|
"type": "string",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ncds/ui-admin-mcp",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.23",
|
|
4
4
|
"description": "NCDS UI Admin MCP 서버 — AI 에이전트가 NCUA 컴포넌트를 조회하고 HTML을 검증할 수 있는 MCP 서버",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ncua-mcp": "./bin/server.mjs"
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "1.1.0",
|
|
45
45
|
"@atlaskit/pragmatic-drag-and-drop-react-accessibility": "1.1.4",
|
|
46
46
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
47
|
-
"@ncds/ui-admin-icon": "0.1.
|
|
47
|
+
"@ncds/ui-admin-icon": "0.1.12",
|
|
48
48
|
"classnames": "2.5.1",
|
|
49
49
|
"dompurify": "3.4.1",
|
|
50
50
|
"flatpickr": "4.6.13",
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* list_sidecar_overrides tool — composition.json sidecar 적용 현황 요약
|
|
3
|
-
*
|
|
4
|
-
* 신규 프로젝트에서 NCDS MCP 와 연결한 뒤, 어느 컴포넌트에 어떤 sidecar 보강이
|
|
5
|
-
* 들어가 있는지 표 형태(컴포넌트별 row)로 한 번에 확인하는 용도. 응답이 크지 않도록
|
|
6
|
-
* 시나리오 키 목록 + 카운트 위주로 구성하고, 상세는 get_component_props 로 유도.
|
|
7
|
-
*
|
|
8
|
-
* 순수 함수 — server.ts 부팅 시 1회 buildListSidecarOverridesResponse() 로 사전 직렬화.
|
|
9
|
-
*/
|
|
10
|
-
import type { ComponentData } from '../types.js';
|
|
11
|
-
import type { CompositionEntry } from '../utils/dataLoader.js';
|
|
12
|
-
import { type McpToolResponse } from '../utils/response.js';
|
|
13
|
-
export interface SidecarOverrideSummary {
|
|
14
|
-
/** 컴포넌트 이름 (kebab-case) */
|
|
15
|
-
component: string;
|
|
16
|
-
/** canonicalExamples 시나리오 key 목록 — 비어있으면 [] */
|
|
17
|
-
canonicalExamples: string[];
|
|
18
|
-
/** legacy 단일 시나리오 canonicalExample 존재 여부 */
|
|
19
|
-
hasCanonicalExample: boolean;
|
|
20
|
-
/** bemClassesExtra 항목 수 */
|
|
21
|
-
bemClassesExtra: number;
|
|
22
|
-
/** allowedChildren 정의된 부모 키 목록 (예: ["Table", "Table.Header", ...]) */
|
|
23
|
-
allowedChildrenKeys: string[];
|
|
24
|
-
/** allowedParents 정의된 자식 키 목록 */
|
|
25
|
-
allowedParentsKeys: string[];
|
|
26
|
-
/** descriptionExtra 존재 여부 */
|
|
27
|
-
descriptionExtra: boolean;
|
|
28
|
-
/** aliasesExtra 항목 수 */
|
|
29
|
-
aliasesExtra: number;
|
|
30
|
-
/** AI 의 UI 작성 정확도 추정 점수 (0.0 ~ 1.0). 시나리오 + compound 제약 + validate 정확도 + 자연어 보강의 가중 합. */
|
|
31
|
-
coverageScore: number;
|
|
32
|
-
/** 컴포넌트 구조상 의미 있게 달성 가능한 최대 점수. compound 컴포넌트(subComponents 보유): 1.0, 그 외: 0.8. */
|
|
33
|
-
maxAchievable: number;
|
|
34
|
-
/** coverageScore / maxAchievable — 컴포넌트별 천장 대비 충족율 (0.0 ~ 1.0). 절대 점수가 낮아도 비율이 1.0 이면 더 보강할 게 없다. */
|
|
35
|
-
coverageRatio: number;
|
|
36
|
-
/** coverageScore 한 줄 해석 — high/medium/low 와 강점 영역 요약 */
|
|
37
|
-
coverageNote: string;
|
|
38
|
-
}
|
|
39
|
-
export interface ListSidecarOverridesResult {
|
|
40
|
-
/** sidecar 적용 컴포넌트 수 */
|
|
41
|
-
total: number;
|
|
42
|
-
/** 각 척도가 무엇을 의미하고 AI 의 UI 작성 정확도에 어떻게 영향을 주는지 (AI 가 본 응답을 바로 해석하도록 동봉) */
|
|
43
|
-
metrics: Record<string, string>;
|
|
44
|
-
/** coverageScore 산식 (가중치 명시) */
|
|
45
|
-
coverageScoreFormula: string;
|
|
46
|
-
/** 컴포넌트별 요약 row 배열 — coverageScore 내림차순, 동률은 컴포넌트 이름 알파벳 */
|
|
47
|
-
overrides: SidecarOverrideSummary[];
|
|
48
|
-
}
|
|
49
|
-
/** sidecar map → 요약 결과 (순수 함수). coverageRatio 내림차순 + 동률은 coverageScore + 이름 알파벳 */
|
|
50
|
-
export declare const buildSidecarOverridesSummary: (sidecar: Record<string, CompositionEntry>, componentMap: Map<string, ComponentData>) => ListSidecarOverridesResult;
|
|
51
|
-
/** server.ts 부팅 시 1회 호출 — 응답 사전 직렬화 */
|
|
52
|
-
export declare const buildListSidecarOverridesResponse: (sidecar: Record<string, CompositionEntry>, componentMap: Map<string, ComponentData>) => McpToolResponse;
|
|
53
|
-
/** list_sidecar_overrides tool — 사전 직렬화된 응답을 그대로 반환 */
|
|
54
|
-
export declare const listSidecarOverrides: (prebuilt: McpToolResponse) => McpToolResponse;
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.listSidecarOverrides = exports.buildListSidecarOverridesResponse = exports.buildSidecarOverridesSummary = void 0;
|
|
4
|
-
const response_js_1 = require("../utils/response.js");
|
|
5
|
-
/** AI 가 UI 를 얼마나 정확히 그릴 수 있는지 추정 — 각 sidecar 보강이 다른 정확도 영역을 커버한다 */
|
|
6
|
-
const METRIC_DESCRIPTIONS = {
|
|
7
|
-
canonicalExamples: 'AI 가 시나리오별로 분기 가능한 정답 트리 수 (form / data-grid / with-tooltip 등). 가장 강한 정확도 신호 — 0 이면 AI 가 prop 조합을 추측해야 한다.',
|
|
8
|
-
hasCanonicalExample: 'legacy 단일 시나리오 존재 여부 — 진입용 표준 트리 1건. canonicalExamples 가 비어있는 컴포넌트의 fallback.',
|
|
9
|
-
bemClassesExtra: 'extract 가 못 잡은 BEM 클래스 화이트리스트 수. validate_html 이 합법/위법을 정확히 판정 — 발명 클래스 사용 차단력.',
|
|
10
|
-
allowedChildrenKeys: 'compound 부모-자식 제약 노드 수. 잘못된 자식 끼우기 / 컨텍스트 위반 (Table.Pagination in DataGrid 등) 차단력.',
|
|
11
|
-
allowedParentsKeys: '역방향 제약 노드 수 — 자식이 어느 부모 안에만 허용되는지 명시.',
|
|
12
|
-
descriptionExtra: 'list_components 응답에 자연어 용도/모드 명시 여부. 같은 컴포넌트가 다른 모드(horizontal/vertical) 로 쓰일 때 AI 가 모드를 인지하는 정확도.',
|
|
13
|
-
aliasesExtra: 'search_component 한국어/유사 키워드 매칭 별칭 수. AI 가 "폼 레이아웃", "세로 테이블" 같은 비공식 용어로 검색해도 정답 컴포넌트에 도달.',
|
|
14
|
-
maxAchievable: '구조상 의미 있게 도달 가능한 최대 점수. compound 컴포넌트(subComponents 보유): 1.0, 그 외(prop 배열로 항목 받는 컴포넌트 — menus/groups/optionItems 등): 0.8. allowedChildren 가중치(+0.20) 가 compound 가 아닌 컴포넌트에는 적용 불가하기 때문.',
|
|
15
|
-
coverageRatio: 'coverageScore / maxAchievable. 절대 점수보다 더 정확한 "보강 충족율" — 1.0 이면 해당 컴포넌트는 더 채울 영역이 없다. 0.8 미만이면 의미 있는 보강 여지 있음.',
|
|
16
|
-
};
|
|
17
|
-
const COVERAGE_FORMULA = 'canonicalExamples>=2: +0.50 (>=1 또는 hasCanonicalExample: +0.25) · allowedChildrenKeys>=2: +0.20 (>=1: +0.10) · bemClassesExtra>=1: +0.10 · descriptionExtra: +0.10 · aliasesExtra>=1: +0.10 · max 1.0. 임계값: high>=0.70, medium>=0.40, 그 외 low. 시나리오 가중치가 가장 큼 — AI hallucination 의 가장 강한 차단 신호이기 때문.';
|
|
18
|
-
const computeCoverageScore = (s) => {
|
|
19
|
-
let score = 0;
|
|
20
|
-
if (s.canonicalExamples.length >= 2)
|
|
21
|
-
score += 0.5;
|
|
22
|
-
else if (s.canonicalExamples.length >= 1 || s.hasCanonicalExample)
|
|
23
|
-
score += 0.25;
|
|
24
|
-
if (s.allowedChildrenKeys.length >= 2)
|
|
25
|
-
score += 0.2;
|
|
26
|
-
else if (s.allowedChildrenKeys.length >= 1)
|
|
27
|
-
score += 0.1;
|
|
28
|
-
if (s.bemClassesExtra >= 1)
|
|
29
|
-
score += 0.1;
|
|
30
|
-
if (s.descriptionExtra)
|
|
31
|
-
score += 0.1;
|
|
32
|
-
if (s.aliasesExtra >= 1)
|
|
33
|
-
score += 0.1;
|
|
34
|
-
return Math.min(1, Math.round(score * 100) / 100);
|
|
35
|
-
};
|
|
36
|
-
/** 컴포넌트 구조상 의미 있게 도달 가능한 최대 점수.
|
|
37
|
-
* compound (subComponents 보유): canonicalExamples 0.5 + allowedChildren 0.2 + bem 0.1 + desc 0.1 + alias 0.1 = 1.0.
|
|
38
|
-
* non-compound: allowedChildren 항목이 의미 없음 → 0.8 cap. */
|
|
39
|
-
const computeMaxAchievable = (isCompound) => (isCompound ? 1.0 : 0.8);
|
|
40
|
-
const noteFor = (s, score) => {
|
|
41
|
-
const strengths = [];
|
|
42
|
-
if (s.canonicalExamples.length >= 2)
|
|
43
|
-
strengths.push(`시나리오 ${s.canonicalExamples.length}`);
|
|
44
|
-
else if (s.canonicalExamples.length >= 1 || s.hasCanonicalExample)
|
|
45
|
-
strengths.push('시나리오 1');
|
|
46
|
-
if (s.allowedChildrenKeys.length >= 1)
|
|
47
|
-
strengths.push(`compound 제약 ${s.allowedChildrenKeys.length}`);
|
|
48
|
-
if (s.bemClassesExtra >= 1)
|
|
49
|
-
strengths.push(`BEM 화이트리스트 ${s.bemClassesExtra}`);
|
|
50
|
-
if (s.descriptionExtra)
|
|
51
|
-
strengths.push('모드 인지 보강');
|
|
52
|
-
if (s.aliasesExtra >= 1)
|
|
53
|
-
strengths.push(`검색 별칭 ${s.aliasesExtra}`);
|
|
54
|
-
const tier = score >= 0.7 ? 'high' : score >= 0.4 ? 'medium' : 'low';
|
|
55
|
-
return strengths.length > 0 ? `${tier} · ${strengths.join(' + ')}` : `${tier} · 보강 거의 없음 — 직접 작성 hallucination 위험`;
|
|
56
|
-
};
|
|
57
|
-
/** 단일 entry 를 row 로 변환 — componentMap 으로 compound 여부 결정해 maxAchievable 계산 */
|
|
58
|
-
const toSummary = (component, entry, componentMap) => {
|
|
59
|
-
const base = {
|
|
60
|
-
component,
|
|
61
|
-
canonicalExamples: Object.keys(entry.canonicalExamples ?? {}).filter((k) => !k.startsWith('_')),
|
|
62
|
-
hasCanonicalExample: !!entry.canonicalExample,
|
|
63
|
-
bemClassesExtra: (entry.bemClassesExtra ?? []).length,
|
|
64
|
-
allowedChildrenKeys: Object.keys(entry.allowedChildren ?? {}),
|
|
65
|
-
allowedParentsKeys: Object.keys(entry.allowedParents ?? {}),
|
|
66
|
-
descriptionExtra: !!entry.descriptionExtra,
|
|
67
|
-
aliasesExtra: (entry.aliasesExtra ?? []).length,
|
|
68
|
-
};
|
|
69
|
-
const coverageScore = computeCoverageScore(base);
|
|
70
|
-
const subComponentCount = Object.keys(componentMap.get(component)?.subComponents ?? {}).length;
|
|
71
|
-
const isCompound = subComponentCount > 0;
|
|
72
|
-
const maxAchievable = computeMaxAchievable(isCompound);
|
|
73
|
-
const coverageRatio = Math.round((coverageScore / maxAchievable) * 100) / 100;
|
|
74
|
-
return { ...base, coverageScore, maxAchievable, coverageRatio, coverageNote: noteFor(base, coverageScore) };
|
|
75
|
-
};
|
|
76
|
-
/** sidecar map → 요약 결과 (순수 함수). coverageRatio 내림차순 + 동률은 coverageScore + 이름 알파벳 */
|
|
77
|
-
const buildSidecarOverridesSummary = (sidecar, componentMap) => {
|
|
78
|
-
const overrides = Object.entries(sidecar)
|
|
79
|
-
.map(([component, entry]) => toSummary(component, entry, componentMap))
|
|
80
|
-
.sort((a, b) => b.coverageRatio - a.coverageRatio ||
|
|
81
|
-
b.coverageScore - a.coverageScore ||
|
|
82
|
-
a.component.localeCompare(b.component));
|
|
83
|
-
return {
|
|
84
|
-
total: overrides.length,
|
|
85
|
-
metrics: METRIC_DESCRIPTIONS,
|
|
86
|
-
coverageScoreFormula: COVERAGE_FORMULA,
|
|
87
|
-
overrides,
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
exports.buildSidecarOverridesSummary = buildSidecarOverridesSummary;
|
|
91
|
-
/** server.ts 부팅 시 1회 호출 — 응답 사전 직렬화 */
|
|
92
|
-
const buildListSidecarOverridesResponse = (sidecar, componentMap) => (0, response_js_1.successResponse)((0, exports.buildSidecarOverridesSummary)(sidecar, componentMap));
|
|
93
|
-
exports.buildListSidecarOverridesResponse = buildListSidecarOverridesResponse;
|
|
94
|
-
/** list_sidecar_overrides tool — 사전 직렬화된 응답을 그대로 반환 */
|
|
95
|
-
const listSidecarOverrides = (prebuilt) => prebuilt;
|
|
96
|
-
exports.listSidecarOverrides = listSidecarOverrides;
|