@loom-framework/core 0.1.0-alpha.8 → 0.1.0-alpha.80
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/dist/adapter-base.d.ts +29 -0
- package/dist/adapter-base.d.ts.map +1 -0
- package/dist/adapter-base.js +62 -0
- package/dist/adapter-base.js.map +1 -0
- package/dist/adapter-factory.d.ts +8 -0
- package/dist/adapter-factory.d.ts.map +1 -0
- package/dist/adapter-factory.js +25 -0
- package/dist/adapter-factory.js.map +1 -0
- package/dist/adapter-filesystem.d.ts +6 -11
- package/dist/adapter-filesystem.d.ts.map +1 -1
- package/dist/adapter-filesystem.js +56 -41
- package/dist/adapter-filesystem.js.map +1 -1
- package/dist/adapter-sqlite.d.ts +6 -23
- package/dist/adapter-sqlite.d.ts.map +1 -1
- package/dist/adapter-sqlite.js +65 -50
- package/dist/adapter-sqlite.js.map +1 -1
- package/dist/backend/ai/button-resolver.d.ts +18 -0
- package/dist/backend/ai/button-resolver.d.ts.map +1 -0
- package/dist/backend/ai/button-resolver.js +58 -0
- package/dist/backend/ai/button-resolver.js.map +1 -0
- package/dist/backend/ai/engine.d.ts +52 -0
- package/dist/backend/ai/engine.d.ts.map +1 -0
- package/dist/backend/ai/engine.js +186 -0
- package/dist/backend/ai/engine.js.map +1 -0
- package/dist/backend/ai/index.d.ts +11 -0
- package/dist/backend/ai/index.d.ts.map +1 -0
- package/dist/backend/ai/index.js +8 -0
- package/dist/backend/ai/index.js.map +1 -0
- package/dist/backend/ai/output-parser.d.ts +29 -0
- package/dist/backend/ai/output-parser.d.ts.map +1 -0
- package/dist/backend/ai/output-parser.js +247 -0
- package/dist/backend/ai/output-parser.js.map +1 -0
- package/dist/backend/ai/session-manager.d.ts +103 -0
- package/dist/backend/ai/session-manager.d.ts.map +1 -0
- package/dist/backend/ai/session-manager.js +298 -0
- package/dist/backend/ai/session-manager.js.map +1 -0
- package/dist/backend/index.d.ts +61 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +161 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/observe/index.d.ts +6 -0
- package/dist/backend/observe/index.d.ts.map +1 -0
- package/dist/backend/observe/index.js +5 -0
- package/dist/backend/observe/index.js.map +1 -0
- package/dist/backend/observe/logger.d.ts +28 -0
- package/dist/backend/observe/logger.d.ts.map +1 -0
- package/dist/backend/observe/logger.js +80 -0
- package/dist/backend/observe/logger.js.map +1 -0
- package/dist/backend/observe/types.d.ts +26 -0
- package/dist/backend/observe/types.d.ts.map +1 -0
- package/dist/backend/observe/types.js +7 -0
- package/dist/backend/observe/types.js.map +1 -0
- package/dist/backend/routes/chat.d.ts +31 -0
- package/dist/backend/routes/chat.d.ts.map +1 -0
- package/dist/backend/routes/chat.js +426 -0
- package/dist/backend/routes/chat.js.map +1 -0
- package/dist/backend/routes/data.d.ts +13 -0
- package/dist/backend/routes/data.d.ts.map +1 -0
- package/dist/backend/routes/data.js +134 -0
- package/dist/backend/routes/data.js.map +1 -0
- package/dist/backend/routes/health.d.ts +7 -0
- package/dist/backend/routes/health.d.ts.map +1 -0
- package/dist/backend/routes/health.js +15 -0
- package/dist/backend/routes/health.js.map +1 -0
- package/dist/backend/routes/index.d.ts +11 -0
- package/dist/backend/routes/index.d.ts.map +1 -0
- package/dist/backend/routes/index.js +9 -0
- package/dist/backend/routes/index.js.map +1 -0
- package/dist/backend/routes/skills.d.ts +16 -0
- package/dist/backend/routes/skills.d.ts.map +1 -0
- package/dist/backend/routes/skills.js +590 -0
- package/dist/backend/routes/skills.js.map +1 -0
- package/dist/backend/routes/upload.d.ts +24 -0
- package/dist/backend/routes/upload.d.ts.map +1 -0
- package/dist/backend/routes/upload.js +67 -0
- package/dist/backend/routes/upload.js.map +1 -0
- package/dist/bin.d.ts +8 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +12 -0
- package/dist/bin.js.map +1 -0
- package/dist/capability-generator.d.ts +21 -6
- package/dist/capability-generator.d.ts.map +1 -1
- package/dist/capability-generator.js +88 -261
- package/dist/capability-generator.js.map +1 -1
- package/dist/cli/commands/build.d.ts +11 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +170 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/data.d.ts +12 -0
- package/dist/cli/commands/data.d.ts.map +1 -0
- package/dist/cli/commands/data.js +158 -0
- package/dist/cli/commands/data.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +9 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +114 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/generate-capabilities.d.ts +8 -0
- package/dist/cli/commands/generate-capabilities.d.ts.map +1 -0
- package/dist/cli/commands/generate-capabilities.js +40 -0
- package/dist/cli/commands/generate-capabilities.js.map +1 -0
- package/dist/cli/commands/generate-cli-command.d.ts +8 -0
- package/dist/cli/commands/generate-cli-command.d.ts.map +1 -0
- package/dist/cli/commands/generate-cli-command.js +64 -0
- package/dist/cli/commands/generate-cli-command.js.map +1 -0
- package/dist/cli/commands/generate-page.d.ts +9 -0
- package/dist/cli/commands/generate-page.d.ts.map +1 -0
- package/dist/cli/commands/generate-page.js +641 -0
- package/dist/cli/commands/generate-page.js.map +1 -0
- package/dist/cli/commands/generate-skill.d.ts +8 -0
- package/dist/cli/commands/generate-skill.d.ts.map +1 -0
- package/dist/cli/commands/generate-skill.js +75 -0
- package/dist/cli/commands/generate-skill.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +6 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +17 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +8 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +539 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/observe.d.ts +9 -0
- package/dist/cli/commands/observe.d.ts.map +1 -0
- package/dist/cli/commands/observe.js +142 -0
- package/dist/cli/commands/observe.js.map +1 -0
- package/dist/cli/commands/skill.d.ts +9 -0
- package/dist/cli/commands/skill.d.ts.map +1 -0
- package/dist/cli/commands/skill.js +186 -0
- package/dist/cli/commands/skill.js.map +1 -0
- package/dist/cli/helpers/duration.d.ts +5 -0
- package/dist/cli/helpers/duration.d.ts.map +1 -0
- package/dist/cli/helpers/duration.js +19 -0
- package/dist/cli/helpers/duration.js.map +1 -0
- package/dist/cli/helpers/field-template.d.ts +10 -0
- package/dist/cli/helpers/field-template.d.ts.map +1 -0
- package/dist/cli/helpers/field-template.js +100 -0
- package/dist/cli/helpers/field-template.js.map +1 -0
- package/dist/cli/helpers/naming.d.ts +12 -0
- package/dist/cli/helpers/naming.d.ts.map +1 -0
- package/dist/cli/helpers/naming.js +25 -0
- package/dist/cli/helpers/naming.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +33 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils.d.ts +10 -0
- package/dist/cli/utils.d.ts.map +1 -0
- package/dist/cli/utils.js +31 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/config.d.ts +8 -40
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -8
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/server-bin.d.ts +12 -0
- package/dist/server-bin.d.ts.map +1 -0
- package/dist/server-bin.js +75 -0
- package/dist/server-bin.js.map +1 -0
- package/dist/types.d.ts +33 -20
- package/dist/types.d.ts.map +1 -1
- package/package.json +25 -10
- package/templates/app-skill/SKILL.md +27 -0
- package/templates/app-skill/references/data-semantics.md +44 -0
- package/templates/app-skill/references/models.md +31 -0
- package/templates/loom-skill/SKILL.md +140 -0
- package/templates/loom-skill/references/README.md +128 -0
- package/templates/loom-skill/references/data-model.md +78 -0
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* loom generate page <name>
|
|
3
|
+
*
|
|
4
|
+
* With --model: generate capabilities → CRUD page → auto-wire App.tsx
|
|
5
|
+
* Without --model: generate minimal skeleton page
|
|
6
|
+
*/
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { promises as fs } from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { loadConfig, getModelSchema, generateCapabilities } from '../../index.js';
|
|
11
|
+
import { resolveProjectRoot } from '../utils.js';
|
|
12
|
+
import { toPascalCase } from '../helpers/naming.js';
|
|
13
|
+
import { fieldToFormItem } from '../helpers/field-template.js';
|
|
14
|
+
/** Semantic color mapping for common enum values */
|
|
15
|
+
const SEMANTIC_COLORS = {
|
|
16
|
+
'active': 'green', 'inactive': 'default', 'pending': 'orange',
|
|
17
|
+
'enabled': 'green', 'disabled': 'default',
|
|
18
|
+
'未掌握': 'red', '部分掌握': 'orange', '已掌握': 'green',
|
|
19
|
+
'仍需练习': 'orange',
|
|
20
|
+
'简单': 'green', '中等': 'blue', '困难': 'red',
|
|
21
|
+
'easy': 'green', 'medium': 'blue', 'hard': 'red',
|
|
22
|
+
'high': 'red', 'low': 'green',
|
|
23
|
+
'是': 'green', '否': 'red',
|
|
24
|
+
'yes': 'green', 'no': 'red',
|
|
25
|
+
};
|
|
26
|
+
const TAG_PALETTE = ['blue', 'green', 'orange', 'red', 'purple', 'cyan', 'magenta', 'volcano', 'gold', 'lime'];
|
|
27
|
+
/** Fallback labels for common field names without description */
|
|
28
|
+
const FALLBACK_LABELS = {
|
|
29
|
+
createdAt: '创建时间',
|
|
30
|
+
updatedAt: '更新时间',
|
|
31
|
+
};
|
|
32
|
+
/** Generate tagColors constant code for enum fields */
|
|
33
|
+
function generateTagColors(fields) {
|
|
34
|
+
const enumFields = fields.filter(f => f.enum && f.name !== 'id');
|
|
35
|
+
if (enumFields.length === 0)
|
|
36
|
+
return '';
|
|
37
|
+
const entries = enumFields.map(f => {
|
|
38
|
+
const mappings = f.enum.map((v, i) => {
|
|
39
|
+
const color = SEMANTIC_COLORS[v] || TAG_PALETTE[i % TAG_PALETTE.length];
|
|
40
|
+
return `'${v}': '${color}'`;
|
|
41
|
+
}).join(', ');
|
|
42
|
+
return ` ${f.name}: { ${mappings} }`;
|
|
43
|
+
}).join(',\n');
|
|
44
|
+
return `\nconst tagColors: Record<string, Record<string, string>> = {\n${entries}\n};\n`;
|
|
45
|
+
}
|
|
46
|
+
/** Check if a string field is likely a long-text field */
|
|
47
|
+
function isLongTextField(field) {
|
|
48
|
+
const name = field.name.toLowerCase();
|
|
49
|
+
return (field.type === 'string' &&
|
|
50
|
+
!field.enum &&
|
|
51
|
+
(name.includes('content') ||
|
|
52
|
+
name.includes('description') ||
|
|
53
|
+
name.includes('body') ||
|
|
54
|
+
name.includes('text') ||
|
|
55
|
+
name.includes('note') ||
|
|
56
|
+
name.includes('remark') ||
|
|
57
|
+
name.includes('bio') ||
|
|
58
|
+
name.includes('summary') ||
|
|
59
|
+
name.includes('analysis')));
|
|
60
|
+
}
|
|
61
|
+
/** Get column width based on field type */
|
|
62
|
+
function getColumnWidth(field) {
|
|
63
|
+
if (isLongTextField(field))
|
|
64
|
+
return 300;
|
|
65
|
+
if (field.enum)
|
|
66
|
+
return 110;
|
|
67
|
+
if (field.type === 'boolean')
|
|
68
|
+
return 90;
|
|
69
|
+
if (field.type === 'number')
|
|
70
|
+
return 100;
|
|
71
|
+
if (field.type === 'date')
|
|
72
|
+
return 130;
|
|
73
|
+
if (field.type === 'string[]')
|
|
74
|
+
return 180;
|
|
75
|
+
if (field.type === 'number[]')
|
|
76
|
+
return 140;
|
|
77
|
+
if (field.type === 'json')
|
|
78
|
+
return 200;
|
|
79
|
+
return 160; // default string
|
|
80
|
+
}
|
|
81
|
+
/** Generate table columns from model fields — server-side filter & sort */
|
|
82
|
+
function generateColumns(fields, modelName, aiButtons) {
|
|
83
|
+
const cols = fields
|
|
84
|
+
.filter((f) => f.name !== 'id') // skip id column in form
|
|
85
|
+
.map((f) => {
|
|
86
|
+
const label = f.description || FALLBACK_LABELS[f.name] || f.name;
|
|
87
|
+
const width = getColumnWidth(f);
|
|
88
|
+
const extras = [` width: ${width},`];
|
|
89
|
+
const renders = [];
|
|
90
|
+
if (f.type === 'boolean') {
|
|
91
|
+
renders.push(` render: (val: boolean) => <Tag color={val ? 'green' : 'red'}>{val ? '是' : '否'}</Tag>,`);
|
|
92
|
+
}
|
|
93
|
+
else if (f.enum) {
|
|
94
|
+
// Enum columns: Tag render + server-side column filter
|
|
95
|
+
renders.push(` render: (val: string) => val ? <Tag color={tagColors?.['${f.name}']?.[val] || 'blue'}>{val}</Tag> : '-',`);
|
|
96
|
+
const filterItems = f.enum.map(v => ` { text: '${v}', value: '${v}' },`).join('\n');
|
|
97
|
+
extras.push(` filters: [\n${filterItems}\n ],`);
|
|
98
|
+
extras.push(` filteredValue: tableFilters.${f.name} || null,`);
|
|
99
|
+
}
|
|
100
|
+
else if (f.type === 'string[]') {
|
|
101
|
+
renders.push(` render: (val: string[]) => val?.map((v, i) => <Tag key={i}>{v}</Tag>),`);
|
|
102
|
+
}
|
|
103
|
+
else if (f.type === 'number[]') {
|
|
104
|
+
renders.push(` render: (val: number[]) => val?.join(', '),`);
|
|
105
|
+
}
|
|
106
|
+
else if (f.type === 'number') {
|
|
107
|
+
// Number columns: server-side sortable
|
|
108
|
+
extras.push(` sorter: true,`);
|
|
109
|
+
extras.push(` sortOrder: tableSorter.field === '${f.name}' ? tableSorter.order : null,`);
|
|
110
|
+
}
|
|
111
|
+
else if (f.type === 'date') {
|
|
112
|
+
// Date columns: server-side range filter
|
|
113
|
+
extras.push(` filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }: any) => (
|
|
114
|
+
<div style={{ padding: 8 }}>
|
|
115
|
+
<DatePicker.RangePicker
|
|
116
|
+
style={{ marginBottom: 8, display: 'block' }}
|
|
117
|
+
value={selectedKeys[0] ? selectedKeys : []}
|
|
118
|
+
onChange={(dates) => {
|
|
119
|
+
setSelectedKeys(dates ? [dates] : []);
|
|
120
|
+
confirm({ closeDropdown: false });
|
|
121
|
+
}}
|
|
122
|
+
/>
|
|
123
|
+
<Space>
|
|
124
|
+
<Button type="primary" size="small" onClick={() => confirm()}>筛选</Button>
|
|
125
|
+
<Button size="small" onClick={() => { clearFilters?.(); confirm(); }}>重置</Button>
|
|
126
|
+
</Space>
|
|
127
|
+
</div>
|
|
128
|
+
),`);
|
|
129
|
+
extras.push(` filteredValue: tableFilters.${f.name} || null,`);
|
|
130
|
+
}
|
|
131
|
+
else if (isLongTextField(f)) {
|
|
132
|
+
// Long text: auto wrap + 2-line ellipsis with expandable
|
|
133
|
+
extras.push(` onCell: () => ({ style: { wordBreak: 'break-word' as const } }),`);
|
|
134
|
+
renders.push(` render: (val: string) => val ? <Typography.Paragraph ellipsis={{ rows: 2, expandable: 'collapsible', symbol: '展开' }} style={{ marginBottom: 0 }}>{val}</Typography.Paragraph> : '-',`);
|
|
135
|
+
}
|
|
136
|
+
else if (f.type === 'string' && !f.enum) {
|
|
137
|
+
// Short string: tooltip ellipsis
|
|
138
|
+
extras.push(` ellipsis: true,`);
|
|
139
|
+
}
|
|
140
|
+
return ` {
|
|
141
|
+
title: '${label}',
|
|
142
|
+
dataIndex: '${f.name}',
|
|
143
|
+
key: '${f.name}',
|
|
144
|
+
${extras.join('\n')}${renders.join('\n')} },`;
|
|
145
|
+
})
|
|
146
|
+
.join('\n');
|
|
147
|
+
// Add action column
|
|
148
|
+
const aiButtonMenuCode = aiButtons && aiButtons.length > 0
|
|
149
|
+
? `<Tooltip title="AI 助手"><Dropdown menu={{ items: aiButtonMenuItems(record) }}>
|
|
150
|
+
<Button type="text" size="small" icon={<ThunderboltOutlined />} />
|
|
151
|
+
</Dropdown></Tooltip>`
|
|
152
|
+
: '';
|
|
153
|
+
const actionButtons = [
|
|
154
|
+
`<Tooltip title="编辑"><Button type="text" size="small" icon={<EditOutlined />} onClick={() => handleEdit(record)} /></Tooltip>`,
|
|
155
|
+
aiButtonMenuCode,
|
|
156
|
+
`<Popconfirm title="确认删除?" onConfirm={() => handleDelete(record.id)}>
|
|
157
|
+
<Tooltip title="删除"><Button type="text" size="small" danger icon={<DeleteOutlined />} /></Tooltip>
|
|
158
|
+
</Popconfirm>`,
|
|
159
|
+
].filter(Boolean).join('\n ');
|
|
160
|
+
return `${cols}
|
|
161
|
+
{
|
|
162
|
+
title: '操作',
|
|
163
|
+
key: 'action',
|
|
164
|
+
width: ${aiButtons && aiButtons.length > 0 ? 120 : 90},
|
|
165
|
+
fixed: 'right' as const,
|
|
166
|
+
render: (_: unknown, record: ${toPascalCase(modelName)}Record) => (
|
|
167
|
+
<Space>
|
|
168
|
+
${actionButtons}
|
|
169
|
+
</Space>
|
|
170
|
+
),
|
|
171
|
+
},`;
|
|
172
|
+
}
|
|
173
|
+
/** Build display label from model description */
|
|
174
|
+
function buildLabel(description, pascalName) {
|
|
175
|
+
return description || pascalName;
|
|
176
|
+
}
|
|
177
|
+
/** Generate CRUD page template from model schema */
|
|
178
|
+
function crudPageTemplate(model, aiButtons) {
|
|
179
|
+
const pascalName = toPascalCase(model.name);
|
|
180
|
+
const recordType = `${pascalName}Record`;
|
|
181
|
+
// Detect field types for conditional logic
|
|
182
|
+
const dateFields = model.fields.filter(f => f.type === 'date').map(f => f.name);
|
|
183
|
+
const hasDateFields = dateFields.length > 0;
|
|
184
|
+
// Build TypeScript interface from fields
|
|
185
|
+
const fieldDefs = model.fields.map((f) => {
|
|
186
|
+
const tsType = f.type === 'string[]' ? 'string[]'
|
|
187
|
+
: f.type === 'number[]' ? 'number[]'
|
|
188
|
+
: f.type === 'json' ? 'Record<string, unknown>'
|
|
189
|
+
: f.type === 'number' ? 'number'
|
|
190
|
+
: f.type === 'boolean' ? 'boolean'
|
|
191
|
+
: f.type === 'date' ? 'string'
|
|
192
|
+
: 'string';
|
|
193
|
+
return ` ${f.name}${f.required ? '' : '?'}: ${tsType};`;
|
|
194
|
+
}).join('\n');
|
|
195
|
+
const columns = generateColumns(model.fields, model.name, aiButtons);
|
|
196
|
+
const formItems = model.fields
|
|
197
|
+
.filter((f) => f.name !== 'id') // id is auto-generated
|
|
198
|
+
.map((f) => fieldToFormItem(f, model.name))
|
|
199
|
+
.join('\n');
|
|
200
|
+
// Generate handleEdit with date conversion
|
|
201
|
+
const handleEditBody = hasDateFields
|
|
202
|
+
? `const handleEdit = (record: ${recordType}) => {
|
|
203
|
+
setEditingRecord(record);
|
|
204
|
+
const formValues = { ...record };
|
|
205
|
+
${dateFields.map(f => ` if (formValues.${f}) formValues.${f} = dayjs(formValues.${f}) as any;`).join('\n')}
|
|
206
|
+
form.setFieldsValue(formValues);
|
|
207
|
+
setModalOpen(true);
|
|
208
|
+
};`
|
|
209
|
+
: `const handleEdit = (record: ${recordType}) => {
|
|
210
|
+
setEditingRecord(record);
|
|
211
|
+
form.setFieldsValue(record);
|
|
212
|
+
setModalOpen(true);
|
|
213
|
+
};`;
|
|
214
|
+
// Generate handleSave with date serialization
|
|
215
|
+
const handleSaveBody = hasDateFields
|
|
216
|
+
? `const handleSave = async () => {
|
|
217
|
+
try {
|
|
218
|
+
const values = await form.validateFields();
|
|
219
|
+
${dateFields.map(f => ` if (values.${f}) values.${f} = values.${f}.format('YYYY-MM-DD');`).join('\n')}
|
|
220
|
+
if (editingRecord?.id) {
|
|
221
|
+
await update(editingRecord.id, values);
|
|
222
|
+
message.success('更新成功');
|
|
223
|
+
} else {
|
|
224
|
+
await create(values);
|
|
225
|
+
message.success('创建成功');
|
|
226
|
+
}
|
|
227
|
+
setModalOpen(false);
|
|
228
|
+
fetchData();
|
|
229
|
+
} catch {
|
|
230
|
+
// form validation failed
|
|
231
|
+
}
|
|
232
|
+
};`
|
|
233
|
+
: `const handleSave = async () => {
|
|
234
|
+
try {
|
|
235
|
+
const values = await form.validateFields();
|
|
236
|
+
if (editingRecord?.id) {
|
|
237
|
+
await update(editingRecord.id, values);
|
|
238
|
+
message.success('更新成功');
|
|
239
|
+
} else {
|
|
240
|
+
await create(values);
|
|
241
|
+
message.success('创建成功');
|
|
242
|
+
}
|
|
243
|
+
setModalOpen(false);
|
|
244
|
+
fetchData();
|
|
245
|
+
} catch {
|
|
246
|
+
// form validation failed
|
|
247
|
+
}
|
|
248
|
+
};`;
|
|
249
|
+
const dayjsImport = hasDateFields ? `\nimport dayjs from 'dayjs';` : '';
|
|
250
|
+
const hasAIButtons = aiButtons && aiButtons.length > 0;
|
|
251
|
+
// Build imports — merge AI-specific imports into existing lines
|
|
252
|
+
const antdExtra = hasAIButtons ? ', Dropdown' : '';
|
|
253
|
+
const iconsExtra = hasAIButtons ? ', ThunderboltOutlined' : '';
|
|
254
|
+
const extraIcons = ', EditOutlined, DeleteOutlined';
|
|
255
|
+
const loomExtra = hasAIButtons ? ', AIContext' : '';
|
|
256
|
+
const reactExtra = hasAIButtons ? ', useContext' : '';
|
|
257
|
+
return `import React, { useEffect, useState, useCallback${reactExtra} } from 'react';
|
|
258
|
+
import { Table, Button, Modal, Form, Input, InputNumber, Select, Switch, DatePicker, Space, Popconfirm, message, Tag, Card, Flex, Tooltip, Typography, type TableProps${antdExtra} } from 'antd';
|
|
259
|
+
import { PlusOutlined${iconsExtra}${extraIcons} } from '@ant-design/icons';
|
|
260
|
+
import { useData${loomExtra} } from '@loom-framework/frontend-antd';${dayjsImport}
|
|
261
|
+
|
|
262
|
+
interface ${recordType} {
|
|
263
|
+
id: string;
|
|
264
|
+
${fieldDefs}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const modelFields: { name: string; type: string }[] = [
|
|
268
|
+
${model.fields.map(f => ` { name: '${f.name}', type: '${f.type}' },`).join('\n')}
|
|
269
|
+
];
|
|
270
|
+
|
|
271
|
+
export function ${pascalName}Page(): React.ReactElement {
|
|
272
|
+
const { list, create, update, remove, loading, refresh } = useData<${recordType}>('${model.name}');
|
|
273
|
+
const [form] = Form.useForm();
|
|
274
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
275
|
+
const [editingRecord, setEditingRecord] = useState<${recordType} | null>(null);
|
|
276
|
+
const [tableFilters, setTableFilters] = useState<Record<string, any>>({});
|
|
277
|
+
const [tableSorter, setTableSorter] = useState<{ field: string; order: 'ascend' | 'descend' | null }>({ field: '', order: null });
|
|
278
|
+
|
|
279
|
+
const fetchData = useCallback((filters?: Record<string, (string | number | boolean | null)[] | null>, sorter?: { field: string; order: 'ascend' | 'descend' | null }) => {
|
|
280
|
+
const currentFilters = filters ?? tableFilters;
|
|
281
|
+
const currentSorter = sorter ?? tableSorter;
|
|
282
|
+
const queryParams: any = {};
|
|
283
|
+
// Build filter from antd column filter values
|
|
284
|
+
const apiFilter: Record<string, unknown> = {};
|
|
285
|
+
for (const [key, val] of Object.entries(currentFilters)) {
|
|
286
|
+
if (val && val.length > 0) {
|
|
287
|
+
const field = modelFields.find(f => f.name === key);
|
|
288
|
+
if (field?.type === 'date') {
|
|
289
|
+
// Date range: val is [dayjs, dayjs] stored in filter
|
|
290
|
+
apiFilter[key] = { __range: val.map((v: any) => v?.format?.('YYYY-MM-DD') || v) };
|
|
291
|
+
} else if (val.length === 1) {
|
|
292
|
+
apiFilter[key] = val[0];
|
|
293
|
+
} else {
|
|
294
|
+
// Multiple filter values for a single column (e.g. subject in [数学, 英语])
|
|
295
|
+
apiFilter[key] = val;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (Object.keys(apiFilter).length > 0) queryParams.filter = apiFilter;
|
|
300
|
+
// Build sort
|
|
301
|
+
if (currentSorter.field && currentSorter.order) {
|
|
302
|
+
queryParams.sort = currentSorter.field;
|
|
303
|
+
queryParams.sortOrder = currentSorter.order === 'descend' ? 'desc' : 'asc';
|
|
304
|
+
}
|
|
305
|
+
refresh(queryParams);
|
|
306
|
+
}, [refresh, tableFilters, tableSorter]);
|
|
307
|
+
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
fetchData({}, { field: '', order: null });
|
|
310
|
+
}, []);
|
|
311
|
+
|
|
312
|
+
const handleAdd = () => {
|
|
313
|
+
setEditingRecord(null);
|
|
314
|
+
form.resetFields();
|
|
315
|
+
setModalOpen(true);
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
${handleEditBody}
|
|
319
|
+
|
|
320
|
+
const handleDelete = async (id: string) => {
|
|
321
|
+
try {
|
|
322
|
+
await remove(id);
|
|
323
|
+
message.success('删除成功');
|
|
324
|
+
fetchData();
|
|
325
|
+
} catch {
|
|
326
|
+
message.error('删除失败');
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
${handleSaveBody}
|
|
331
|
+
${hasAIButtons ? `
|
|
332
|
+
const ai = useContext(AIContext);
|
|
333
|
+
|
|
334
|
+
// Build context object from the current record for AI prompts
|
|
335
|
+
// Key = raw field name (matches {{var}} in prompt templates)
|
|
336
|
+
// Value = description + value for fields with descriptions
|
|
337
|
+
const buildRecordContext = (record: ${recordType}): Record<string, string | string[] | number | boolean | null | undefined> => {
|
|
338
|
+
const labelMap: Record<string, string> = {
|
|
339
|
+
${model.fields.map(f => ` ${f.name}: '${f.description || ''}',`).join('\n')}
|
|
340
|
+
};
|
|
341
|
+
const ctx: Record<string, string | string[] | number | boolean | null | undefined> = {};
|
|
342
|
+
for (const [k, v] of Object.entries(record)) {
|
|
343
|
+
if (v != null && v !== '' && !(Array.isArray(v) && v.length === 0)) {
|
|
344
|
+
ctx[k] = v as string | string[] | number | boolean | null | undefined;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return ctx;
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const aiButtonMenuItems = (record: ${recordType}) => {
|
|
351
|
+
const ctx = buildRecordContext(record);
|
|
352
|
+
return [
|
|
353
|
+
${aiButtons.map(btn => {
|
|
354
|
+
return ` { key: '${btn.id}', label: '${btn.label}', onClick: () => ai?.triggerAI({ buttonId: '${btn.id}', label: '${btn.label}', prompt: '${btn.prompt.replace(/'/g, "\\'").replace(/\n/g, "\\n")}', context: ctx }) },`;
|
|
355
|
+
}).join('\n')}
|
|
356
|
+
];
|
|
357
|
+
};` : ''}
|
|
358
|
+
|
|
359
|
+
const columns: TableProps<${recordType}>['columns'] = [
|
|
360
|
+
${columns}
|
|
361
|
+
];
|
|
362
|
+
${generateTagColors(model.fields)}
|
|
363
|
+
const handleTableChange: TableProps<${recordType}>['onChange'] = (pagination, filters, sorter) => {
|
|
364
|
+
const newFilters = filters as Record<string, any>;
|
|
365
|
+
const newSorter = !Array.isArray(sorter) && sorter.field
|
|
366
|
+
? { field: sorter.field as string, order: sorter.order as 'ascend' | 'descend' | null }
|
|
367
|
+
: { field: '', order: null };
|
|
368
|
+
setTableFilters(newFilters);
|
|
369
|
+
setTableSorter(newSorter);
|
|
370
|
+
fetchData(newFilters, newSorter);
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
return (
|
|
374
|
+
<>
|
|
375
|
+
<Card>
|
|
376
|
+
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
|
|
377
|
+
<h2 style={{ margin: 0 }}>${buildLabel(model.description, pascalName)}</h2>
|
|
378
|
+
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
|
|
379
|
+
新增
|
|
380
|
+
</Button>
|
|
381
|
+
</Flex>
|
|
382
|
+
|
|
383
|
+
<Table
|
|
384
|
+
columns={columns}
|
|
385
|
+
dataSource={list}
|
|
386
|
+
rowKey="id"
|
|
387
|
+
loading={loading}
|
|
388
|
+
size="middle"
|
|
389
|
+
scroll={{ x: 'max-content' }}
|
|
390
|
+
onChange={handleTableChange}
|
|
391
|
+
pagination={{ pageSize: 10, showSizeChanger: true, showTotal: (total) => \`共 \${total} 条\` }}
|
|
392
|
+
/>
|
|
393
|
+
</Card>
|
|
394
|
+
|
|
395
|
+
<Modal
|
|
396
|
+
title={editingRecord ? '编辑${buildLabel(model.description, pascalName)}' : '新增${buildLabel(model.description, pascalName)}'}
|
|
397
|
+
open={modalOpen}
|
|
398
|
+
onOk={handleSave}
|
|
399
|
+
onCancel={() => setModalOpen(false)}
|
|
400
|
+
destroyOnHidden
|
|
401
|
+
width={640}
|
|
402
|
+
>
|
|
403
|
+
<Form form={form} layout="vertical">
|
|
404
|
+
${formItems}
|
|
405
|
+
</Form>
|
|
406
|
+
</Modal>
|
|
407
|
+
</>
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export default ${pascalName}Page;
|
|
412
|
+
`;
|
|
413
|
+
}
|
|
414
|
+
/** Minimal skeleton page template (no model) */
|
|
415
|
+
const SKELETON_TEMPLATE = (pascalName) => `import React from 'react';
|
|
416
|
+
|
|
417
|
+
export interface ${pascalName}Props {
|
|
418
|
+
// TODO: Define page props
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export function ${pascalName}(props: ${pascalName}Props): React.ReactElement {
|
|
422
|
+
return (
|
|
423
|
+
<div className="${pascalName.toLowerCase()}-page">
|
|
424
|
+
<h1>${pascalName}</h1>
|
|
425
|
+
<p>TODO: Implement this page.</p>
|
|
426
|
+
</div>
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export default ${pascalName};
|
|
431
|
+
`;
|
|
432
|
+
export function registerGeneratePageCommand(program) {
|
|
433
|
+
program
|
|
434
|
+
.command('page <name>')
|
|
435
|
+
.description('Create a new frontend page component with PascalCase naming')
|
|
436
|
+
.option('--model <model>', 'Data model name from loom.config.ts to generate CRUD page (auto-generates capabilities and wires App.tsx)')
|
|
437
|
+
.action(async (name, cmdOptions) => {
|
|
438
|
+
try {
|
|
439
|
+
const projectRoot = await resolveProjectRoot();
|
|
440
|
+
const pascalName = toPascalCase(name);
|
|
441
|
+
const pageDir = path.join(projectRoot, 'frontend', 'src', 'components', 'pages');
|
|
442
|
+
const pagePath = path.join(pageDir, `${pascalName}.tsx`);
|
|
443
|
+
// Check if page already exists
|
|
444
|
+
try {
|
|
445
|
+
await fs.access(pagePath);
|
|
446
|
+
console.error(chalk.red(`Page "${pascalName}" already exists at ${pagePath}`));
|
|
447
|
+
process.exit(1);
|
|
448
|
+
}
|
|
449
|
+
catch {
|
|
450
|
+
// File does not exist, proceed
|
|
451
|
+
}
|
|
452
|
+
let template;
|
|
453
|
+
let modelLabel = pascalName;
|
|
454
|
+
if (cmdOptions.model) {
|
|
455
|
+
// Load config and find model schema
|
|
456
|
+
const config = await loadConfig(projectRoot);
|
|
457
|
+
const modelSchema = getModelSchema(config, cmdOptions.model);
|
|
458
|
+
if (!modelSchema) {
|
|
459
|
+
console.error(chalk.red(`Model "${cmdOptions.model}" not found in loom.config.ts`));
|
|
460
|
+
console.error(chalk.dim(`Available models: ${config.data.models.map((m) => m.name).join(', ')}`));
|
|
461
|
+
process.exit(1);
|
|
462
|
+
}
|
|
463
|
+
modelLabel = buildLabel(modelSchema.description, pascalName);
|
|
464
|
+
// Step 1: Auto-generate capabilities (Skill for data access via CLI)
|
|
465
|
+
const capResult = await generateCapabilities(projectRoot, config);
|
|
466
|
+
console.log(chalk.green('Capabilities generated'), chalk.dim(`(${capResult.filesWritten.length} files)`));
|
|
467
|
+
// Step 2: Generate CRUD page — filter aiButtons by placement
|
|
468
|
+
const modelAiButtons = config.aiButtons?.filter(btn => {
|
|
469
|
+
// No placement = show on all pages (backward compatible)
|
|
470
|
+
if (!btn.placement)
|
|
471
|
+
return true;
|
|
472
|
+
// Comma-separated list of model names
|
|
473
|
+
const targets = btn.placement.split(',').map(s => s.trim());
|
|
474
|
+
return targets.includes(cmdOptions.model);
|
|
475
|
+
});
|
|
476
|
+
template = crudPageTemplate(modelSchema, modelAiButtons);
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
template = SKELETON_TEMPLATE(pascalName);
|
|
480
|
+
}
|
|
481
|
+
await fs.mkdir(pageDir, { recursive: true });
|
|
482
|
+
await fs.writeFile(pagePath, template, 'utf-8');
|
|
483
|
+
console.log(chalk.green('Page created successfully!'));
|
|
484
|
+
console.log();
|
|
485
|
+
console.log(chalk.bold(' Page:'), pascalName);
|
|
486
|
+
console.log(chalk.bold(' Path:'), path.join('frontend', 'src', 'components', 'pages', `${pascalName}.tsx`));
|
|
487
|
+
if (cmdOptions.model) {
|
|
488
|
+
console.log(chalk.bold(' Model:'), cmdOptions.model);
|
|
489
|
+
}
|
|
490
|
+
// Step 3: Auto-wire App.tsx when using --model
|
|
491
|
+
if (cmdOptions.model) {
|
|
492
|
+
const wired = await wireAppTsxAutomatic(projectRoot, pascalName, cmdOptions.model, modelLabel);
|
|
493
|
+
if (wired) {
|
|
494
|
+
console.log(chalk.green(' App.tsx wired automatically'));
|
|
495
|
+
// Also wire SkillManagementPage on first page generation
|
|
496
|
+
const skillWired = await wireSkillManagementPage(projectRoot);
|
|
497
|
+
if (skillWired) {
|
|
498
|
+
console.log(chalk.green(' Skill management page wired'));
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
console.log(chalk.yellow(' Could not auto-wire App.tsx — add the page import, navItem, and switch case manually'));
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
console.log();
|
|
507
|
+
console.log(chalk.dim(' Use --model <name> to generate a CRUD page from a data model.'));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
catch (err) {
|
|
511
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
512
|
+
console.error(chalk.red('Failed to create page:'), message);
|
|
513
|
+
process.exit(1);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Auto-wire App.tsx: add import, navItem, and switch case for a new page.
|
|
519
|
+
* Returns true if successful, false if App.tsx structure is unexpected.
|
|
520
|
+
*/
|
|
521
|
+
async function wireAppTsxAutomatic(projectRoot, pascalName, modelKey, modelLabel) {
|
|
522
|
+
const appPath = path.join(projectRoot, 'frontend', 'src', 'App.tsx');
|
|
523
|
+
let content;
|
|
524
|
+
try {
|
|
525
|
+
content = await fs.readFile(appPath, 'utf-8');
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
// Check if this page is already wired (avoid duplicates)
|
|
531
|
+
if (content.includes(`from './components/pages/${pascalName}'`) || content.includes(`<${pascalName}Page`)) {
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
// Also check if navItem with same key already exists
|
|
535
|
+
if (content.includes(`key: '${modelKey}'`)) {
|
|
536
|
+
return false;
|
|
537
|
+
}
|
|
538
|
+
let modified = content;
|
|
539
|
+
// 1. Add import after the last import line
|
|
540
|
+
const importLine = `import ${pascalName}Page from './components/pages/${pascalName}';`;
|
|
541
|
+
const lastImportEnd = modified.lastIndexOf('\n', modified.indexOf('\nexport'));
|
|
542
|
+
if (lastImportEnd === -1)
|
|
543
|
+
return false;
|
|
544
|
+
modified = modified.slice(0, lastImportEnd + 1) + importLine + '\n' + modified.slice(lastImportEnd + 1);
|
|
545
|
+
// 2. Add navItem (before the closing ] of navItems array)
|
|
546
|
+
const navItemLine = ` { key: '${modelKey}', label: '${modelLabel}' },`;
|
|
547
|
+
const navItemsEnd = modified.indexOf('// Add more nav items');
|
|
548
|
+
if (navItemsEnd !== -1) {
|
|
549
|
+
// Insert before the comment placeholder
|
|
550
|
+
const lineStart = modified.lastIndexOf('\n', navItemsEnd) + 1;
|
|
551
|
+
modified = modified.slice(0, lineStart) + navItemLine + '\n' + modified.slice(lineStart);
|
|
552
|
+
}
|
|
553
|
+
else {
|
|
554
|
+
// Fallback: find the closing ] of navItems array
|
|
555
|
+
const navArrayMatch = modified.match(/const navItems\s*=\s*\[/);
|
|
556
|
+
if (!navArrayMatch)
|
|
557
|
+
return false;
|
|
558
|
+
const arrayStart = navArrayMatch.index + navArrayMatch[0].length;
|
|
559
|
+
// Find the matching ]
|
|
560
|
+
let depth = 1;
|
|
561
|
+
let pos = arrayStart;
|
|
562
|
+
while (pos < modified.length && depth > 0) {
|
|
563
|
+
if (modified[pos] === '[')
|
|
564
|
+
depth++;
|
|
565
|
+
else if (modified[pos] === ']')
|
|
566
|
+
depth--;
|
|
567
|
+
pos++;
|
|
568
|
+
}
|
|
569
|
+
const closingBracket = pos - 1;
|
|
570
|
+
modified = modified.slice(0, closingBracket) + navItemLine + '\n' + modified.slice(closingBracket);
|
|
571
|
+
}
|
|
572
|
+
// 3. Add switch case — before skill-management case if present, otherwise before default
|
|
573
|
+
const caseLine = ` case '${modelKey}': return <${pascalName}Page />;`;
|
|
574
|
+
const skillCaseIdx = modified.indexOf("case 'skill-management':");
|
|
575
|
+
const insertAnchor = skillCaseIdx !== -1 ? skillCaseIdx : modified.indexOf('default:');
|
|
576
|
+
if (insertAnchor === -1)
|
|
577
|
+
return false;
|
|
578
|
+
const insertLineStart = modified.lastIndexOf('\n', insertAnchor) + 1;
|
|
579
|
+
modified = modified.slice(0, insertLineStart) + caseLine + '\n' + modified.slice(insertLineStart);
|
|
580
|
+
// 4. Ensure baseUrl="" on AppShell (prevent /api/v1/api/v1 double prefix)
|
|
581
|
+
if (modified.includes('<AppShell') && !modified.includes('baseUrl=')) {
|
|
582
|
+
modified = modified.replace('<AppShell', '<AppShell\n baseUrl=""');
|
|
583
|
+
}
|
|
584
|
+
await fs.writeFile(appPath, modified, 'utf-8');
|
|
585
|
+
return true;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Auto-wire the SkillManagementPage into App.tsx.
|
|
589
|
+
* Called once when the first CRUD page is generated.
|
|
590
|
+
* Returns true if successful, false if already wired or structure is unexpected.
|
|
591
|
+
*/
|
|
592
|
+
async function wireSkillManagementPage(projectRoot) {
|
|
593
|
+
const appPath = path.join(projectRoot, 'frontend', 'src', 'App.tsx');
|
|
594
|
+
let content;
|
|
595
|
+
try {
|
|
596
|
+
content = await fs.readFile(appPath, 'utf-8');
|
|
597
|
+
}
|
|
598
|
+
catch {
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
// Check if already wired (avoid duplicates)
|
|
602
|
+
if (content.includes('SkillManagementPage')) {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
let modified = content;
|
|
606
|
+
// 1. Add import after the last import line
|
|
607
|
+
const importLine = `import { SkillManagementPage } from '@loom-framework/frontend-antd';`;
|
|
608
|
+
const lastImportEnd = modified.lastIndexOf('\n', modified.indexOf('\nexport'));
|
|
609
|
+
if (lastImportEnd === -1)
|
|
610
|
+
return false;
|
|
611
|
+
modified = modified.slice(0, lastImportEnd + 1) + importLine + '\n' + modified.slice(lastImportEnd + 1);
|
|
612
|
+
// 2. Add navItem — always at the end of the array so it stays below all model pages
|
|
613
|
+
const navItemLine = ` { key: 'skill-management', label: 'Skill 管理' },`;
|
|
614
|
+
const navArrayMatch = modified.match(/const navItems\s*=\s*\[/);
|
|
615
|
+
if (!navArrayMatch)
|
|
616
|
+
return false;
|
|
617
|
+
const arrayStart = navArrayMatch.index + navArrayMatch[0].length;
|
|
618
|
+
let depth = 1;
|
|
619
|
+
let pos = arrayStart;
|
|
620
|
+
while (pos < modified.length && depth > 0) {
|
|
621
|
+
if (modified[pos] === '[')
|
|
622
|
+
depth++;
|
|
623
|
+
else if (modified[pos] === ']')
|
|
624
|
+
depth--;
|
|
625
|
+
pos++;
|
|
626
|
+
}
|
|
627
|
+
const closingBracket = pos - 1;
|
|
628
|
+
// Insert before the line containing the closing bracket
|
|
629
|
+
const lineStart = modified.lastIndexOf('\n', closingBracket) + 1;
|
|
630
|
+
modified = modified.slice(0, lineStart) + navItemLine + '\n' + modified.slice(lineStart);
|
|
631
|
+
// 3. Add switch case before default
|
|
632
|
+
const caseLine = ` case 'skill-management': return <SkillManagementPage />;`;
|
|
633
|
+
const defaultCase = modified.indexOf('default:');
|
|
634
|
+
if (defaultCase === -1)
|
|
635
|
+
return false;
|
|
636
|
+
const defaultLineStart = modified.lastIndexOf('\n', defaultCase) + 1;
|
|
637
|
+
modified = modified.slice(0, defaultLineStart) + caseLine + '\n' + modified.slice(defaultLineStart);
|
|
638
|
+
await fs.writeFile(appPath, modified, 'utf-8');
|
|
639
|
+
return true;
|
|
640
|
+
}
|
|
641
|
+
//# sourceMappingURL=generate-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-page.js","sourceRoot":"","sources":["../../../src/cli/commands/generate-page.ts"],"names":[],"mappings":"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"}
|