zelune 1.6.2 → 1.6.4

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 (39) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/bin/cli.mjs +13 -54
  3. package/dist/assets/CheckoutScreen-6IdrpKgm.js +229 -0
  4. package/dist/assets/HomeScreen-Dxe9L4I2.js +316 -0
  5. package/dist/assets/LoginScreen-Dp1awI4F.js +189 -0
  6. package/dist/assets/ProductDetailScreen-Wa5_nlRP.js +196 -0
  7. package/dist/assets/ProfileScreen-riAU6vVh.js +185 -0
  8. package/dist/assets/index-hEzd4JVy.js +44697 -0
  9. package/{index.html → dist/index.html} +3 -7
  10. package/mcp/server.mjs +1370 -34
  11. package/package.json +10 -17
  12. package/plugin.json +1 -1
  13. package/socket.yml +11 -0
  14. package/mcp/server.ts +0 -446
  15. package/plugins/viteReactNativeFallbackPlugin.ts +0 -519
  16. package/plugins/viteRnSourceInject.ts +0 -117
  17. package/plugins/viteVirtualScreensPlugin.ts +0 -216
  18. package/src/canvas/CanvasApp.tsx +0 -1655
  19. package/src/canvas/FlowArrowsLayer.tsx +0 -239
  20. package/src/canvas/InspectorPanel.tsx +0 -1494
  21. package/src/canvas/ScreenArtboard.tsx +0 -1491
  22. package/src/canvas/types.ts +0 -23
  23. package/src/main.tsx +0 -80
  24. package/src/runtime/MockNavigationContext.tsx +0 -1795
  25. package/src/runtime/ScreenErrorBoundary.tsx +0 -86
  26. package/src/runtime/nativewindShim.ts +0 -997
  27. package/src/runtime/reactNativeShim.ts +0 -240
  28. package/src/screens/CheckoutScreen.tsx +0 -229
  29. package/src/screens/HomeScreen.tsx +0 -288
  30. package/src/screens/LoginScreen.tsx +0 -176
  31. package/src/screens/ProductDetailScreen.tsx +0 -207
  32. package/src/screens/ProfileScreen.tsx +0 -172
  33. package/src/screens/index.ts +0 -1
  34. package/src/server/apiMiddleware.ts +0 -375
  35. package/src/server/astEngine.ts +0 -2553
  36. package/src/vite-env.d.ts +0 -7
  37. package/tsconfig.json +0 -23
  38. package/vite.config.ts +0 -340
  39. /package/{src/styles.css → dist/assets/index-C7nrS82N.css} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zelune",
3
- "version": "1.6.2",
3
+ "version": "1.6.4",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,17 +29,14 @@
29
29
  },
30
30
  "files": [
31
31
  "bin/",
32
- "src/",
33
- "plugins/",
34
- "mcp/",
32
+ "dist/",
33
+ "mcp/server.mjs",
35
34
  "skills/",
36
35
  "rules/",
37
36
  "assets/",
38
- "index.html",
39
- "vite.config.ts",
40
- "tsconfig.json",
41
37
  "plugin.json",
42
38
  "mcp_config.json",
39
+ "socket.yml",
43
40
  "PRODUCT.md",
44
41
  "DESIGN.md",
45
42
  "README.md",
@@ -49,7 +46,7 @@
49
46
  "dev": "vite --host 127.0.0.1 --port 5173",
50
47
  "zelune": "node ./bin/cli.mjs",
51
48
  "canvas": "node ./bin/cli.mjs",
52
- "build": "vite build",
49
+ "build": "vite build --mode development",
53
50
  "preview": "vite preview --host 127.0.0.1 --port 4173",
54
51
  "test": "vitest run",
55
52
  "mcp": "node ./bin/cli.mjs --mcp"
@@ -57,22 +54,18 @@
57
54
  "dependencies": {
58
55
  "@babel/generator": "^7.25.0",
59
56
  "@babel/parser": "^7.25.0",
60
- "@babel/traverse": "^7.25.0",
61
- "@babel/types": "^7.25.0",
62
- "@vitejs/plugin-react": "^4.7.0",
63
- "lucide-react": "^0.454.0",
64
- "react": "^18.3.1",
65
- "react-dom": "^18.3.1",
66
- "react-native-web": "^0.19.12",
67
- "vite": "6.4.4"
57
+ "@babel/types": "^7.25.0"
68
58
  },
69
59
  "devDependencies": {
70
60
  "@types/babel__generator": "^7.6.8",
71
- "@types/babel__traverse": "^7.20.6",
72
61
  "@types/node": "^22.0.0",
73
62
  "@types/react": "^18.3.11",
74
63
  "@types/react-dom": "^18.3.1",
64
+ "lucide-react": "^0.454.0",
65
+ "react": "^18.3.1",
66
+ "react-dom": "^18.3.1",
75
67
  "typescript": "^5.6.2",
68
+ "vite": "6.4.4",
76
69
  "vitest": "^2.1.2"
77
70
  }
78
71
  }
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zelune",
3
3
  "displayName": "Zelune — React Native Visual Canvas",
4
- "version": "1.6.2",
4
+ "version": "1.6.4",
5
5
  "description": "Zelune MCP & Figma-style multi-screen React Native visual canvas with live surgical AST patching and navigation flow visualization for Google Antigravity.",
6
6
  "logo": "assets/logo.svg",
7
7
  "suggestedPrompts": [
package/socket.yml ADDED
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ projectIgnorePaths:
3
+ - "tests/**"
4
+ - "dist/**"
5
+ issueRules:
6
+ fsAccess:
7
+ action: ignore
8
+ envVars:
9
+ action: ignore
10
+ networkAccess:
11
+ action: ignore
package/mcp/server.ts DELETED
@@ -1,446 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import readline from 'node:readline';
4
- import { fileURLToPath, pathToFileURL } from 'node:url';
5
- import {
6
- discoverScreens,
7
- inspectElement,
8
- patchElement,
9
- reorderElement,
10
- insertElement,
11
- duplicateElement,
12
- deleteElement,
13
- type InsertElementPreset,
14
- type StyleValue,
15
- } from '../src/server/astEngine.js';
16
-
17
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
- const DEFAULT_WORKSPACE_ROOT = path.resolve(__dirname, '..');
19
-
20
- export interface JsonRpcRequest {
21
- jsonrpc?: string;
22
- id?: string | number | null;
23
- method?: string;
24
- params?: Record<string, unknown>;
25
- }
26
-
27
- export interface JsonRpcResponse {
28
- jsonrpc: '2.0';
29
- id: string | number | null;
30
- result?: unknown;
31
- error?: {
32
- code: number;
33
- message: string;
34
- };
35
- }
36
-
37
- export const MCP_TOOLS = [
38
- {
39
- name: 'list_canvas_screens',
40
- description:
41
- 'Lists all discovered React Native screens on the visual canvas along with their element counts and outgoing navigation flow edges.',
42
- inputSchema: {
43
- type: 'object',
44
- properties: {},
45
- },
46
- },
47
- {
48
- name: 'inspect_screen_element',
49
- description:
50
- 'Inspects a specific JSX element inside a React Native screen by its relative file path and AST index path.',
51
- inputSchema: {
52
- type: 'object',
53
- properties: {
54
- file: {
55
- type: 'string',
56
- description: 'Relative path to the screen file (e.g. src/screens/HomeScreen.tsx)',
57
- },
58
- astPath: {
59
- type: 'string',
60
- description: 'Preorder AST index of the JSX element (e.g. "0", "4")',
61
- },
62
- },
63
- required: ['file', 'astPath'],
64
- },
65
- },
66
- {
67
- name: 'patch_screen_element',
68
- description:
69
- 'Surgically patches the text copy or StyleSheet properties of a React Native JSX element.',
70
- inputSchema: {
71
- type: 'object',
72
- properties: {
73
- file: {
74
- type: 'string',
75
- description: 'Relative path to the screen file (e.g. src/screens/HomeScreen.tsx)',
76
- },
77
- astPath: {
78
- type: 'string',
79
- description: 'Preorder AST index of the JSX element',
80
- },
81
- text: {
82
- type: 'string',
83
- description: 'Optional new static text content for <Text> elements',
84
- },
85
- styles: {
86
- type: 'object',
87
- description: 'Optional map of React Native style properties to update',
88
- },
89
- },
90
- required: ['file', 'astPath'],
91
- },
92
- },
93
- {
94
- name: 'reorder_screen_element',
95
- description:
96
- 'Surgically reorders a React Native JSX element among its Flexbox siblings in the .tsx AST.',
97
- inputSchema: {
98
- type: 'object',
99
- properties: {
100
- file: {
101
- type: 'string',
102
- description: 'Relative path to the screen file (e.g. src/screens/HomeScreen.tsx)',
103
- },
104
- astPath: {
105
- type: 'string',
106
- description: 'Preorder AST index of the JSX element to move',
107
- },
108
- direction: {
109
- type: 'string',
110
- enum: ['up', 'down'],
111
- description: 'Optional relative direction ("up" or "down") among siblings',
112
- },
113
- targetAstPath: {
114
- type: 'string',
115
- description: 'Optional AST index of the sibling to place before/after',
116
- },
117
- placement: {
118
- type: 'string',
119
- enum: ['before', 'after'],
120
- description: 'Whether to insert before or after targetAstPath',
121
- },
122
- },
123
- required: ['file', 'astPath'],
124
- },
125
- },
126
- {
127
- name: 'insert_screen_element',
128
- description:
129
- 'Surgically inserts a new React Native component/section preset (button, section, row, heading, text, input, badge, divider) into a screen .tsx AST and auto-injects required react-native imports.',
130
- inputSchema: {
131
- type: 'object',
132
- properties: {
133
- file: {
134
- type: 'string',
135
- description: 'Relative path to the screen file (e.g. src/screens/HomeScreen.tsx)',
136
- },
137
- astPath: {
138
- type: 'string',
139
- description: 'Optional AST index of the reference JSX element',
140
- },
141
- placement: {
142
- type: 'string',
143
- enum: ['inside', 'after', 'before'],
144
- description: 'Placement relative to astPath (defaults to "after" or "inside")',
145
- },
146
- preset: {
147
- type: 'string',
148
- enum: ['button', 'section', 'row', 'heading', 'text', 'input', 'badge', 'divider'],
149
- description: 'Component preset to insert',
150
- },
151
- label: {
152
- type: 'string',
153
- description: 'Optional custom label/text/placeholder for the inserted component',
154
- },
155
- navigateTo: {
156
- type: 'string',
157
- description: 'Optional target screen ID if inserting a navigation button',
158
- },
159
- },
160
- required: ['file', 'preset'],
161
- },
162
- },
163
- {
164
- name: 'duplicate_screen_element',
165
- description: 'Duplicates a JSX element right after itself in the screen .tsx AST.',
166
- inputSchema: {
167
- type: 'object',
168
- properties: {
169
- file: { type: 'string' },
170
- astPath: { type: 'string' },
171
- },
172
- required: ['file', 'astPath'],
173
- },
174
- },
175
- {
176
- name: 'delete_screen_element',
177
- description: 'Deletes a non-root JSX element from the screen .tsx AST.',
178
- inputSchema: {
179
- type: 'object',
180
- properties: {
181
- file: { type: 'string' },
182
- astPath: { type: 'string' },
183
- },
184
- required: ['file', 'astPath'],
185
- },
186
- },
187
- ];
188
-
189
- async function executeMcpTool(
190
- workspaceRoot: string,
191
- name: string,
192
- args: Record<string, unknown> | undefined
193
- ): Promise<{ content: Array<{ type: 'text'; text: string }> }> {
194
- if (name === 'list_canvas_screens') {
195
- const screens = await discoverScreens(workspaceRoot);
196
- return {
197
- content: [{ type: 'text', text: JSON.stringify(screens, null, 2) }],
198
- };
199
- }
200
-
201
- if (name === 'inspect_screen_element') {
202
- const file = String(args?.file ?? '');
203
- const astPath = String(args?.astPath ?? '0');
204
- const element = await inspectElement(workspaceRoot, { file, astPath });
205
- return {
206
- content: [{ type: 'text', text: JSON.stringify(element, null, 2) }],
207
- };
208
- }
209
-
210
- if (name === 'patch_screen_element') {
211
- const file = String(args?.file ?? '');
212
- const astPath = String(args?.astPath ?? '0');
213
- const text = typeof args?.text === 'string' ? args.text : undefined;
214
- const styles = (args?.styles as Record<string, StyleValue> | undefined) ?? undefined;
215
-
216
- const result = await patchElement(workspaceRoot, {
217
- file,
218
- astPath,
219
- text,
220
- styles,
221
- });
222
- return {
223
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
224
- };
225
- }
226
-
227
- if (name === 'reorder_screen_element') {
228
- const file = String(args?.file ?? '');
229
- const astPath = String(args?.astPath ?? '0');
230
- const direction =
231
- args?.direction === 'up' || args?.direction === 'down' ? args.direction : undefined;
232
- const targetAstPath =
233
- typeof args?.targetAstPath === 'string' ? args.targetAstPath : undefined;
234
- const placement =
235
- args?.placement === 'before' || args?.placement === 'after' ? args.placement : undefined;
236
-
237
- const result = await reorderElement(workspaceRoot, {
238
- file,
239
- astPath,
240
- direction,
241
- targetAstPath,
242
- placement,
243
- });
244
- return {
245
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
246
- };
247
- }
248
-
249
- if (name === 'insert_screen_element') {
250
- const file = String(args?.file ?? '');
251
- const preset = String(args?.preset ?? 'button') as InsertElementPreset;
252
- const astPath = typeof args?.astPath === 'string' ? args.astPath : undefined;
253
- const placement =
254
- args?.placement === 'inside' || args?.placement === 'after' || args?.placement === 'before'
255
- ? args.placement
256
- : undefined;
257
- const label = typeof args?.label === 'string' ? args.label : undefined;
258
- const navigateTo = typeof args?.navigateTo === 'string' ? args.navigateTo : undefined;
259
-
260
- const result = await insertElement(workspaceRoot, {
261
- file,
262
- astPath,
263
- placement,
264
- preset,
265
- label,
266
- navigateTo,
267
- });
268
- return {
269
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
270
- };
271
- }
272
-
273
- if (name === 'duplicate_screen_element') {
274
- const file = String(args?.file ?? '');
275
- const astPath = String(args?.astPath ?? '1');
276
- const result = await duplicateElement(workspaceRoot, { file, astPath });
277
- return {
278
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
279
- };
280
- }
281
-
282
- if (name === 'delete_screen_element') {
283
- const file = String(args?.file ?? '');
284
- const astPath = String(args?.astPath ?? '1');
285
- const result = await deleteElement(workspaceRoot, { file, astPath });
286
- return {
287
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
288
- };
289
- }
290
-
291
- throw new Error(`Unknown MCP tool: ${name}`);
292
- }
293
-
294
- export async function handleMcpJsonRpcRequest(
295
- request: JsonRpcRequest,
296
- customWorkspaceRoot?: string
297
- ): Promise<JsonRpcResponse | null> {
298
- if (request.id === undefined) {
299
- // Notification (e.g. notifications/initialized)
300
- return null;
301
- }
302
-
303
- const workspaceRoot =
304
- customWorkspaceRoot ||
305
- process.env.ANTIGRAVITY_TARGET_PROJECT ||
306
- process.env.ANTIGRAVITY_WORKSPACE_ROOT ||
307
- DEFAULT_WORKSPACE_ROOT;
308
-
309
- const method = request.method ?? '';
310
-
311
- try {
312
- if (method === 'initialize') {
313
- const requestedProtocol =
314
- typeof request.params?.protocolVersion === 'string'
315
- ? request.params.protocolVersion
316
- : '2024-11-05';
317
- return {
318
- jsonrpc: '2.0',
319
- id: request.id,
320
- result: {
321
- protocolVersion: requestedProtocol,
322
- capabilities: {
323
- tools: {},
324
- },
325
- serverInfo: {
326
- name: 'zelune',
327
- version: '1.6.1',
328
- },
329
- },
330
- };
331
- }
332
-
333
- if (method === 'ping') {
334
- return {
335
- jsonrpc: '2.0',
336
- id: request.id,
337
- result: {},
338
- };
339
- }
340
-
341
- if (method === 'tools/list') {
342
- return {
343
- jsonrpc: '2.0',
344
- id: request.id,
345
- result: {
346
- tools: MCP_TOOLS,
347
- },
348
- };
349
- }
350
-
351
- if (method === 'resources/list') {
352
- return {
353
- jsonrpc: '2.0',
354
- id: request.id,
355
- result: {
356
- resources: [],
357
- },
358
- };
359
- }
360
-
361
- if (method === 'prompts/list') {
362
- return {
363
- jsonrpc: '2.0',
364
- id: request.id,
365
- result: {
366
- prompts: [],
367
- },
368
- };
369
- }
370
-
371
- if (method === 'tools/call') {
372
- const toolName = String(request.params?.name ?? '');
373
- const toolArgs =
374
- (request.params?.arguments as Record<string, unknown> | undefined) ?? undefined;
375
- const toolResult = await executeMcpTool(workspaceRoot, toolName, toolArgs);
376
- return {
377
- jsonrpc: '2.0',
378
- id: request.id,
379
- result: toolResult,
380
- };
381
- }
382
-
383
- return {
384
- jsonrpc: '2.0',
385
- id: request.id,
386
- error: {
387
- code: -32601,
388
- message: `Method not found: ${method}`,
389
- },
390
- };
391
- } catch (err) {
392
- const message = err instanceof Error ? err.message : String(err);
393
- return {
394
- jsonrpc: '2.0',
395
- id: request.id,
396
- error: {
397
- code: -32603,
398
- message,
399
- },
400
- };
401
- }
402
- }
403
-
404
- export function startMcpServer(customWorkspaceRoot?: string): void {
405
- const rl = readline.createInterface({
406
- input: process.stdin,
407
- terminal: false,
408
- });
409
-
410
- rl.on('line', async (line) => {
411
- const trimmed = line.trim();
412
- if (!trimmed) return;
413
-
414
- let parsed: JsonRpcRequest;
415
- try {
416
- parsed = JSON.parse(trimmed) as JsonRpcRequest;
417
- } catch {
418
- const parseErr: JsonRpcResponse = {
419
- jsonrpc: '2.0',
420
- id: null,
421
- error: { code: -32700, message: 'Parse error' },
422
- };
423
- process.stdout.write(`${JSON.stringify(parseErr)}\n`);
424
- return;
425
- }
426
-
427
- const response = await handleMcpJsonRpcRequest(parsed, customWorkspaceRoot);
428
- if (response) {
429
- process.stdout.write(`${JSON.stringify(response)}\n`);
430
- }
431
- });
432
- }
433
-
434
- const isDirectExecution =
435
- Boolean(process.argv[1]) &&
436
- (() => {
437
- try {
438
- return import.meta.url === pathToFileURL(fs.realpathSync(process.argv[1])).href;
439
- } catch {
440
- return false;
441
- }
442
- })();
443
-
444
- if (isDirectExecution) {
445
- startMcpServer();
446
- }