@atlashub/smartstack-mcp 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlashub/smartstack-mcp",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "MCP Server for SmartStack/AtlasHub - Conventions validation, migrations analysis, scaffolding",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,298 +1,298 @@
1
- import React, { useState, useEffect, useCallback } from 'react';
2
-
3
- // ============================================================================
4
- // Types
5
- // ============================================================================
6
-
7
- export interface {{name}}Data {
8
- id?: string;
9
- createdAt?: string;
10
- updatedAt?: string;
11
- // TODO: Add {{name}} specific properties
12
- }
13
-
14
- export interface {{name}}Props {
15
- /** Entity ID for edit mode */
16
- id?: string;
17
- /** Initial data */
18
- initialData?: Partial<{{name}}Data>;
19
- /** Callback when data is saved */
20
- onSave?: (data: {{name}}Data) => void;
21
- /** Callback when cancelled */
22
- onCancel?: () => void;
23
- /** Loading state from parent */
24
- loading?: boolean;
25
- /** Read-only mode */
26
- readOnly?: boolean;
27
- }
28
-
29
- // ============================================================================
30
- // Component
31
- // ============================================================================
32
-
33
- /**
34
- * {{name}} component
35
- *
36
- * @example
37
- * ```tsx
38
- * <{{name}}
39
- * id="123"
40
- * onSave={(data) => console.log('Saved:', data)}
41
- * onCancel={() => navigate(-1)}
42
- * />
43
- * ```
44
- */
45
- export const {{name}}: React.FC<{{name}}Props> = ({
46
- id,
47
- initialData,
48
- onSave,
49
- onCancel,
50
- loading: externalLoading,
51
- readOnly = false,
52
- }) => {
53
- // State
54
- const [data, setData] = useState<{{name}}Data>(initialData || {});
55
- const [loading, setLoading] = useState(false);
56
- const [error, setError] = useState<string | null>(null);
57
- const [isDirty, setIsDirty] = useState(false);
58
-
59
- // Combined loading state
60
- const isLoading = loading || externalLoading;
61
-
62
- // Fetch data when ID changes
63
- useEffect(() => {
64
- if (id && !initialData) {
65
- fetchData(id);
66
- }
67
- }, [id, initialData]);
68
-
69
- // Fetch data from API
70
- const fetchData = useCallback(async (fetchId: string) => {
71
- setLoading(true);
72
- setError(null);
73
-
74
- try {
75
- // TODO: Implement API call
76
- // const response = await {{nameCamel}}Api.getById(fetchId);
77
- // setData(response);
78
-
79
- // Placeholder
80
- setData({ id: fetchId });
81
- } catch (e) {
82
- setError(e instanceof Error ? e.message : 'Failed to load data');
83
- } finally {
84
- setLoading(false);
85
- }
86
- }, []);
87
-
88
- // Handle field change
89
- const handleChange = useCallback((field: keyof {{name}}Data, value: unknown) => {
90
- setData(prev => ({ ...prev, [field]: value }));
91
- setIsDirty(true);
92
- }, []);
93
-
94
- // Handle form submission
95
- const handleSubmit = useCallback(async (e: React.FormEvent) => {
96
- e.preventDefault();
97
-
98
- if (readOnly) return;
99
-
100
- setLoading(true);
101
- setError(null);
102
-
103
- try {
104
- // TODO: Implement API call
105
- // const result = data.id
106
- // ? await {{nameCamel}}Api.update(data.id, data)
107
- // : await {{nameCamel}}Api.create(data);
108
-
109
- if (onSave) {
110
- onSave(data);
111
- }
112
-
113
- setIsDirty(false);
114
- } catch (e) {
115
- setError(e instanceof Error ? e.message : 'Failed to save');
116
- } finally {
117
- setLoading(false);
118
- }
119
- }, [data, onSave, readOnly]);
120
-
121
- // Handle cancel
122
- const handleCancel = useCallback(() => {
123
- if (isDirty) {
124
- const confirmed = window.confirm('You have unsaved changes. Are you sure you want to cancel?');
125
- if (!confirmed) return;
126
- }
127
-
128
- if (onCancel) {
129
- onCancel();
130
- }
131
- }, [isDirty, onCancel]);
132
-
133
- // Render loading state
134
- if (isLoading && !data.id) {
135
- return (
136
- <div className="flex items-center justify-center p-8">
137
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500" />
138
- <span className="ml-2 text-gray-600">Loading...</span>
139
- </div>
140
- );
141
- }
142
-
143
- // Render error state
144
- if (error) {
145
- return (
146
- <div className="p-4 bg-red-50 border border-red-200 rounded-lg">
147
- <div className="flex items-center">
148
- <svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
149
- <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
150
- </svg>
151
- <span className="ml-2 text-red-700">{error}</span>
152
- </div>
153
- <button
154
- onClick={() => id && fetchData(id)}
155
- className="mt-2 text-sm text-red-600 hover:text-red-800 underline"
156
- >
157
- Try again
158
- </button>
159
- </div>
160
- );
161
- }
162
-
163
- return (
164
- <div className="bg-white rounded-lg shadow-sm border border-gray-200">
165
- {/* Header */}
166
- <div className="px-6 py-4 border-b border-gray-200">
167
- <h2 className="text-xl font-semibold text-gray-900">
168
- {id ? 'Edit' : 'Create'} {{name}}
169
- </h2>
170
- {isDirty && (
171
- <span className="text-sm text-amber-600">Unsaved changes</span>
172
- )}
173
- </div>
174
-
175
- {/* Form */}
176
- <form onSubmit={handleSubmit} className="p-6 space-y-6">
177
- {/* TODO: Add form fields */}
178
- <div className="text-gray-500 text-center py-8">
179
- Add your form fields here
180
- </div>
181
-
182
- {/* Actions */}
183
- {!readOnly && (
184
- <div className="flex items-center justify-end gap-3 pt-4 border-t border-gray-200">
185
- {onCancel && (
186
- <button
187
- type="button"
188
- onClick={handleCancel}
189
- disabled={isLoading}
190
- className="px-4 py-2 text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50"
191
- >
192
- Cancel
193
- </button>
194
- )}
195
- <button
196
- type="submit"
197
- disabled={isLoading || !isDirty}
198
- className="px-4 py-2 text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
199
- >
200
- {isLoading ? 'Saving...' : 'Save'}
201
- </button>
202
- </div>
203
- )}
204
- </form>
205
- </div>
206
- );
207
- };
208
-
209
- export default {{name}};
210
-
211
- // ============================================================================
212
- // Hook
213
- // ============================================================================
214
-
215
- export interface Use{{name}}Options {
216
- id?: string;
217
- autoFetch?: boolean;
218
- }
219
-
220
- export function use{{name}}(options: Use{{name}}Options = {}) {
221
- const { id, autoFetch = true } = options;
222
-
223
- const [data, setData] = useState<{{name}}Data | null>(null);
224
- const [loading, setLoading] = useState(false);
225
- const [error, setError] = useState<Error | null>(null);
226
-
227
- const fetch = useCallback(async (fetchId?: string) => {
228
- const targetId = fetchId || id;
229
- if (!targetId) return;
230
-
231
- setLoading(true);
232
- setError(null);
233
-
234
- try {
235
- // TODO: Implement API call
236
- // const result = await {{nameCamel}}Api.getById(targetId);
237
- // setData(result);
238
- } catch (e) {
239
- setError(e instanceof Error ? e : new Error('Unknown error'));
240
- } finally {
241
- setLoading(false);
242
- }
243
- }, [id]);
244
-
245
- const save = useCallback(async (saveData: {{name}}Data) => {
246
- setLoading(true);
247
- setError(null);
248
-
249
- try {
250
- // TODO: Implement API call
251
- // const result = saveData.id
252
- // ? await {{nameCamel}}Api.update(saveData.id, saveData)
253
- // : await {{nameCamel}}Api.create(saveData);
254
- // setData(result);
255
- // return result;
256
- } catch (e) {
257
- setError(e instanceof Error ? e : new Error('Unknown error'));
258
- throw e;
259
- } finally {
260
- setLoading(false);
261
- }
262
- }, []);
263
-
264
- const remove = useCallback(async (removeId?: string) => {
265
- const targetId = removeId || id;
266
- if (!targetId) return;
267
-
268
- setLoading(true);
269
- setError(null);
270
-
271
- try {
272
- // TODO: Implement API call
273
- // await {{nameCamel}}Api.delete(targetId);
274
- setData(null);
275
- } catch (e) {
276
- setError(e instanceof Error ? e : new Error('Unknown error'));
277
- throw e;
278
- } finally {
279
- setLoading(false);
280
- }
281
- }, [id]);
282
-
283
- useEffect(() => {
284
- if (autoFetch && id) {
285
- fetch();
286
- }
287
- }, [autoFetch, id, fetch]);
288
-
289
- return {
290
- data,
291
- loading,
292
- error,
293
- fetch,
294
- save,
295
- remove,
296
- setData,
297
- };
298
- }
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+
3
+ // ============================================================================
4
+ // Types
5
+ // ============================================================================
6
+
7
+ export interface {{name}}Data {
8
+ id?: string;
9
+ createdAt?: string;
10
+ updatedAt?: string;
11
+ // TODO: Add {{name}} specific properties
12
+ }
13
+
14
+ export interface {{name}}Props {
15
+ /** Entity ID for edit mode */
16
+ id?: string;
17
+ /** Initial data */
18
+ initialData?: Partial<{{name}}Data>;
19
+ /** Callback when data is saved */
20
+ onSave?: (data: {{name}}Data) => void;
21
+ /** Callback when cancelled */
22
+ onCancel?: () => void;
23
+ /** Loading state from parent */
24
+ loading?: boolean;
25
+ /** Read-only mode */
26
+ readOnly?: boolean;
27
+ }
28
+
29
+ // ============================================================================
30
+ // Component
31
+ // ============================================================================
32
+
33
+ /**
34
+ * {{name}} component
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * <{{name}}
39
+ * id="123"
40
+ * onSave={(data) => console.log('Saved:', data)}
41
+ * onCancel={() => navigate(-1)}
42
+ * />
43
+ * ```
44
+ */
45
+ export const {{name}}: React.FC<{{name}}Props> = ({
46
+ id,
47
+ initialData,
48
+ onSave,
49
+ onCancel,
50
+ loading: externalLoading,
51
+ readOnly = false,
52
+ }) => {
53
+ // State
54
+ const [data, setData] = useState<{{name}}Data>(initialData || {});
55
+ const [loading, setLoading] = useState(false);
56
+ const [error, setError] = useState<string | null>(null);
57
+ const [isDirty, setIsDirty] = useState(false);
58
+
59
+ // Combined loading state
60
+ const isLoading = loading || externalLoading;
61
+
62
+ // Fetch data when ID changes
63
+ useEffect(() => {
64
+ if (id && !initialData) {
65
+ fetchData(id);
66
+ }
67
+ }, [id, initialData]);
68
+
69
+ // Fetch data from API
70
+ const fetchData = useCallback(async (fetchId: string) => {
71
+ setLoading(true);
72
+ setError(null);
73
+
74
+ try {
75
+ // TODO: Implement API call
76
+ // const response = await {{nameCamel}}Api.getById(fetchId);
77
+ // setData(response);
78
+
79
+ // Placeholder
80
+ setData({ id: fetchId });
81
+ } catch (e) {
82
+ setError(e instanceof Error ? e.message : 'Failed to load data');
83
+ } finally {
84
+ setLoading(false);
85
+ }
86
+ }, []);
87
+
88
+ // Handle field change
89
+ const handleChange = useCallback((field: keyof {{name}}Data, value: unknown) => {
90
+ setData(prev => ({ ...prev, [field]: value }));
91
+ setIsDirty(true);
92
+ }, []);
93
+
94
+ // Handle form submission
95
+ const handleSubmit = useCallback(async (e: React.FormEvent) => {
96
+ e.preventDefault();
97
+
98
+ if (readOnly) return;
99
+
100
+ setLoading(true);
101
+ setError(null);
102
+
103
+ try {
104
+ // TODO: Implement API call
105
+ // const result = data.id
106
+ // ? await {{nameCamel}}Api.update(data.id, data)
107
+ // : await {{nameCamel}}Api.create(data);
108
+
109
+ if (onSave) {
110
+ onSave(data);
111
+ }
112
+
113
+ setIsDirty(false);
114
+ } catch (e) {
115
+ setError(e instanceof Error ? e.message : 'Failed to save');
116
+ } finally {
117
+ setLoading(false);
118
+ }
119
+ }, [data, onSave, readOnly]);
120
+
121
+ // Handle cancel
122
+ const handleCancel = useCallback(() => {
123
+ if (isDirty) {
124
+ const confirmed = window.confirm('You have unsaved changes. Are you sure you want to cancel?');
125
+ if (!confirmed) return;
126
+ }
127
+
128
+ if (onCancel) {
129
+ onCancel();
130
+ }
131
+ }, [isDirty, onCancel]);
132
+
133
+ // Render loading state
134
+ if (isLoading && !data.id) {
135
+ return (
136
+ <div className="flex items-center justify-center p-8">
137
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500" />
138
+ <span className="ml-2 text-gray-600">Loading...</span>
139
+ </div>
140
+ );
141
+ }
142
+
143
+ // Render error state
144
+ if (error) {
145
+ return (
146
+ <div className="p-4 bg-red-50 border border-red-200 rounded-lg">
147
+ <div className="flex items-center">
148
+ <svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
149
+ <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
150
+ </svg>
151
+ <span className="ml-2 text-red-700">{error}</span>
152
+ </div>
153
+ <button
154
+ onClick={() => id && fetchData(id)}
155
+ className="mt-2 text-sm text-red-600 hover:text-red-800 underline"
156
+ >
157
+ Try again
158
+ </button>
159
+ </div>
160
+ );
161
+ }
162
+
163
+ return (
164
+ <div className="bg-white rounded-lg shadow-sm border border-gray-200">
165
+ {/* Header */}
166
+ <div className="px-6 py-4 border-b border-gray-200">
167
+ <h2 className="text-xl font-semibold text-gray-900">
168
+ {id ? 'Edit' : 'Create'} {{name}}
169
+ </h2>
170
+ {isDirty && (
171
+ <span className="text-sm text-amber-600">Unsaved changes</span>
172
+ )}
173
+ </div>
174
+
175
+ {/* Form */}
176
+ <form onSubmit={handleSubmit} className="p-6 space-y-6">
177
+ {/* TODO: Add form fields */}
178
+ <div className="text-gray-500 text-center py-8">
179
+ Add your form fields here
180
+ </div>
181
+
182
+ {/* Actions */}
183
+ {!readOnly && (
184
+ <div className="flex items-center justify-end gap-3 pt-4 border-t border-gray-200">
185
+ {onCancel && (
186
+ <button
187
+ type="button"
188
+ onClick={handleCancel}
189
+ disabled={isLoading}
190
+ className="px-4 py-2 text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50"
191
+ >
192
+ Cancel
193
+ </button>
194
+ )}
195
+ <button
196
+ type="submit"
197
+ disabled={isLoading || !isDirty}
198
+ className="px-4 py-2 text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
199
+ >
200
+ {isLoading ? 'Saving...' : 'Save'}
201
+ </button>
202
+ </div>
203
+ )}
204
+ </form>
205
+ </div>
206
+ );
207
+ };
208
+
209
+ export default {{name}};
210
+
211
+ // ============================================================================
212
+ // Hook
213
+ // ============================================================================
214
+
215
+ export interface Use{{name}}Options {
216
+ id?: string;
217
+ autoFetch?: boolean;
218
+ }
219
+
220
+ export function use{{name}}(options: Use{{name}}Options = {}) {
221
+ const { id, autoFetch = true } = options;
222
+
223
+ const [data, setData] = useState<{{name}}Data | null>(null);
224
+ const [loading, setLoading] = useState(false);
225
+ const [error, setError] = useState<Error | null>(null);
226
+
227
+ const fetch = useCallback(async (fetchId?: string) => {
228
+ const targetId = fetchId || id;
229
+ if (!targetId) return;
230
+
231
+ setLoading(true);
232
+ setError(null);
233
+
234
+ try {
235
+ // TODO: Implement API call
236
+ // const result = await {{nameCamel}}Api.getById(targetId);
237
+ // setData(result);
238
+ } catch (e) {
239
+ setError(e instanceof Error ? e : new Error('Unknown error'));
240
+ } finally {
241
+ setLoading(false);
242
+ }
243
+ }, [id]);
244
+
245
+ const save = useCallback(async (saveData: {{name}}Data) => {
246
+ setLoading(true);
247
+ setError(null);
248
+
249
+ try {
250
+ // TODO: Implement API call
251
+ // const result = saveData.id
252
+ // ? await {{nameCamel}}Api.update(saveData.id, saveData)
253
+ // : await {{nameCamel}}Api.create(saveData);
254
+ // setData(result);
255
+ // return result;
256
+ } catch (e) {
257
+ setError(e instanceof Error ? e : new Error('Unknown error'));
258
+ throw e;
259
+ } finally {
260
+ setLoading(false);
261
+ }
262
+ }, []);
263
+
264
+ const remove = useCallback(async (removeId?: string) => {
265
+ const targetId = removeId || id;
266
+ if (!targetId) return;
267
+
268
+ setLoading(true);
269
+ setError(null);
270
+
271
+ try {
272
+ // TODO: Implement API call
273
+ // await {{nameCamel}}Api.delete(targetId);
274
+ setData(null);
275
+ } catch (e) {
276
+ setError(e instanceof Error ? e : new Error('Unknown error'));
277
+ throw e;
278
+ } finally {
279
+ setLoading(false);
280
+ }
281
+ }, [id]);
282
+
283
+ useEffect(() => {
284
+ if (autoFetch && id) {
285
+ fetch();
286
+ }
287
+ }, [autoFetch, id, fetch]);
288
+
289
+ return {
290
+ data,
291
+ loading,
292
+ error,
293
+ fetch,
294
+ save,
295
+ remove,
296
+ setData,
297
+ };
298
+ }