@morya-ui/mcp 0.2.8 → 0.3.0
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 +2 -2
- package/data/catalog.json +529 -248
- package/data/example-coverage.json +67 -39
- package/data/golden-pages/dashboard-page.vue +41 -8
- package/data/golden-pages/detail-page.vue +178 -0
- package/data/golden-pages/empty-state.vue +22 -1
- package/data/golden-pages/form-in-dialog.vue +166 -0
- package/data/golden-pages/form-page.vue +1 -1
- package/data/golden-pages/landing-page.vue +31 -1
- package/data/golden-pages/list-page.vue +25 -12
- package/data/golden-pages/login-page.vue +44 -4
- package/data/golden-pages/result-page.vue +84 -0
- package/data/golden-pages/settings-page.vue +163 -0
- package/data/golden-pages/wizard-form.vue +182 -0
- package/dist/__tests__/tools.test.js +97 -4
- package/dist/decisions.js +136 -1
- package/dist/golden-pages.js +35 -0
- package/dist/index.js +1 -1
- package/dist/page-snippets.js +46 -36
- package/dist/patterns.d.ts +7 -5
- package/dist/patterns.js +29 -8
- package/dist/tools.js +181 -58
- package/package.json +1 -1
package/dist/tools.js
CHANGED
|
@@ -57,7 +57,7 @@ function generatedPageCode(patternId, intent, locale) {
|
|
|
57
57
|
const isSettings = patternId === 'settings-page';
|
|
58
58
|
const isAuth = patternId === 'auth-page';
|
|
59
59
|
const isForm = patternId === 'form-page' || isSettings;
|
|
60
|
-
const useLayoutShell = isList || isForm || isDashboard || isDetail || isSettings;
|
|
60
|
+
const useLayoutShell = isList || isForm || isDashboard || isDetail || isSettings || isWizard;
|
|
61
61
|
const title = intent || (zh ? '业务页面' : 'Business page');
|
|
62
62
|
const layoutImports = useLayoutShell
|
|
63
63
|
? ', MLayout, MLayoutContent, MLayoutHeader, MLayoutSider, MBreadcrumb'
|
|
@@ -68,9 +68,9 @@ function generatedPageCode(patternId, intent, locale) {
|
|
|
68
68
|
const listImports = isList ? ', MEmpty, MSelect, MSpace, MTable' : '';
|
|
69
69
|
const formImports = isForm || isAuth || isWizard ? ', MForm, MFormItem, MSelect' : '';
|
|
70
70
|
const dashboardImports = isDashboard ? ', MCard, MGrid, MGridItem, MPagePlaceholder, MPageStat, MSkeleton, MTable' : '';
|
|
71
|
-
const detailImports = isDetail ? ',
|
|
71
|
+
const detailImports = isDetail ? ', MSpace' : '';
|
|
72
72
|
const emptyImports = isEmpty ? ', MEmpty, MPageToolbar' : '';
|
|
73
|
-
const wizardImports = isWizard ? ', MStepper' : '';
|
|
73
|
+
const wizardImports = isWizard ? ', MStepper, MSpace' : '';
|
|
74
74
|
const settingsImports = isSettings ? ', MTabs' : '';
|
|
75
75
|
const statusImports = isList || isDetail || isDashboard ? ', MStatus' : '';
|
|
76
76
|
const script = `<script setup lang="ts">
|
|
@@ -79,6 +79,7 @@ import { MButton, MCard, MConfigProvider, MInput, MTag, zhCN${layoutImports}${pa
|
|
|
79
79
|
|
|
80
80
|
const loading = ref(false)
|
|
81
81
|
const error = ref('')
|
|
82
|
+
const title = ${JSON.stringify(title)}
|
|
82
83
|
${isList ? `const keyword = ref('')
|
|
83
84
|
const rows = ref<Record<string, unknown>[]>([])
|
|
84
85
|
const columns = [{ key: 'name', label: '${zh ? '名称' : 'Name'}' }, { key: 'status', label: '${zh ? '状态' : 'Status'}' }]
|
|
@@ -87,7 +88,10 @@ const columns = [{ key: 'name', label: '${zh ? '名称' : 'Name'}' }, { key: 'st
|
|
|
87
88
|
{ label: '${zh ? '总用户' : 'Users'}', value: '0' },
|
|
88
89
|
{ label: '${zh ? '今日活跃' : 'Active today'}', value: '0' },
|
|
89
90
|
])
|
|
91
|
+
` : ''}${isSettings ? `const activeTab = ref('general')
|
|
92
|
+
const settingTabs = [{ label: '${zh ? '常规' : 'General'}', value: 'general' }]
|
|
90
93
|
` : ''}${isWizard ? `const activeStep = ref(0)
|
|
94
|
+
const wizardSteps = [{ label: '${zh ? '基本信息' : 'Details'}' }, { label: '${zh ? '确认' : 'Confirm'}' }]
|
|
91
95
|
` : ''}
|
|
92
96
|
|
|
93
97
|
async function submit() {
|
|
@@ -149,24 +153,48 @@ async function submit() {
|
|
|
149
153
|
<MSkeleton v-if="loading" height="8rem" />
|
|
150
154
|
<MPagePlaceholder v-else :description="${zh ? '接入图表或业务组件。' : 'Connect charts or business widgets here.'}" aria-label="${zh ? '图表占位' : 'Chart placeholder'}" />
|
|
151
155
|
</MCard>`;
|
|
152
|
-
const detailContent = ` <
|
|
156
|
+
const detailContent = ` <MPageHeader :title="title" :description="${zh ? '查看资源摘要与属性。' : 'Review summary and properties.'}">
|
|
153
157
|
<template #actions>
|
|
154
|
-
<
|
|
158
|
+
<MSpace>
|
|
159
|
+
<MStatus :label="${zh ? '启用' : 'Active'}" severity="success" />
|
|
160
|
+
<MButton severity="primary">${zh ? '编辑' : 'Edit'}</MButton>
|
|
161
|
+
<MButton severity="secondary">${zh ? '返回' : 'Back'}</MButton>
|
|
162
|
+
</MSpace>
|
|
155
163
|
</template>
|
|
156
|
-
</
|
|
157
|
-
<
|
|
158
|
-
|
|
159
|
-
<MDivider />
|
|
160
|
-
<p style="margin:0;color:var(--m-color-text-muted)">${zh ? '示例资源详情' : 'Example resource details'}</p>
|
|
164
|
+
</MPageHeader>
|
|
165
|
+
<MCard :title="${zh ? '基本信息' : 'Basics'}">
|
|
166
|
+
<p style="margin:0;color:var(--m-color-text-muted)">${zh ? '用定义列表或网格展示属性;相关列表用 MTable + rows。' : 'Use a definition grid; related lists use MTable + rows.'}</p>
|
|
161
167
|
</MCard>`;
|
|
162
|
-
const settingsContent = `
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
const settingsContent = ` <MPageHeader :title="title" :description="${zh ? '按域分组配置偏好。' : 'Grouped preference settings.'}" />
|
|
169
|
+
<MTabs v-model="activeTab" :tabs="settingTabs">
|
|
170
|
+
<template #default="{ activeValue }">
|
|
171
|
+
<MPageSection v-if="activeValue === 'general'" variant="form" :title="${zh ? '常规' : 'General'}">
|
|
172
|
+
<MForm @submit.prevent="submit">
|
|
173
|
+
<MFormItem label="${zh ? '显示名称' : 'Display name'}" name="name" required>
|
|
174
|
+
<MInput v-model="model.name" fluid />
|
|
175
|
+
</MFormItem>
|
|
176
|
+
<MPageSection variant="actions">
|
|
177
|
+
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '保存' : 'Save'}</MButton>
|
|
178
|
+
</MPageSection>
|
|
179
|
+
</MForm>
|
|
180
|
+
</MPageSection>
|
|
181
|
+
</template>
|
|
182
|
+
</MTabs>`;
|
|
183
|
+
const wizardContent = ` <MPageHeader :title="title" :description="${zh ? '每步一个主任务。' : 'One job per step.'}" />
|
|
184
|
+
<MStepper v-model="activeStep" :steps="wizardSteps" linear />
|
|
185
|
+
<MPageSection variant="form">
|
|
186
|
+
<MForm @submit.prevent="submit">
|
|
187
|
+
<MFormItem label="${zh ? '名称' : 'Name'}" name="name" required>
|
|
188
|
+
<MInput v-model="model.name" fluid />
|
|
189
|
+
</MFormItem>
|
|
190
|
+
<MPageSection variant="actions">
|
|
191
|
+
<MSpace>
|
|
192
|
+
<MButton severity="secondary" text :disabled="activeStep === 0" @click="activeStep = Math.max(activeStep - 1, 0)">${zh ? '上一步' : 'Back'}</MButton>
|
|
193
|
+
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '下一步' : 'Next'}</MButton>
|
|
194
|
+
</MSpace>
|
|
195
|
+
</MPageSection>
|
|
196
|
+
</MForm>
|
|
197
|
+
</MPageSection>`;
|
|
170
198
|
let innerTemplate = '';
|
|
171
199
|
if (isList) {
|
|
172
200
|
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
@@ -186,12 +214,20 @@ ${listContent}
|
|
|
186
214
|
</MConfigProvider>`;
|
|
187
215
|
}
|
|
188
216
|
else if (useLayoutShell) {
|
|
189
|
-
const content = isDashboard
|
|
190
|
-
|
|
217
|
+
const content = isDashboard
|
|
218
|
+
? dashboardContent
|
|
219
|
+
: isDetail
|
|
220
|
+
? detailContent
|
|
221
|
+
: isSettings
|
|
222
|
+
? settingsContent
|
|
223
|
+
: isWizard
|
|
224
|
+
? wizardContent
|
|
225
|
+
: formContent;
|
|
226
|
+
const pageContentAttrs = isForm || isSettings || isWizard ? ' width="narrow"' : isDashboard ? ' density="spacious"' : '';
|
|
191
227
|
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
192
228
|
<MLayout fill-viewport>
|
|
193
229
|
<MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
|
|
194
|
-
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label:
|
|
230
|
+
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label: title }]" />
|
|
195
231
|
</MLayoutHeader>
|
|
196
232
|
<MLayoutContent>
|
|
197
233
|
<MPageContent${pageContentAttrs}>
|
|
@@ -236,19 +272,6 @@ ${content}
|
|
|
236
272
|
</template>
|
|
237
273
|
</MEmpty>
|
|
238
274
|
</main>
|
|
239
|
-
</MConfigProvider>`;
|
|
240
|
-
}
|
|
241
|
-
else if (isWizard) {
|
|
242
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
243
|
-
<main class="m-generated-page">
|
|
244
|
-
<MCard>
|
|
245
|
-
<MStepper v-model="activeStep" :items="[${zh ? "'基本信息', '确认'" : "'Details', 'Confirm'"}]" />
|
|
246
|
-
<MForm label-position="top" @submit.prevent="submit">
|
|
247
|
-
<MFormItem label="${zh ? '名称' : 'Name'}" name="name"><MInput v-model="model.name" fluid /></MFormItem>
|
|
248
|
-
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '下一步' : 'Next'}</MButton>
|
|
249
|
-
</MForm>
|
|
250
|
-
</MCard>
|
|
251
|
-
</main>
|
|
252
275
|
</MConfigProvider>`;
|
|
253
276
|
}
|
|
254
277
|
else {
|
|
@@ -697,24 +720,48 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
697
720
|
nextStep: (() => {
|
|
698
721
|
const goldenId = best.pattern.goldenPage?.split('/').pop()?.replace(/\.vue$/i, '') ||
|
|
699
722
|
listGoldenPages().find((item) => item.patternId === best.pattern.id)?.id ||
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
723
|
+
null;
|
|
724
|
+
if (locale === 'en-US') {
|
|
725
|
+
return goldenId
|
|
726
|
+
? `Call get_golden_page("${goldenId}") and mirror it. Look up unfamiliar APIs with get_component/get_example, then always run validate_usage and validate_page. includeScaffold returns the golden source when available — not a separate aesthetic template.`
|
|
727
|
+
: `No golden page for this pattern: use get_pattern + get_design_rules, look up APIs with get_component/get_example, then always run validate_usage and validate_page.`;
|
|
728
|
+
}
|
|
729
|
+
return goldenId
|
|
730
|
+
? `调用 get_golden_page("${goldenId}") 并镜像结构。不熟悉的 API 用 get_component/get_example 核对,然后必须跑 validate_usage 与 validate_page。includeScaffold 有黄金样例时返回样例源码,不是另一套审美模板。`
|
|
731
|
+
: `该模式暂无黄金样例:用 get_pattern + get_design_rules,API 用 get_component/get_example 核对,然后必须跑 validate_usage 与 validate_page。`;
|
|
704
732
|
})(),
|
|
705
733
|
};
|
|
706
734
|
if (args.includeScaffold) {
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
735
|
+
const goldenId = best.pattern.goldenPage?.split('/').pop()?.replace(/\.vue$/i, '') ||
|
|
736
|
+
listGoldenPages().find((item) => item.patternId === best.pattern.id)?.id ||
|
|
737
|
+
null;
|
|
738
|
+
const golden = goldenId ? readGoldenPageSource(goldenId) : null;
|
|
739
|
+
if (golden) {
|
|
740
|
+
result.scaffold = {
|
|
741
|
+
source: 'golden-page',
|
|
742
|
+
goldenPage: golden.record.id,
|
|
743
|
+
files: { component: golden.source },
|
|
744
|
+
warnings: [
|
|
745
|
+
locale === 'en-US'
|
|
746
|
+
? 'Scaffold is the golden page source. Remap domain copy/data only; never invent props. Then validate_usage + validate_page.'
|
|
747
|
+
: '脚手架即黄金样例源码。只替换域文案与数据,禁止臆造 prop。完成后必须 validate_usage + validate_page。',
|
|
748
|
+
],
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
const code = generatedPageCode(best.pattern.id, args.intent, locale);
|
|
753
|
+
const componentSource = `${code.script}\n\n${code.template}\n\n${code.style}`;
|
|
754
|
+
result.scaffold = {
|
|
755
|
+
source: 'generated-fallback',
|
|
756
|
+
vue: code,
|
|
757
|
+
files: { component: componentSource },
|
|
758
|
+
warnings: [
|
|
759
|
+
locale === 'en-US'
|
|
760
|
+
? 'No golden page for this pattern — structural fallback only. Prefer get_pattern + get_component. Must validate_usage before delivery.'
|
|
761
|
+
: '该模式暂无黄金样例,仅为结构占位。优先 get_pattern + get_component。交付前必须 validate_usage。',
|
|
762
|
+
],
|
|
763
|
+
};
|
|
764
|
+
}
|
|
718
765
|
}
|
|
719
766
|
return textResult(result);
|
|
720
767
|
}
|
|
@@ -734,8 +781,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
734
781
|
file: payload.record.file,
|
|
735
782
|
source: payload.source,
|
|
736
783
|
nextStep: locale === 'en-US'
|
|
737
|
-
? '
|
|
738
|
-
: '
|
|
784
|
+
? 'Mirror this structure and replace business data. Look up unfamiliar APIs with get_component/get_example, then always run validate_usage and validate_page. See get_design_rules for page standards.'
|
|
785
|
+
: '镜像此结构并替换业务数据。不熟悉的 API 用 get_component/get_example 核对,然后必须跑 validate_usage 与 validate_page。页面标准见 get_design_rules。',
|
|
739
786
|
});
|
|
740
787
|
}
|
|
741
788
|
function listGoldenPageCatalog(args = {}) {
|
|
@@ -769,8 +816,9 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
769
816
|
const ranked = pageSnippets
|
|
770
817
|
.map((snippet) => ({ snippet, score: scorePageSnippet(snippet, args.section) }))
|
|
771
818
|
.sort((a, b) => b.score - a.score || a.snippet.id.localeCompare(b.snippet.id));
|
|
772
|
-
const
|
|
773
|
-
|
|
819
|
+
const exact = findPageSnippet(args.section);
|
|
820
|
+
const match = exact || (ranked[0]?.score ? ranked[0].snippet : undefined);
|
|
821
|
+
if (!match || (!exact && (ranked[0]?.score ?? 0) === 0)) {
|
|
774
822
|
return textResult({
|
|
775
823
|
error: `Page snippet not found: ${args.section}`,
|
|
776
824
|
availableSnippets: pageSnippets.map((item) => item.id),
|
|
@@ -802,7 +850,7 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
802
850
|
template: match.template,
|
|
803
851
|
};
|
|
804
852
|
}
|
|
805
|
-
if (!
|
|
853
|
+
if (!exact && ranked.length > 1 && ranked[0]?.score) {
|
|
806
854
|
payload.matchedBy = 'query';
|
|
807
855
|
payload.alternatives = ranked
|
|
808
856
|
.slice(1, 4)
|
|
@@ -950,6 +998,61 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
950
998
|
});
|
|
951
999
|
}
|
|
952
1000
|
}
|
|
1001
|
+
if (/<MTable\b[^>]*(?::data|v-bind:data)\s*=/i.test(code) || /<MTable\b[^>]*\sdata\s*=/i.test(code)) {
|
|
1002
|
+
suggestions.push({
|
|
1003
|
+
standardId: 'feedback',
|
|
1004
|
+
type: 'table-data-prop',
|
|
1005
|
+
message: locale === 'en-US'
|
|
1006
|
+
? 'Contract: MTable row data uses the rows prop (not data). See golden list-page / get_component Table.'
|
|
1007
|
+
: '契约:MTable 行数据使用 rows,不要用 data。见黄金样例 list-page / get_component Table。',
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
if (/<MMessage\b[^>]*\bseverity\b/i.test(code)) {
|
|
1011
|
+
suggestions.push({
|
|
1012
|
+
standardId: 'feedback',
|
|
1013
|
+
type: 'mmessage-as-alert',
|
|
1014
|
+
message: locale === 'en-US'
|
|
1015
|
+
? 'Contract: <MMessage> is the message service host, not an inline alert. Use field errorMessage or a token-styled role="alert".'
|
|
1016
|
+
: '契约:<MMessage> 是 message 服务宿主,不是内嵌 Alert。表单常驻错误用字段 errorMessage 或 token 样式的 role="alert"。',
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
if (/toast\.(?:success|info|warn|warning|error)\s*\(\s*['"`][^'"`]+['"`]\s*\)/i.test(code)) {
|
|
1020
|
+
suggestions.push({
|
|
1021
|
+
standardId: 'feedback',
|
|
1022
|
+
type: 'toast-one-liner',
|
|
1023
|
+
message: locale === 'en-US'
|
|
1024
|
+
? 'Contract: one-line feedback should use message.*; toast is for summary + detail or async feel.'
|
|
1025
|
+
: '契约:单行操作回执用 message.*;toast 仅用于 summary + detail 或异步通知感。',
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
if (/#cell-status[\s\S]{0,500}<MTag\b/i.test(code) &&
|
|
1029
|
+
!/#cell-status[\s\S]{0,500}<MStatus\b/i.test(code)) {
|
|
1030
|
+
suggestions.push({
|
|
1031
|
+
standardId: 'feedback',
|
|
1032
|
+
type: 'status-cell-tag',
|
|
1033
|
+
message: locale === 'en-US'
|
|
1034
|
+
? 'Prefer MStatus for business status in #cell-status; use MTag for categories / closable chips (see list-status-dot / detail-page).'
|
|
1035
|
+
: '行内业务状态优先 MStatus(#cell-status);分类或可关闭标签再用 MTag(见 list-status-dot / detail-page)。',
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
if (/<MTabs\b[^>]*(?::items|v-bind:items)\s*=/i.test(code) || /<MTabs\b[^>]*\sitems\s*=/i.test(code)) {
|
|
1039
|
+
suggestions.push({
|
|
1040
|
+
standardId: 'feedback',
|
|
1041
|
+
type: 'tabs-items-prop',
|
|
1042
|
+
message: locale === 'en-US'
|
|
1043
|
+
? 'Contract: MTabs uses the tabs prop with v-model (not items / value). See settings-page golden.'
|
|
1044
|
+
: '契约:MTabs 使用 v-model + tabs(不是 items / value)。见黄金样例 settings-page。',
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
if (/<MStepper\b[^>]*(?::items|v-bind:items)\s*=/i.test(code) || /<MStepper\b[^>]*\sitems\s*=/i.test(code)) {
|
|
1048
|
+
suggestions.push({
|
|
1049
|
+
standardId: 'feedback',
|
|
1050
|
+
type: 'stepper-items-prop',
|
|
1051
|
+
message: locale === 'en-US'
|
|
1052
|
+
? 'Contract: MStepper uses the steps prop with v-model (not items). See wizard-form golden.'
|
|
1053
|
+
: '契约:MStepper 使用 v-model + steps(不是 items)。见黄金样例 wizard-form。',
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
953
1056
|
return textResult({
|
|
954
1057
|
ok: true,
|
|
955
1058
|
advisory: true,
|
|
@@ -994,7 +1097,7 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
994
1097
|
spacing: '--m-space-*',
|
|
995
1098
|
radius: '--m-radius-sm/md/lg',
|
|
996
1099
|
typography: '--m-font-size-xs/sm/md/lg',
|
|
997
|
-
motion: '--m-motion-fast/normal',
|
|
1100
|
+
motion: '--m-motion-fast/normal/enter/exit/distance/ease; intensity via useMotion (data-m-motion); enter/exit via motion.transitions / transition prop (fade, scale-fade, zoom, slide-*, dialog, drawer, …)',
|
|
998
1101
|
},
|
|
999
1102
|
composition: designRules.composition,
|
|
1000
1103
|
actions: {
|
|
@@ -1003,13 +1106,25 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1003
1106
|
destructive: { component: 'MButton', props: ['severity="danger"'], requiresConfirmation: true },
|
|
1004
1107
|
cancel: { component: 'MButton', props: ['severity="secondary"', 'text'] },
|
|
1005
1108
|
},
|
|
1006
|
-
status: {
|
|
1109
|
+
status: {
|
|
1110
|
+
preferred: 'MStatus',
|
|
1111
|
+
chip: 'MTag',
|
|
1112
|
+
badge: 'MBadge',
|
|
1113
|
+
entity: 'MChip',
|
|
1114
|
+
mapping: { active: 'success', pending: 'warn', disabled: 'secondary', error: 'danger' },
|
|
1115
|
+
note: 'Inline status uses MStatus; category or closable labels use MTag; counts use MBadge.',
|
|
1116
|
+
},
|
|
1007
1117
|
feedback: {
|
|
1008
1118
|
default: 'message',
|
|
1009
1119
|
message: { when: ['single-line action result', 'save/delete/create confirmations'] },
|
|
1010
1120
|
toast: { when: ['summary + detail', 'async or background notifications'] },
|
|
1011
|
-
|
|
1012
|
-
|
|
1121
|
+
empty: { component: 'MEmpty', when: ['no rows', 'no filter matches', 'first use'] },
|
|
1122
|
+
result: { component: 'MResult', when: ['terminal success/failure', '403 / 404 / 500'] },
|
|
1123
|
+
inlineMessage: {
|
|
1124
|
+
api: 'field errorMessage | token-styled role=alert',
|
|
1125
|
+
when: ['persistent form/auth errors; MMessage is the message host, not an inline alert'],
|
|
1126
|
+
},
|
|
1127
|
+
doc: 'design-kit/.agents/skills/morya-ui-pages/references/feedback.md',
|
|
1013
1128
|
},
|
|
1014
1129
|
global: [
|
|
1015
1130
|
'Prefer library components and --m-* tokens.',
|
|
@@ -1104,6 +1219,14 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1104
1219
|
install: 'pnpm add morya-ui',
|
|
1105
1220
|
peer: 'vue@^3.3.0',
|
|
1106
1221
|
styles: "import 'morya-ui/styles.css'",
|
|
1222
|
+
aiSetup: {
|
|
1223
|
+
command: 'npx @morya-ui/setup',
|
|
1224
|
+
skill: 'morya-ui-pages',
|
|
1225
|
+
mcp: 'npx -y @morya-ui/mcp',
|
|
1226
|
+
note: locale === 'en-US'
|
|
1227
|
+
? 'setup installs the library, copies the page skill and Cursor rules, and merges MCP. Table data uses the rows prop. MMessage is the message host, not an inline alert.'
|
|
1228
|
+
: 'setup 会安装组件库、复制页面 skill 与 Cursor 规则,并合并 MCP。表格数据用 rows。MMessage 是 message 宿主,不是内嵌 Alert。',
|
|
1229
|
+
},
|
|
1107
1230
|
guides: {
|
|
1108
1231
|
introduction: pickMarkdown(intro),
|
|
1109
1232
|
quickStart: pickMarkdown(quickStart),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morya-ui/mcp",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"description": "MCP server for morya-ui — component docs, examples, and usage guidance for AI coding agents.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/morya-space/morya-ui/tree/main/packages/ui-mcp#readme",
|