@auto-engineer/frontend-implementer 0.1.4 → 0.8.1

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,5 @@
1
1
  {
2
2
  "name": "@auto-engineer/frontend-implementer",
3
- "version": "0.1.4",
4
3
  "type": "module",
5
4
  "main": "./dist/index.js",
6
5
  "types": "./dist/index.d.ts",
@@ -14,30 +13,31 @@
14
13
  "access": "public"
15
14
  },
16
15
  "dependencies": {
17
- "@auto-engineer/ai-gateway": "^0.6.3",
18
- "@auto-engineer/message-bus": "^0.5.5",
19
16
  "@modelcontextprotocol/sdk": "^1.3.0",
20
17
  "debug": "^4.4.1",
21
18
  "jsdom": "^26.1.0",
22
19
  "openai": "^5.7.0",
23
20
  "vite": "^5.4.1",
24
- "zod": "^3.25.67"
21
+ "zod": "^3.25.67",
22
+ "@auto-engineer/ai-gateway": "0.8.1",
23
+ "@auto-engineer/message-bus": "0.8.1"
25
24
  },
26
25
  "devDependencies": {
27
- "@auto-engineer/cli": "^0.7.6",
28
- "playwright": "^1.54.1"
26
+ "playwright": "^1.54.1",
27
+ "@auto-engineer/cli": "0.8.1"
29
28
  },
29
+ "version": "0.8.1",
30
30
  "scripts": {
31
31
  "start": "tsx src/index.ts",
32
- "build": "tsc && tsx ../../scripts/fix-esm-imports.ts",
32
+ "build": "tsc && tsx ../../scripts/fix-esm-imports.ts && cp src/*.html dist/src/ 2>/dev/null || true",
33
33
  "dev": "tsc --watch",
34
- "test": "vitest run",
34
+ "test": "vitest run --reporter=dot",
35
35
  "ai-agent": "tsx -r dotenv/config src/agent-cli.ts",
36
36
  "lint": "eslint 'src/**/*.ts' --max-warnings 0 --config ../../eslint.config.ts",
37
37
  "type-check": "tsc --noEmit",
38
- "format": "prettier --write \"**/*.{js,ts,json,md,yml,yaml}\" --ignore-path ../../.prettierignore",
38
+ "format": "prettier --write \"**/*.{js,ts,json,md,yml,yaml}\" --ignore-path ../../.prettierignore --log-level warn",
39
39
  "lint:fix": "eslint 'src/**/*.ts' --fix --config ../../eslint.config.ts",
40
- "format:fix": "prettier --write \"**/*.{js,ts,json,md,yml,yaml}\" --ignore-path ../../.prettierignore",
40
+ "format:fix": "prettier --write \"**/*.{js,ts,json,md,yml,yaml}\" --ignore-path ../../.prettierignore --log-level warn",
41
41
  "link:dev": "pnpm build && pnpm link --global",
42
42
  "unlink:dev": "pnpm unlink --global"
43
43
  }
package/src/agent.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AIProvider, generateTextWithAI } from '@auto-engineer/ai-gateway';
1
+ import { generateTextWithAI } from '@auto-engineer/ai-gateway';
2
2
  import * as fs from 'fs/promises';
3
3
  import * as path from 'path';
4
4
  import * as ts from 'typescript';
@@ -97,7 +97,7 @@ async function getAtomsWithProps(
97
97
  return atoms;
98
98
  }
99
99
 
100
- const provider = AIProvider.Anthropic;
100
+ const provider = undefined;
101
101
 
102
102
  function extractJsonArray(text: string): string {
103
103
  debugAI('Extracting JSON array from text of length: %d', text.length);
@@ -119,7 +119,7 @@ async function callAI(prompt: string, options?: { temperature?: number; maxToken
119
119
  const temperature = options?.temperature ?? 0.2;
120
120
  const maxTokens = options?.maxTokens ?? 4000;
121
121
  debugAI('Calling AI with prompt length: %d, temperature: %f, maxTokens: %d', prompt.length, temperature, maxTokens);
122
- const result = await generateTextWithAI(prompt, provider, { temperature, maxTokens });
122
+ const result = await generateTextWithAI(prompt, { provider, temperature, maxTokens });
123
123
  debugAI('AI response received, length: %d', result.length);
124
124
  return result.trim();
125
125
  }
@@ -695,7 +695,7 @@ async function checkVisualErrors(baseUrl: string, routes: string[], theme: strin
695
695
  IMPORTANT: return something only if you found valid errors, I don't want to show only the route name from the above request.
696
696
  `,
697
697
  screenshot.screenshot,
698
- AIProvider.OpenAI,
698
+ undefined,
699
699
  );
700
700
  if (error) {
701
701
  debugScreenshots('Visual errors found on route %s', screenshot.route);
@@ -1,22 +1,9 @@
1
- import { type CommandHandler, type Command, type Event } from '@auto-engineer/message-bus';
1
+ import { type Command, type Event, defineCommandHandler } from '@auto-engineer/message-bus';
2
2
  import { runAIAgent } from '../agent';
3
3
  import createDebug from 'debug';
4
4
 
5
5
  const debug = createDebug('frontend-implementer:implement-client');
6
6
 
7
- export const implementClientManifest = {
8
- handler: () => Promise.resolve({ default: implementClientCommandHandler }),
9
- description: 'AI implements client',
10
- usage: 'implement:client <client> <context> <principles> <design>',
11
- examples: ['$ auto implement:client ./client ./.context ./design-principles.md ./design-system.md'],
12
- args: [
13
- { name: 'client', description: 'Client directory path', required: true },
14
- { name: 'context', description: 'Context directory path', required: true },
15
- { name: 'principles', description: 'Design principles file', required: true },
16
- { name: 'design', description: 'Design system file', required: true },
17
- ],
18
- };
19
-
20
7
  export type ImplementClientCommand = Command<
21
8
  'ImplementClient',
22
9
  {
@@ -41,6 +28,41 @@ export type ClientImplementationFailedEvent = Event<
41
28
  }
42
29
  >;
43
30
 
31
+ export const commandHandler = defineCommandHandler<ImplementClientCommand>({
32
+ name: 'ImplementClient',
33
+ alias: 'implement:client',
34
+ description: 'AI implements client',
35
+ category: 'implement',
36
+ fields: {
37
+ projectDir: {
38
+ description: 'Client directory path',
39
+ required: true,
40
+ },
41
+ iaSchemeDir: {
42
+ description: 'Context directory path',
43
+ required: true,
44
+ },
45
+ designSystemPath: {
46
+ description: 'Design system file',
47
+ required: true,
48
+ },
49
+ },
50
+ examples: [
51
+ '$ auto implement:client --project-dir=./client --ia-scheme-dir=./.context --design-system-path=./design-system.md',
52
+ ],
53
+ handle: async (
54
+ command: ImplementClientCommand,
55
+ ): Promise<ClientImplementedEvent | ClientImplementationFailedEvent> => {
56
+ const result = await handleImplementClientCommandInternal(command);
57
+ if (result.type === 'ClientImplemented') {
58
+ debug('Client implemented successfully');
59
+ } else {
60
+ debug('Failed: %s', result.data.error);
61
+ }
62
+ return result;
63
+ },
64
+ });
65
+
44
66
  async function handleImplementClientCommandInternal(
45
67
  command: ImplementClientCommand,
46
68
  ): Promise<ClientImplementedEvent | ClientImplementationFailedEvent> {
@@ -78,23 +100,5 @@ async function handleImplementClientCommandInternal(
78
100
  }
79
101
  }
80
102
 
81
- export const implementClientCommandHandler: CommandHandler<
82
- ImplementClientCommand,
83
- ClientImplementedEvent | ClientImplementationFailedEvent
84
- > = {
85
- name: 'ImplementClient',
86
- handle: async (
87
- command: ImplementClientCommand,
88
- ): Promise<ClientImplementedEvent | ClientImplementationFailedEvent> => {
89
- const result = await handleImplementClientCommandInternal(command);
90
- if (result.type === 'ClientImplemented') {
91
- debug('Client implemented successfully');
92
- } else {
93
- debug('Failed: %s', result.data.error);
94
- }
95
- return result;
96
- },
97
- };
98
-
99
103
  // Default export is the command handler
100
- export default implementClientCommandHandler;
104
+ export default commandHandler;
package/src/index.ts CHANGED
@@ -1,321 +1,8 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import { z } from 'zod';
4
- import * as fs from 'fs/promises';
5
- import * as path from 'path';
6
- import createDebug from 'debug';
7
-
8
- const debug = createDebug('frontend-impl:mcp');
9
- const debugTools = createDebug('frontend-impl:mcp:tools');
10
- const debugServer = createDebug('frontend-impl:mcp:server');
11
- const debugLifecycle = createDebug('frontend-impl:mcp:lifecycle');
12
-
13
- interface Component {
14
- type: string;
15
- items?: Record<string, unknown>;
16
- }
17
-
18
- interface Scheme {
19
- generatedComponents?: Component[];
20
- atoms?: {
21
- description?: string;
22
- items?: Record<string, unknown>;
23
- };
24
- molecules?: {
25
- description?: string;
26
- items?: Record<string, unknown>;
27
- };
28
- organisms?: {
29
- description?: string;
30
- items?: Record<string, unknown>;
31
- };
32
- pages?: {
33
- description?: string;
34
- items?: Record<string, unknown>;
35
- };
36
- }
37
-
38
- // Helper to recursively list files
39
- async function listFiles(dir: string, base = dir): Promise<string[]> {
40
- const entries = await fs.readdir(dir, { withFileTypes: true });
41
- const files = await Promise.all(
42
- entries.map(async (entry) => {
43
- const res = path.resolve(dir, entry.name);
44
- if (entry.isDirectory()) {
45
- return listFiles(res, base);
46
- } else {
47
- return [path.relative(base, res)];
48
- }
49
- }),
50
- );
51
- return files.flat();
52
- }
53
-
54
- // Helper to read auto-ia-scheme.json
55
- async function readAutoIAScheme(directory: string): Promise<Scheme> {
56
- const filePath = path.join(directory, 'auto-ia-scheme.json');
57
- const content = await fs.readFile(filePath, 'utf-8');
58
- return JSON.parse(content) as Scheme;
59
- }
60
-
61
- function buildEntities(scheme: Scheme) {
62
- const entities = [];
63
- if (scheme.atoms) entities.push({ type: 'atoms', items: Object.keys(scheme.atoms.items ?? {}) });
64
- if (scheme.molecules) entities.push({ type: 'molecules', items: Object.keys(scheme.molecules.items ?? {}) });
65
- if (scheme.organisms) entities.push({ type: 'organisms', items: Object.keys(scheme.organisms.items ?? {}) });
66
- if (scheme.pages) entities.push({ type: 'pages', items: Object.keys(scheme.pages.items ?? {}) });
67
- return entities;
68
- }
69
-
70
- debugServer('Initializing MCP server with name: frontend-implementer, version: 0.1.0');
71
- const server = new McpServer({
72
- name: 'frontend-implementer',
73
- version: '0.1.0',
74
- });
75
- debugServer('MCP server instance created');
76
-
77
- // Tool: List all files in the project
78
- debugTools('Registering tool: listFiles');
79
- server.registerTool(
80
- 'listFiles',
81
- {
82
- title: 'List Project Files',
83
- description: 'List all files in the given project directory.',
84
- inputSchema: {
85
- directory: z.string().min(1, 'Directory is required'),
86
- },
87
- },
88
- async ({ directory }: { directory: string }) => {
89
- debugTools('listFiles called with directory: %s', directory);
90
- try {
91
- const files = await listFiles(directory);
92
- debugTools('Found %d files in directory', files.length);
93
- return {
94
- content: [
95
- {
96
- type: 'text',
97
- text: JSON.stringify(files, null, 2),
98
- },
99
- ],
100
- };
101
- } catch (error) {
102
- debugTools('Error listing files: %O', error);
103
- return {
104
- isError: true,
105
- content: [
106
- {
107
- type: 'text',
108
- text: `Error listing files: ${error instanceof Error ? error.message : String(error)}`,
109
- },
110
- ],
111
- };
112
- }
113
- },
114
- );
115
-
116
- // Tool: Read a file
117
- debugTools('Registering tool: readFile');
118
- server.registerTool(
119
- 'readFile',
120
- {
121
- title: 'Read File',
122
- description: 'Read the contents of a file in the project.',
123
- inputSchema: {
124
- directory: z.string().min(1, 'Directory is required'),
125
- relativePath: z.string().min(1, 'Relative file path is required'),
126
- },
127
- },
128
- async ({ directory, relativePath }: { directory: string; relativePath: string }) => {
129
- debugTools('readFile called - directory: %s, relativePath: %s', directory, relativePath);
130
- try {
131
- const filePath = path.join(directory, relativePath);
132
- debugTools('Reading file from: %s', filePath);
133
- const content = await fs.readFile(filePath, 'utf-8');
134
- debugTools('File read successfully, size: %d bytes', content.length);
135
- return {
136
- content: [
137
- {
138
- type: 'text',
139
- text: content,
140
- },
141
- ],
142
- };
143
- } catch (error) {
144
- debugTools('Error reading file: %O', error);
145
- return {
146
- isError: true,
147
- content: [
148
- {
149
- type: 'text',
150
- text: `Error reading file: ${error instanceof Error ? error.message : String(error)}`,
151
- },
152
- ],
153
- };
154
- }
155
- },
156
- );
157
-
158
- // Tool: Create or update a file
159
- debugTools('Registering tool: createOrUpdateFile');
160
- server.registerTool(
161
- 'createOrUpdateFile',
162
- {
163
- title: 'Create or Update File',
164
- description: 'Create or overwrite a file in the given React project directory.',
165
- inputSchema: {
166
- directory: z.string().min(1, 'Directory is required'),
167
- relativePath: z.string().min(1, 'Relative file path is required'),
168
- content: z.string().min(1, 'File content is required'),
169
- },
170
- },
171
- async ({ directory, relativePath, content }: { directory: string; relativePath: string; content: string }) => {
172
- debugTools(
173
- 'createOrUpdateFile called - directory: %s, relativePath: %s, content size: %d',
174
- directory,
175
- relativePath,
176
- content.length,
177
- );
178
- try {
179
- const filePath = path.join(directory, relativePath);
180
- debugTools('Writing file to: %s', filePath);
181
- await fs.mkdir(path.dirname(filePath), { recursive: true });
182
- await fs.writeFile(filePath, content, 'utf-8');
183
- debugTools('File written successfully');
184
- return {
185
- content: [
186
- {
187
- type: 'text',
188
- text: `File created/updated: ${filePath}`,
189
- },
190
- ],
191
- };
192
- } catch (error) {
193
- debugTools('Error creating/updating file: %O', error);
194
- return {
195
- isError: true,
196
- content: [
197
- {
198
- type: 'text',
199
- text: `Error creating/updating file: ${error instanceof Error ? error.message : String(error)}`,
200
- },
201
- ],
202
- };
203
- }
204
- },
205
- );
206
-
207
- // Tool: Read auto-ia-scheme.json
208
- debugTools('Registering tool: readAutoIAScheme');
209
- server.registerTool(
210
- 'readAutoIAScheme',
211
- {
212
- title: 'Read auto-ia-scheme.json',
213
- description: 'Read and return the parsed auto-ia-scheme.json from the project root.',
214
- inputSchema: {
215
- directory: z.string().min(1, 'Directory is required'),
216
- },
217
- },
218
- async ({ directory }: { directory: string }) => {
219
- debugTools('readAutoIAScheme called with directory: %s', directory);
220
- try {
221
- const scheme = await readAutoIAScheme(directory);
222
- debugTools('IA scheme loaded successfully');
223
- return {
224
- content: [
225
- {
226
- type: 'text',
227
- text: JSON.stringify(scheme, null, 2),
228
- },
229
- ],
230
- };
231
- } catch (error) {
232
- debugTools('Error reading auto-ia-scheme.json: %O', error);
233
- return {
234
- isError: true,
235
- content: [
236
- {
237
- type: 'text',
238
- text: `Error reading auto-ia-scheme.json: ${error instanceof Error ? error.message : String(error)}`,
239
- },
240
- ],
241
- };
242
- }
243
- },
244
- );
245
-
246
- // Tool: List entities from auto-ia-scheme.json
247
- debugTools('Registering tool: listAutoIASchemeEntities');
248
- server.registerTool(
249
- 'listAutoIASchemeEntities',
250
- {
251
- title: 'List Entities from auto-ia-scheme.json',
252
- description: 'List all atoms, molecules, organisms, and pages defined in auto-ia-scheme.json.',
253
- inputSchema: {
254
- directory: z.string().min(1, 'Directory is required'),
255
- },
256
- },
257
- async ({ directory }: { directory: string }) => {
258
- try {
259
- const scheme = await readAutoIAScheme(directory);
260
- const entities = buildEntities(scheme);
261
- return {
262
- content: [
263
- {
264
- type: 'text',
265
- text: JSON.stringify(entities, null, 2),
266
- },
267
- ],
268
- };
269
- } catch (error) {
270
- return {
271
- isError: true,
272
- content: [
273
- {
274
- type: 'text',
275
- text: `Error listing entities: ${error instanceof Error ? error.message : String(error)}`,
276
- },
277
- ],
278
- };
279
- }
280
- },
281
- );
282
-
283
- const transport = new StdioServerTransport();
284
-
285
- async function cleanup() {
286
- debug('Cleanup initiated');
287
- console.log('Cleaning up...');
288
- await transport.close();
289
- debug('Transport closed, exiting process');
290
- process.exit(0);
291
- }
292
-
293
- process.on('SIGTERM', () => {
294
- void cleanup();
295
- });
296
- process.on('SIGINT', () => {
297
- void cleanup();
298
- });
299
-
300
- async function startServer() {
301
- debugLifecycle('Starting MCP server');
302
- debugServer('Connecting server to transport');
303
- await server.connect(transport);
304
- console.error('Frontend Implementation MCP Server running on stdio');
305
- debugLifecycle('MCP server connected and running');
306
- debugServer('Server ready to handle requests');
307
- }
308
-
309
- // Only start the server if this file is run directly
310
- if (process.argv[1] && import.meta.url === `file://${process.argv[1]}`) {
311
- debugLifecycle('Running as main module, starting server');
312
- startServer().catch((error) => {
313
- debugLifecycle('Fatal error starting server: %O', error);
314
- console.error(error);
315
- });
316
- } else {
317
- debugLifecycle('Module imported, not starting MCP server');
318
- }
319
-
320
- export * from './commands/implement-client';
321
- export { CLI_MANIFEST } from './cli-manifest';
1
+ // Command exports
2
+ import { commandHandler as implementClientHandler } from './commands/implement-client.js';
3
+ export const COMMANDS = [implementClientHandler];
4
+ export {
5
+ type ImplementClientCommand,
6
+ type ClientImplementedEvent,
7
+ type ClientImplementationFailedEvent,
8
+ } from './commands/implement-client.js';