fastmode-mcp 1.0.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.
Files changed (67) hide show
  1. package/README.md +561 -0
  2. package/bin/run.js +50 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +802 -0
  6. package/dist/lib/api-client.d.ts +81 -0
  7. package/dist/lib/api-client.d.ts.map +1 -0
  8. package/dist/lib/api-client.js +237 -0
  9. package/dist/lib/auth-state.d.ts +13 -0
  10. package/dist/lib/auth-state.d.ts.map +1 -0
  11. package/dist/lib/auth-state.js +24 -0
  12. package/dist/lib/context-fetcher.d.ts +67 -0
  13. package/dist/lib/context-fetcher.d.ts.map +1 -0
  14. package/dist/lib/context-fetcher.js +190 -0
  15. package/dist/lib/credentials.d.ts +52 -0
  16. package/dist/lib/credentials.d.ts.map +1 -0
  17. package/dist/lib/credentials.js +196 -0
  18. package/dist/lib/device-flow.d.ts +14 -0
  19. package/dist/lib/device-flow.d.ts.map +1 -0
  20. package/dist/lib/device-flow.js +244 -0
  21. package/dist/tools/cms-items.d.ts +56 -0
  22. package/dist/tools/cms-items.d.ts.map +1 -0
  23. package/dist/tools/cms-items.js +376 -0
  24. package/dist/tools/create-site.d.ts +9 -0
  25. package/dist/tools/create-site.d.ts.map +1 -0
  26. package/dist/tools/create-site.js +202 -0
  27. package/dist/tools/deploy-package.d.ts +9 -0
  28. package/dist/tools/deploy-package.d.ts.map +1 -0
  29. package/dist/tools/deploy-package.js +434 -0
  30. package/dist/tools/generate-samples.d.ts +19 -0
  31. package/dist/tools/generate-samples.d.ts.map +1 -0
  32. package/dist/tools/generate-samples.js +272 -0
  33. package/dist/tools/get-conversion-guide.d.ts +7 -0
  34. package/dist/tools/get-conversion-guide.d.ts.map +1 -0
  35. package/dist/tools/get-conversion-guide.js +1323 -0
  36. package/dist/tools/get-example.d.ts +7 -0
  37. package/dist/tools/get-example.d.ts.map +1 -0
  38. package/dist/tools/get-example.js +1568 -0
  39. package/dist/tools/get-field-types.d.ts +30 -0
  40. package/dist/tools/get-field-types.d.ts.map +1 -0
  41. package/dist/tools/get-field-types.js +154 -0
  42. package/dist/tools/get-schema.d.ts +5 -0
  43. package/dist/tools/get-schema.d.ts.map +1 -0
  44. package/dist/tools/get-schema.js +320 -0
  45. package/dist/tools/get-started.d.ts +21 -0
  46. package/dist/tools/get-started.d.ts.map +1 -0
  47. package/dist/tools/get-started.js +624 -0
  48. package/dist/tools/get-tenant-schema.d.ts +18 -0
  49. package/dist/tools/get-tenant-schema.d.ts.map +1 -0
  50. package/dist/tools/get-tenant-schema.js +158 -0
  51. package/dist/tools/list-projects.d.ts +5 -0
  52. package/dist/tools/list-projects.d.ts.map +1 -0
  53. package/dist/tools/list-projects.js +101 -0
  54. package/dist/tools/sync-schema.d.ts +41 -0
  55. package/dist/tools/sync-schema.d.ts.map +1 -0
  56. package/dist/tools/sync-schema.js +483 -0
  57. package/dist/tools/validate-manifest.d.ts +5 -0
  58. package/dist/tools/validate-manifest.d.ts.map +1 -0
  59. package/dist/tools/validate-manifest.js +311 -0
  60. package/dist/tools/validate-package.d.ts +5 -0
  61. package/dist/tools/validate-package.d.ts.map +1 -0
  62. package/dist/tools/validate-package.js +337 -0
  63. package/dist/tools/validate-template.d.ts +12 -0
  64. package/dist/tools/validate-template.d.ts.map +1 -0
  65. package/dist/tools/validate-template.js +790 -0
  66. package/package.json +54 -0
  67. package/scripts/postinstall.js +129 -0
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ /**
3
+ * Generate Sample Items Tool
4
+ *
5
+ * Generates sample items for collections with automatic dependency ordering.
6
+ * Handles relation fields by generating parent collections first.
7
+ * Requires authentication.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.generateSampleItems = generateSampleItems;
11
+ const api_client_1 = require("../lib/api-client");
12
+ const device_flow_1 = require("../lib/device-flow");
13
+ // ============ Constants ============
14
+ const AUTH_REQUIRED_MESSAGE = `# Authentication Required
15
+
16
+ This tool requires authentication to generate sample items.
17
+
18
+ **To authenticate:**
19
+ 1. Set the FASTMODE_AUTH_TOKEN environment variable, OR
20
+ 2. Run this tool again and follow the browser-based login flow
21
+
22
+ Use \`list_projects\` to verify your authentication status.
23
+ `;
24
+ // ============ Helper Functions ============
25
+ /**
26
+ * Resolve project identifier to tenant ID
27
+ */
28
+ async function resolveProjectId(projectIdentifier) {
29
+ const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
30
+ if (uuidPattern.test(projectIdentifier)) {
31
+ return { tenantId: projectIdentifier };
32
+ }
33
+ const response = await (0, api_client_1.apiRequest)('/api/tenants');
34
+ if ((0, api_client_1.isApiError)(response)) {
35
+ return { error: `Failed to look up project: ${response.error}` };
36
+ }
37
+ const match = response.data.find(p => p.name.toLowerCase() === projectIdentifier.toLowerCase());
38
+ if (match) {
39
+ return { tenantId: match.id };
40
+ }
41
+ const partialMatch = response.data.find(p => p.name.toLowerCase().includes(projectIdentifier.toLowerCase()));
42
+ if (partialMatch) {
43
+ return { tenantId: partialMatch.id };
44
+ }
45
+ return {
46
+ error: `Project "${projectIdentifier}" not found. Use list_projects to see available projects.`
47
+ };
48
+ }
49
+ /**
50
+ * Topological sort of collections based on relation dependencies
51
+ * Returns collections ordered so that dependencies come first
52
+ */
53
+ function sortByDependencies(collections) {
54
+ const slugToCollection = new Map();
55
+ const inDegree = new Map();
56
+ const adjacencyList = new Map();
57
+ // Initialize
58
+ for (const col of collections) {
59
+ slugToCollection.set(col.slug, col);
60
+ inDegree.set(col.slug, 0);
61
+ adjacencyList.set(col.slug, []);
62
+ }
63
+ // Build dependency graph
64
+ // If collection A has a relation to collection B, then B must be populated first
65
+ // So B -> A (B is a dependency of A)
66
+ for (const col of collections) {
67
+ for (const field of col.fields) {
68
+ if (field.type === 'relation' && field.referenceCollection) {
69
+ const refSlug = field.referenceCollection;
70
+ // Only count if the referenced collection is in our list
71
+ if (slugToCollection.has(refSlug)) {
72
+ // refSlug must come before col.slug
73
+ const deps = adjacencyList.get(refSlug) || [];
74
+ deps.push(col.slug);
75
+ adjacencyList.set(refSlug, deps);
76
+ inDegree.set(col.slug, (inDegree.get(col.slug) || 0) + 1);
77
+ }
78
+ }
79
+ }
80
+ }
81
+ // Kahn's algorithm for topological sort
82
+ const queue = [];
83
+ const result = [];
84
+ // Start with nodes that have no dependencies
85
+ for (const [slug, degree] of inDegree) {
86
+ if (degree === 0) {
87
+ queue.push(slug);
88
+ }
89
+ }
90
+ while (queue.length > 0) {
91
+ const current = queue.shift();
92
+ const col = slugToCollection.get(current);
93
+ if (col) {
94
+ result.push(col);
95
+ }
96
+ // Reduce in-degree for dependent collections
97
+ const dependents = adjacencyList.get(current) || [];
98
+ for (const dep of dependents) {
99
+ const newDegree = (inDegree.get(dep) || 0) - 1;
100
+ inDegree.set(dep, newDegree);
101
+ if (newDegree === 0) {
102
+ queue.push(dep);
103
+ }
104
+ }
105
+ }
106
+ // If there are still collections not in result (cycle detected), add them anyway
107
+ for (const col of collections) {
108
+ if (!result.find(c => c.slug === col.slug)) {
109
+ result.push(col);
110
+ }
111
+ }
112
+ return result;
113
+ }
114
+ // ============ Main Function ============
115
+ /**
116
+ * Generate sample items for collections
117
+ *
118
+ * @param input - The input with projectId and optional collectionSlugs
119
+ */
120
+ async function generateSampleItems(input) {
121
+ // Check authentication
122
+ if (await (0, api_client_1.needsAuthentication)()) {
123
+ const authResult = await (0, device_flow_1.ensureAuthenticated)();
124
+ if (!authResult.authenticated) {
125
+ return AUTH_REQUIRED_MESSAGE;
126
+ }
127
+ }
128
+ const { projectId, collectionSlugs } = input;
129
+ // Validate input
130
+ if (!projectId) {
131
+ return `# Error: Missing projectId
132
+
133
+ Please provide a projectId. Use \`list_projects\` to see your available projects.
134
+ `;
135
+ }
136
+ // Resolve project ID
137
+ const resolved = await resolveProjectId(projectId);
138
+ if ('error' in resolved) {
139
+ return `# Project Not Found
140
+
141
+ ${resolved.error}
142
+ `;
143
+ }
144
+ const { tenantId } = resolved;
145
+ // Fetch all collections for this project
146
+ const collectionsRes = await (0, api_client_1.apiRequest)('/api/collections', { tenantId });
147
+ if ((0, api_client_1.isApiError)(collectionsRes)) {
148
+ // Check if auth error
149
+ if (collectionsRes.error.includes('401') || collectionsRes.error.includes('auth')) {
150
+ const authResult = await (0, device_flow_1.ensureAuthenticated)();
151
+ if (!authResult.authenticated) {
152
+ return AUTH_REQUIRED_MESSAGE;
153
+ }
154
+ }
155
+ return `# Error
156
+
157
+ Failed to fetch collections: ${collectionsRes.error}
158
+ `;
159
+ }
160
+ const allCollections = collectionsRes.data;
161
+ if (allCollections.length === 0) {
162
+ return `# No Collections Found
163
+
164
+ This project has no collections yet. Use \`sync_schema\` to create collections first.
165
+ `;
166
+ }
167
+ // Determine which collections to generate samples for
168
+ let targetCollections;
169
+ if (collectionSlugs && collectionSlugs.length > 0) {
170
+ // Specific collections requested
171
+ targetCollections = [];
172
+ const notFound = [];
173
+ for (const slug of collectionSlugs) {
174
+ const col = allCollections.find(c => c.slug.toLowerCase() === slug.toLowerCase());
175
+ if (col) {
176
+ targetCollections.push(col);
177
+ }
178
+ else {
179
+ notFound.push(slug);
180
+ }
181
+ }
182
+ if (notFound.length > 0) {
183
+ return `# Collections Not Found
184
+
185
+ The following collections were not found: ${notFound.join(', ')}
186
+
187
+ Available collections: ${allCollections.map(c => c.slug).join(', ')}
188
+ `;
189
+ }
190
+ }
191
+ else {
192
+ // All collections - check which ones are empty
193
+ const emptyCollections = [];
194
+ for (const col of allCollections) {
195
+ const itemsRes = await (0, api_client_1.apiRequest)(`/api/collections/${col.id}/items`, { tenantId });
196
+ if (!(0, api_client_1.isApiError)(itemsRes) && itemsRes.data.length === 0) {
197
+ emptyCollections.push(col);
198
+ }
199
+ }
200
+ if (emptyCollections.length === 0) {
201
+ return `# No Empty Collections
202
+
203
+ All collections already have items. To regenerate samples for specific collections, provide their slugs.
204
+
205
+ Collections with items: ${allCollections.map(c => c.slug).join(', ')}
206
+ `;
207
+ }
208
+ targetCollections = emptyCollections;
209
+ }
210
+ // Sort collections by dependencies (parents first)
211
+ const sortedCollections = sortByDependencies(targetCollections);
212
+ // Generate samples for each collection in order
213
+ const results = [];
214
+ const generated = [];
215
+ const failed = [];
216
+ results.push('## Generation Order\n');
217
+ results.push('Collections are processed in dependency order (parent collections first):\n');
218
+ results.push(sortedCollections.map((c, i) => `${i + 1}. ${c.name} (\`${c.slug}\`)`).join('\n'));
219
+ results.push('\n');
220
+ for (const col of sortedCollections) {
221
+ // Check for relation fields and their dependencies
222
+ const relationFields = col.fields.filter(f => f.type === 'relation' && f.referenceCollection);
223
+ const dependencies = relationFields.map(f => f.referenceCollection).filter(Boolean);
224
+ let dependencyNote = '';
225
+ if (dependencies.length > 0) {
226
+ dependencyNote = ` (depends on: ${dependencies.join(', ')})`;
227
+ }
228
+ // Call the generate-samples endpoint
229
+ const generateRes = await (0, api_client_1.apiRequest)(`/api/collections/${col.id}/generate-samples`, {
230
+ tenantId,
231
+ method: 'POST',
232
+ });
233
+ if ((0, api_client_1.isApiError)(generateRes)) {
234
+ failed.push({ collection: col.slug, error: generateRes.error });
235
+ results.push(`❌ **${col.name}** - Failed: ${generateRes.error}${dependencyNote}`);
236
+ }
237
+ else {
238
+ const count = generateRes.data.data?.length || 5;
239
+ generated.push({ collection: col.slug, count });
240
+ results.push(`✅ **${col.name}** - Generated ${count} sample items${dependencyNote}`);
241
+ }
242
+ }
243
+ // Build summary
244
+ let output = `# Sample Items Generated
245
+
246
+ **Project ID:** \`${tenantId}\`
247
+
248
+ ## Summary
249
+
250
+ | Metric | Count |
251
+ |--------|-------|
252
+ | Collections Processed | ${sortedCollections.length} |
253
+ | Successfully Generated | ${generated.length} |
254
+ | Failed | ${failed.length} |
255
+
256
+ ${results.join('\n')}
257
+ `;
258
+ if (failed.length > 0) {
259
+ output += `\n## Errors\n\n`;
260
+ for (const f of failed) {
261
+ output += `- **${f.collection}**: ${f.error}\n`;
262
+ }
263
+ }
264
+ if (generated.length > 0) {
265
+ output += `\n---\n\n**Next Steps:**
266
+ - View the generated items in the CMS dashboard
267
+ - Edit or delete sample items as needed
268
+ - These are placeholder items - replace with real content when ready
269
+ `;
270
+ }
271
+ return output;
272
+ }
@@ -0,0 +1,7 @@
1
+ type Section = 'full' | 'first_steps' | 'analysis' | 'structure' | 'seo' | 'manifest' | 'templates' | 'tokens' | 'forms' | 'assets' | 'checklist' | 'common_mistakes';
2
+ /**
3
+ * Returns the conversion guide, either full or a specific section
4
+ */
5
+ export declare function getConversionGuide(section: Section): Promise<string>;
6
+ export {};
7
+ //# sourceMappingURL=get-conversion-guide.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-conversion-guide.d.ts","sourceRoot":"","sources":["../../src/tools/get-conversion-guide.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,WAAW,GAAG,KAAK,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,iBAAiB,CAAC;AAotCtK;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CA+F1E"}