@morya-ui/mcp 0.3.1 → 0.3.3
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 +5 -3
- package/data/catalog.json +298 -132
- package/data/example-coverage.json +25 -15
- package/data/golden-pages/dashboard-page.vue +10 -8
- package/data/golden-pages/empty-state.vue +20 -51
- package/data/golden-pages/form-in-dialog.vue +3 -3
- package/data/golden-pages/list-page.vue +77 -12
- package/dist/__tests__/tools.test.js +18 -1
- package/dist/decisions.d.ts +14 -0
- package/dist/decisions.js +777 -41
- package/dist/page-snippets.js +127 -35
- package/dist/tools.js +46 -28
- package/package.json +4 -2
package/dist/page-snippets.js
CHANGED
|
@@ -6,7 +6,7 @@ export const pageSnippets = [
|
|
|
6
6
|
description: '在 MPageContent 内追加或替换筛选区,使用 MPageFilters + MSpace 包裹控件。',
|
|
7
7
|
descriptionEn: 'Add or replace a filter region inside MPageContent using MPageFilters and MSpace.',
|
|
8
8
|
pageTypes: ['list'],
|
|
9
|
-
keywords: ['筛选', '搜索', '查询', 'filter', 'search', 'keyword', 'reset'],
|
|
9
|
+
keywords: ['筛选', '搜索', '查询', 'filters', 'filter', 'search', 'keyword', 'reset'],
|
|
10
10
|
imports: ['MPageFilters', 'MSpace', 'MInput', 'MSelect', 'MButton'],
|
|
11
11
|
scriptSetup: `const keyword = ref('')
|
|
12
12
|
const status = ref<string | undefined>()
|
|
@@ -15,7 +15,7 @@ const statusOptions = [
|
|
|
15
15
|
{ label: '启用', value: 'active' },
|
|
16
16
|
{ label: '停用', value: 'inactive' },
|
|
17
17
|
]`,
|
|
18
|
-
template: `<MPageFilters aria-label="筛选">
|
|
18
|
+
template: `<MPageFilters aria-label="筛选" variant="filled">
|
|
19
19
|
<MSpace wrap>
|
|
20
20
|
<MInput v-model="keyword" placeholder="搜索名称" clearable style="width: 14rem" />
|
|
21
21
|
<MSelect
|
|
@@ -25,33 +25,119 @@ const statusOptions = [
|
|
|
25
25
|
clearable
|
|
26
26
|
style="width: 10rem"
|
|
27
27
|
/>
|
|
28
|
-
<MButton severity="
|
|
29
|
-
<MButton severity="secondary">重置</MButton>
|
|
28
|
+
<MButton severity="secondary">查询</MButton>
|
|
29
|
+
<MButton severity="secondary" text>重置</MButton>
|
|
30
30
|
</MSpace>
|
|
31
31
|
</MPageFilters>`,
|
|
32
|
-
rules: ['放在
|
|
33
|
-
rulesEn: ['Place
|
|
32
|
+
rules: ['放在 MPageHeader 之后、表格之前', 'viewport 内仅一个 primary(通常在 Header)', '不要外包 MCard'],
|
|
33
|
+
rulesEn: ['Place after MPageHeader and before the table', 'Keep one primary in the viewport (usually in Header)', 'Do not wrap with MCard'],
|
|
34
34
|
avoid: ['不要手写 .page-filters 类', '不要用 MCard 包筛选区'],
|
|
35
35
|
avoidEn: ['Do not hand-write .page-filters classes', 'Do not wrap filters in MCard'],
|
|
36
36
|
},
|
|
37
|
+
{
|
|
38
|
+
id: 'list-filters-collapsible',
|
|
39
|
+
title: '列表页折叠筛选',
|
|
40
|
+
titleEn: 'Collapsible list filters',
|
|
41
|
+
description: 'MPageFilters collapsible + #advanced 隐藏次要字段。',
|
|
42
|
+
descriptionEn: 'Hide secondary fields with collapsible MPageFilters and an #advanced slot.',
|
|
43
|
+
pageTypes: ['list'],
|
|
44
|
+
keywords: ['折叠', '高级筛选', 'collapse', 'advanced', 'expand', 'filter'],
|
|
45
|
+
imports: ['MPageFilters', 'MSpace', 'MInput', 'MSelect', 'MButton'],
|
|
46
|
+
scriptSetup: `const filtersExpanded = ref(false)
|
|
47
|
+
const keyword = ref('')
|
|
48
|
+
const department = ref<string | null>(null)`,
|
|
49
|
+
template: `<MPageFilters
|
|
50
|
+
v-model:expanded="filtersExpanded"
|
|
51
|
+
aria-label="筛选"
|
|
52
|
+
variant="filled"
|
|
53
|
+
collapsible
|
|
54
|
+
>
|
|
55
|
+
<MSpace wrap>
|
|
56
|
+
<MInput v-model="keyword" placeholder="搜索名称" clearable style="width: 14rem" />
|
|
57
|
+
<MButton severity="secondary">查询</MButton>
|
|
58
|
+
<MButton severity="secondary" text>重置</MButton>
|
|
59
|
+
</MSpace>
|
|
60
|
+
<template #advanced>
|
|
61
|
+
<MSpace wrap>
|
|
62
|
+
<MSelect
|
|
63
|
+
v-model="department"
|
|
64
|
+
:options="[{ label: '研发', value: '研发' }, { label: '运营', value: '运营' }]"
|
|
65
|
+
placeholder="部门"
|
|
66
|
+
clearable
|
|
67
|
+
style="width: 10rem"
|
|
68
|
+
/>
|
|
69
|
+
</MSpace>
|
|
70
|
+
</template>
|
|
71
|
+
</MPageFilters>`,
|
|
72
|
+
rules: ['常用条件放 default,次要条件放 #advanced', '查询/重置保持 secondary'],
|
|
73
|
+
rulesEn: ['Keep primary filters in default; secondary filters in #advanced', 'Query/reset stay secondary'],
|
|
74
|
+
avoid: ['不要用 MCard 包整个筛选区'],
|
|
75
|
+
avoidEn: ['Do not wrap the whole filter bar in MCard'],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'list-filter-chips',
|
|
79
|
+
title: '列表页已选筛选',
|
|
80
|
+
titleEn: 'Active filter chips',
|
|
81
|
+
description: 'MPageFilterChips + MTag closable 展示并清除已选条件。',
|
|
82
|
+
descriptionEn: 'Show and clear active filters with MPageFilterChips and closable MTag.',
|
|
83
|
+
pageTypes: ['list'],
|
|
84
|
+
keywords: ['已选', 'chip', 'tag', 'active', 'clear', '筛选'],
|
|
85
|
+
imports: ['MPageFilterChips', 'MTag'],
|
|
86
|
+
template: `<MPageFilterChips label="已选" aria-label="已选筛选">
|
|
87
|
+
<MTag
|
|
88
|
+
v-for="item in activeFilters"
|
|
89
|
+
:key="item.key"
|
|
90
|
+
:value="item.label"
|
|
91
|
+
size="small"
|
|
92
|
+
bordered
|
|
93
|
+
closable
|
|
94
|
+
@close="clearFilter(item.key)"
|
|
95
|
+
/>
|
|
96
|
+
</MPageFilterChips>`,
|
|
97
|
+
rules: ['放在 MPageFilters 之后、表格之前', '用业务 computed 生成 activeFilters'],
|
|
98
|
+
rulesEn: ['Place after MPageFilters and before the table', 'Derive activeFilters from filter state'],
|
|
99
|
+
avoid: ['不要手写 pill 样式或 dashed 壳'],
|
|
100
|
+
avoidEn: ['Do not hand-write pill or dashed shells'],
|
|
101
|
+
},
|
|
37
102
|
{
|
|
38
103
|
id: 'list-toolbar',
|
|
39
|
-
title: '
|
|
40
|
-
titleEn: 'List page
|
|
41
|
-
description: '
|
|
42
|
-
descriptionEn: 'Page
|
|
104
|
+
title: '列表页页头',
|
|
105
|
+
titleEn: 'List page header',
|
|
106
|
+
description: '页面身份 + 唯一 primary(新建),放在 MPageContent 顶部。',
|
|
107
|
+
descriptionEn: 'Page identity and the single primary action at the top of MPageContent.',
|
|
43
108
|
pageTypes: ['list'],
|
|
44
|
-
keywords: ['
|
|
45
|
-
imports: ['
|
|
46
|
-
template: `<
|
|
109
|
+
keywords: ['页头', '标题', '新建', 'header', 'title', 'create', 'actions'],
|
|
110
|
+
imports: ['MPageHeader', 'MButton'],
|
|
111
|
+
template: `<MPageHeader title="用户管理" description="维护账号、角色与权限。">
|
|
47
112
|
<template #actions>
|
|
48
113
|
<MButton severity="primary">新建用户</MButton>
|
|
49
114
|
</template>
|
|
115
|
+
</MPageHeader>`,
|
|
116
|
+
rules: ['页级标题用 MPageHeader,不要用 MPageToolbar 当第二页头', '主操作放 #actions'],
|
|
117
|
+
rulesEn: ['Use MPageHeader for page identity; do not use MPageToolbar as a second page title', 'Put primary actions in #actions'],
|
|
118
|
+
avoid: ['不要在 Toolbar 上写页面 H1 标题'],
|
|
119
|
+
avoidEn: ['Do not put the page H1 on MPageToolbar'],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: 'list-batch-toolbar',
|
|
123
|
+
title: '列表页批量操作条',
|
|
124
|
+
titleEn: 'List batch action row',
|
|
125
|
+
description: '表格多选时的批量操作,放在筛选区之后(可选)。',
|
|
126
|
+
descriptionEn: 'Optional batch actions after filters when rows are selectable.',
|
|
127
|
+
pageTypes: ['list'],
|
|
128
|
+
keywords: ['批量', '已选', 'toolbar', 'batch', 'export', 'delete'],
|
|
129
|
+
imports: ['MPageToolbar', 'MButton'],
|
|
130
|
+
template: `<MPageToolbar>
|
|
131
|
+
<span style="color:var(--m-color-text-muted);font-size:var(--m-font-size-sm)">已选 0 项</span>
|
|
132
|
+
<template #actions>
|
|
133
|
+
<MButton severity="secondary" text>导出</MButton>
|
|
134
|
+
<MButton severity="danger" text>删除</MButton>
|
|
135
|
+
</template>
|
|
50
136
|
</MPageToolbar>`,
|
|
51
|
-
rules: ['
|
|
52
|
-
rulesEn: ['
|
|
53
|
-
avoid: ['
|
|
54
|
-
avoidEn: ['Do not
|
|
137
|
+
rules: ['左侧用 default 插槽展示已选数量', '批量操作用 text/outlined,danger 仅 destructive'],
|
|
138
|
+
rulesEn: ['Use the default slot for selection count', 'Batch actions use text/outlined; danger only for destructive ops'],
|
|
139
|
+
avoid: ['不要用 Toolbar title 充当页面标题'],
|
|
140
|
+
avoidEn: ['Do not use Toolbar title as the page heading'],
|
|
55
141
|
},
|
|
56
142
|
{
|
|
57
143
|
id: 'list-table',
|
|
@@ -271,8 +357,8 @@ const submitting = ref(false)`,
|
|
|
271
357
|
keywords: ['kpi', '指标', 'stat', 'grid', 'metrics'],
|
|
272
358
|
imports: ['MGrid', 'MGridItem', 'MPageStat'],
|
|
273
359
|
scriptSetup: `const metrics = ref([
|
|
274
|
-
{ label: '总用户', value: '12,480', trend: '+8.2%', icon: 'users' },
|
|
275
|
-
{ label: '今日活跃', value: '1,926', trend: '+3.1%', icon: 'activity' },
|
|
360
|
+
{ label: '总用户', value: '12,480', trend: '+8.2%', trendDirection: 'up' as const, trendLabel: '较上月', icon: 'users' },
|
|
361
|
+
{ label: '今日活跃', value: '1,926', trend: '+3.1%', trendDirection: 'up' as const, trendLabel: '较昨日', icon: 'activity' },
|
|
276
362
|
])`,
|
|
277
363
|
template: `<MGrid :cols="4" :x-gap="16" :y-gap="16" responsive="screen">
|
|
278
364
|
<MGridItem v-for="metric in metrics" :key="metric.label" :span="1">
|
|
@@ -280,7 +366,9 @@ const submitting = ref(false)`,
|
|
|
280
366
|
:label="metric.label"
|
|
281
367
|
:value="metric.value"
|
|
282
368
|
:trend="metric.trend"
|
|
283
|
-
|
|
369
|
+
:trend-direction="metric.trendDirection"
|
|
370
|
+
:trend-label="metric.trendLabel"
|
|
371
|
+
:icon="metric.icon"
|
|
284
372
|
/>
|
|
285
373
|
</MGridItem>
|
|
286
374
|
</MGrid>`,
|
|
@@ -293,16 +381,17 @@ const submitting = ref(false)`,
|
|
|
293
381
|
id: 'dashboard-chart-card',
|
|
294
382
|
title: '仪表盘图表卡片',
|
|
295
383
|
titleEn: 'Dashboard chart card',
|
|
296
|
-
description: 'MCard
|
|
297
|
-
descriptionEn: 'MCard
|
|
384
|
+
description: 'MCard shadow="always" + MEmpty 作为图表占位。',
|
|
385
|
+
descriptionEn: 'MCard with shadow="always" and MEmpty for chart pending state.',
|
|
298
386
|
pageTypes: ['dashboard'],
|
|
299
387
|
keywords: ['chart', '图表', 'placeholder', 'card', 'trend'],
|
|
300
|
-
imports: ['MCard', '
|
|
301
|
-
template: `<MCard title="趋势概览">
|
|
388
|
+
imports: ['MCard', 'MEmpty', 'MSkeleton'],
|
|
389
|
+
template: `<MCard title="趋势概览" shadow="always">
|
|
302
390
|
<MSkeleton v-if="loading" height="8rem" />
|
|
303
|
-
<
|
|
391
|
+
<MEmpty
|
|
304
392
|
v-else
|
|
305
393
|
aria-label="图表占位"
|
|
394
|
+
title="暂无图表数据"
|
|
306
395
|
description="图表区域(接入 ECharts / 业务组件)"
|
|
307
396
|
/>
|
|
308
397
|
</MCard>`,
|
|
@@ -380,19 +469,22 @@ const recentRows = ref<Record<string, unknown>[]>([])`,
|
|
|
380
469
|
id: 'detail-toolbar',
|
|
381
470
|
title: '详情页顶栏',
|
|
382
471
|
titleEn: 'Detail page header actions',
|
|
383
|
-
description: '
|
|
384
|
-
descriptionEn: 'Detail page title and edit
|
|
472
|
+
description: '详情页标题、状态与编辑操作。',
|
|
473
|
+
descriptionEn: 'Detail page title, status, and edit actions.',
|
|
385
474
|
pageTypes: ['detail'],
|
|
386
|
-
keywords: ['detail', '详情', 'edit', '
|
|
387
|
-
imports: ['
|
|
388
|
-
template: `<
|
|
475
|
+
keywords: ['detail', '详情', 'edit', 'header'],
|
|
476
|
+
imports: ['MPageHeader', 'MButton', 'MStatus', 'MSpace'],
|
|
477
|
+
template: `<MPageHeader title="示例资源" description="查看摘要与属性。">
|
|
389
478
|
<template #actions>
|
|
390
|
-
<
|
|
479
|
+
<MSpace>
|
|
480
|
+
<MStatus label="正常" severity="success" />
|
|
481
|
+
<MButton severity="primary">编辑</MButton>
|
|
482
|
+
<MButton severity="danger" text>删除</MButton>
|
|
483
|
+
</MSpace>
|
|
391
484
|
</template>
|
|
392
|
-
</
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
rulesEn: ['Keep status Tag near the header area', 'Edit is primary; delete stays low emphasis'],
|
|
485
|
+
</MPageHeader>`,
|
|
486
|
+
rules: ['状态用 MStatus 放在 actions 区', '编辑为 primary,删除用 danger text'],
|
|
487
|
+
rulesEn: ['Use MStatus in the actions area', 'Edit is primary; delete uses danger text'],
|
|
396
488
|
avoid: ['不要把操作散落到多个无关区域'],
|
|
397
489
|
avoidEn: ['Do not scatter actions across unrelated areas'],
|
|
398
490
|
},
|
package/dist/tools.js
CHANGED
|
@@ -47,6 +47,25 @@ function pickLocale(record, locale) {
|
|
|
47
47
|
function vueName(name) {
|
|
48
48
|
return `M${name}`;
|
|
49
49
|
}
|
|
50
|
+
function mapDecisionOption(option, locale) {
|
|
51
|
+
const zh = locale !== 'en-US';
|
|
52
|
+
const recipe = {
|
|
53
|
+
props: zh ? option.recipe.props : option.recipe.propsEn,
|
|
54
|
+
...(option.recipe.slots?.length
|
|
55
|
+
? { slots: zh ? option.recipe.slots : option.recipe.slotsEn }
|
|
56
|
+
: {}),
|
|
57
|
+
...(option.recipe.events?.length
|
|
58
|
+
? { events: zh ? option.recipe.events : option.recipe.eventsEn }
|
|
59
|
+
: {}),
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
component: option.component,
|
|
63
|
+
when: zh ? option.when : option.whenEn,
|
|
64
|
+
avoidWhen: zh ? option.avoidWhen : option.avoidWhenEn,
|
|
65
|
+
recipe,
|
|
66
|
+
antiPatterns: zh ? option.antiPatterns : option.antiPatternsEn,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
50
69
|
function generatedPageCode(patternId, intent, locale) {
|
|
51
70
|
const zh = locale === 'zh-CN';
|
|
52
71
|
const isList = patternId === 'admin-list';
|
|
@@ -67,9 +86,9 @@ function generatedPageCode(patternId, intent, locale) {
|
|
|
67
86
|
: '';
|
|
68
87
|
const listImports = isList ? ', MEmpty, MSelect, MSpace, MTable' : '';
|
|
69
88
|
const formImports = isForm || isAuth || isWizard ? ', MForm, MFormItem, MSelect' : '';
|
|
70
|
-
const dashboardImports = isDashboard ? ', MCard, MGrid, MGridItem,
|
|
89
|
+
const dashboardImports = isDashboard ? ', MCard, MGrid, MGridItem, MEmpty, MPageStat, MSkeleton, MTable' : '';
|
|
71
90
|
const detailImports = isDetail ? ', MSpace' : '';
|
|
72
|
-
const emptyImports = isEmpty ? ', MEmpty,
|
|
91
|
+
const emptyImports = isEmpty ? ', MEmpty, MPageContent, MPageHeader' : '';
|
|
73
92
|
const wizardImports = isWizard ? ', MStepper, MSpace' : '';
|
|
74
93
|
const settingsImports = isSettings ? ', MTabs' : '';
|
|
75
94
|
const statusImports = isList || isDetail || isDashboard ? ', MStatus' : '';
|
|
@@ -104,18 +123,18 @@ async function submit() {
|
|
|
104
123
|
}
|
|
105
124
|
}
|
|
106
125
|
</script>`;
|
|
107
|
-
const listContent = ` <
|
|
126
|
+
const listContent = ` <MPageHeader :title="title">
|
|
127
|
+
<template #actions>
|
|
128
|
+
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
129
|
+
</template>
|
|
130
|
+
</MPageHeader>
|
|
131
|
+
<MPageFilters variant="filled" :aria-label="${zh ? '筛选' : 'Filters'}">
|
|
108
132
|
<MSpace wrap>
|
|
109
133
|
<MInput v-model="keyword" placeholder="${zh ? '搜索关键词' : 'Search keyword'}" clearable style="width: 14rem" />
|
|
110
|
-
<MButton severity="
|
|
134
|
+
<MButton severity="secondary">${zh ? '查询' : 'Search'}</MButton>
|
|
111
135
|
<MButton severity="secondary">${zh ? '重置' : 'Reset'}</MButton>
|
|
112
136
|
</MSpace>
|
|
113
137
|
</MPageFilters>
|
|
114
|
-
<MPageToolbar :title="title">
|
|
115
|
-
<template #actions>
|
|
116
|
-
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
117
|
-
</template>
|
|
118
|
-
</MPageToolbar>
|
|
119
138
|
<MTable :columns="columns" :rows="rows" :loading="loading" paginator :rows-per-page="10" striped bordered row-key="id">
|
|
120
139
|
<template #cell-status="{ value }">
|
|
121
140
|
<MStatus :label="String(value ?? '')" :severity="value === 'active' ? 'success' : 'secondary'" />
|
|
@@ -149,9 +168,14 @@ async function submit() {
|
|
|
149
168
|
<MPageStat :label="metric.label" :value="metric.value" icon="activity" />
|
|
150
169
|
</MGridItem>
|
|
151
170
|
</MGrid>
|
|
152
|
-
<MCard :title="${zh ? '趋势概览' : 'Trend overview'}">
|
|
171
|
+
<MCard shadow="always" :title="${zh ? '趋势概览' : 'Trend overview'}">
|
|
153
172
|
<MSkeleton v-if="loading" height="8rem" />
|
|
154
|
-
<
|
|
173
|
+
<MEmpty
|
|
174
|
+
v-else
|
|
175
|
+
:title="${zh ? '暂无图表数据' : 'No chart data yet'}"
|
|
176
|
+
:description="${zh ? '接入图表或业务组件。' : 'Connect charts or business widgets here.'}"
|
|
177
|
+
aria-label="${zh ? '图表占位' : 'Chart placeholder'}"
|
|
178
|
+
/>
|
|
155
179
|
</MCard>`;
|
|
156
180
|
const detailContent = ` <MPageHeader :title="title" :description="${zh ? '查看资源摘要与属性。' : 'Review summary and properties.'}">
|
|
157
181
|
<template #actions>
|
|
@@ -257,11 +281,12 @@ ${content}
|
|
|
257
281
|
else if (isEmpty) {
|
|
258
282
|
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
259
283
|
<main class="m-generated-page">
|
|
260
|
-
<
|
|
261
|
-
<
|
|
262
|
-
<
|
|
263
|
-
|
|
264
|
-
|
|
284
|
+
<MPageContent>
|
|
285
|
+
<MPageHeader :title="title">
|
|
286
|
+
<template #actions>
|
|
287
|
+
<MButton severity="primary" @click="submit">${zh ? '新建' : 'Create'}</MButton>
|
|
288
|
+
</template>
|
|
289
|
+
</MPageHeader>
|
|
265
290
|
<MEmpty
|
|
266
291
|
:title="${zh ? '暂无内容' : 'Nothing here yet'}"
|
|
267
292
|
:description="${zh ? '创建第一条记录开始使用。' : 'Create your first record to get started.'}"
|
|
@@ -271,6 +296,7 @@ ${content}
|
|
|
271
296
|
<MButton severity="primary" @click="submit">${zh ? '创建' : 'Create'}</MButton>
|
|
272
297
|
</template>
|
|
273
298
|
</MEmpty>
|
|
299
|
+
</MPageContent>
|
|
274
300
|
</main>
|
|
275
301
|
</MConfigProvider>`;
|
|
276
302
|
}
|
|
@@ -1163,11 +1189,7 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1163
1189
|
title: locale === 'en-US' ? decision.titleEn : decision.title,
|
|
1164
1190
|
question: locale === 'en-US' ? decision.questionEn : decision.question,
|
|
1165
1191
|
keywords: decision.keywords,
|
|
1166
|
-
options: decision.options.map((option) => (
|
|
1167
|
-
component: option.component,
|
|
1168
|
-
when: locale === 'en-US' ? option.whenEn : option.when,
|
|
1169
|
-
avoidWhen: locale === 'en-US' ? option.avoidWhenEn : option.avoidWhen,
|
|
1170
|
-
})),
|
|
1192
|
+
options: decision.options.map((option) => mapDecisionOption(option, locale)),
|
|
1171
1193
|
});
|
|
1172
1194
|
}
|
|
1173
1195
|
if (!args.query) {
|
|
@@ -1187,14 +1209,10 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1187
1209
|
decision: matched.id,
|
|
1188
1210
|
title: locale === 'en-US' ? matched.titleEn : matched.title,
|
|
1189
1211
|
question: locale === 'en-US' ? matched.questionEn : matched.question,
|
|
1190
|
-
recommendations: matched.options.map((option) => (
|
|
1191
|
-
component: option.component,
|
|
1192
|
-
when: locale === 'en-US' ? option.whenEn : option.when,
|
|
1193
|
-
avoidWhen: locale === 'en-US' ? option.avoidWhenEn : option.avoidWhen,
|
|
1194
|
-
})),
|
|
1212
|
+
recommendations: matched.options.map((option) => mapDecisionOption(option, locale)),
|
|
1195
1213
|
nextStep: locale === 'en-US'
|
|
1196
|
-
? '
|
|
1197
|
-
: '
|
|
1214
|
+
? 'Apply the recipe props/slots/events, then use get_component and get_example before implementing. Run validate_usage before delivery.'
|
|
1215
|
+
: '先按 recipe 的 props/slots/events 落地,再用 get_component / get_example 核对 API;交付前跑 validate_usage。',
|
|
1198
1216
|
});
|
|
1199
1217
|
}
|
|
1200
1218
|
function getSetup(args) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morya-ui/mcp",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.3",
|
|
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",
|
|
@@ -39,11 +39,13 @@
|
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"generate": "node ./scripts/generate-catalog.mjs",
|
|
42
|
+
"generate:recipes": "node --experimental-strip-types ./scripts/generate-decision-recipes.mjs",
|
|
43
|
+
"check-recipes": "node --experimental-strip-types ./scripts/generate-decision-recipes.mjs --check",
|
|
42
44
|
"check-catalog": "node ./scripts/generate-catalog.mjs --check",
|
|
43
45
|
"validate-catalog": "node ./scripts/validate-catalog.mjs",
|
|
44
46
|
"audit-example-coverage": "node ./scripts/audit-example-coverage.mjs",
|
|
45
47
|
"write-example-coverage": "node ./scripts/audit-example-coverage.mjs --write",
|
|
46
|
-
"build": "pnpm run generate && tsc -p tsconfig.json",
|
|
48
|
+
"build": "pnpm run generate && tsc -p tsconfig.json && pnpm run generate:recipes",
|
|
47
49
|
"start": "node ./dist/index.js",
|
|
48
50
|
"test": "vitest run --config ../../vitest.config.ts src/__tests__",
|
|
49
51
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|