agent-stage 0.2.14 → 0.2.17

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 (68) hide show
  1. package/dist/commands/guide.js +5 -5
  2. package/dist/commands/init.d.ts +1 -1
  3. package/dist/commands/init.js +94 -138
  4. package/dist/commands/page/add.js +5 -40
  5. package/dist/commands/run/exec.js +1 -1
  6. package/dist/commands/run/inspect.js +1 -1
  7. package/dist/commands/run/watch.js +1 -1
  8. package/dist/commands/serve.d.ts +2 -0
  9. package/dist/commands/serve.js +238 -0
  10. package/dist/commands/status.d.ts +1 -1
  11. package/dist/commands/status.js +41 -40
  12. package/dist/commands/stop.d.ts +1 -1
  13. package/dist/commands/stop.js +26 -44
  14. package/dist/index.js +16 -30
  15. package/dist/utils/agent-helper.js +5 -5
  16. package/dist/utils/paths.js +5 -5
  17. package/dist/utils/tunnel.d.ts +1 -1
  18. package/dist/utils/tunnel.js +1 -1
  19. package/package.json +8 -5
  20. package/dist/commands/dev/index.d.ts +0 -2
  21. package/dist/commands/dev/index.js +0 -11
  22. package/dist/commands/dev/init.d.ts +0 -2
  23. package/dist/commands/dev/init.js +0 -215
  24. package/dist/commands/dev/start.d.ts +0 -2
  25. package/dist/commands/dev/start.js +0 -145
  26. package/dist/commands/dev/status.d.ts +0 -2
  27. package/dist/commands/dev/status.js +0 -55
  28. package/dist/commands/dev/stop.d.ts +0 -2
  29. package/dist/commands/dev/stop.js +0 -45
  30. package/dist/commands/exec.d.ts +0 -2
  31. package/dist/commands/exec.js +0 -75
  32. package/dist/commands/inspect.d.ts +0 -2
  33. package/dist/commands/inspect.js +0 -62
  34. package/dist/commands/ls.d.ts +0 -2
  35. package/dist/commands/ls.js +0 -132
  36. package/dist/commands/restart.d.ts +0 -2
  37. package/dist/commands/restart.js +0 -90
  38. package/dist/commands/rm-page.d.ts +0 -2
  39. package/dist/commands/rm-page.js +0 -32
  40. package/dist/commands/start.d.ts +0 -2
  41. package/dist/commands/start.js +0 -82
  42. package/dist/commands/watch.d.ts +0 -2
  43. package/dist/commands/watch.js +0 -54
  44. package/template/components.json +0 -17
  45. package/template/index.html +0 -13
  46. package/template/package.json +0 -41
  47. package/template/postcss.config.js +0 -6
  48. package/template/src/components/PageRenderer.tsx +0 -108
  49. package/template/src/components/bridge-state-provider.tsx +0 -87
  50. package/template/src/components/ui/button.tsx +0 -55
  51. package/template/src/components/ui/card.tsx +0 -78
  52. package/template/src/components/ui/input.tsx +0 -24
  53. package/template/src/index.css +0 -59
  54. package/template/src/lib/bridge.ts +0 -53
  55. package/template/src/lib/utils.ts +0 -6
  56. package/template/src/main.tsx +0 -23
  57. package/template/src/pages/counter/store.json +0 -8
  58. package/template/src/pages/counter/ui.json +0 -108
  59. package/template/src/pages/test-page/store.json +0 -8
  60. package/template/src/routeTree.gen.ts +0 -77
  61. package/template/src/routes/__root.tsx +0 -11
  62. package/template/src/routes/counter.tsx +0 -19
  63. package/template/src/routes/index.tsx +0 -46
  64. package/template/src/vite-env.d.ts +0 -1
  65. package/template/tailwind.config.js +0 -53
  66. package/template/tsconfig.json +0 -25
  67. package/template/tsconfig.node.json +0 -11
  68. package/template/vite.config.ts +0 -22
@@ -1,132 +0,0 @@
1
- import { Command } from 'commander';
2
- import consola from 'consola';
3
- import c from 'picocolors';
4
- import { readdir, readFile } from 'fs/promises';
5
- import { existsSync } from 'fs';
6
- import { homedir } from 'os';
7
- import { join } from 'pathe';
8
- import { getWorkspaceDir, readRuntimeConfig, isInitialized } from '../utils/paths.js';
9
- import { BridgeClient } from '@agentstage/bridge/sdk';
10
- async function readLocalStores(localPagesDir) {
11
- if (!existsSync(localPagesDir)) {
12
- return [];
13
- }
14
- const entries = await readdir(localPagesDir, { withFileTypes: true });
15
- const stores = [];
16
- for (const entry of entries) {
17
- if (!entry.isDirectory()) {
18
- continue;
19
- }
20
- const pageId = entry.name;
21
- const storePath = join(localPagesDir, pageId, 'store.json');
22
- if (!existsSync(storePath)) {
23
- continue;
24
- }
25
- try {
26
- const content = await readFile(storePath, 'utf8');
27
- const parsed = JSON.parse(content);
28
- stores.push({
29
- pageId: typeof parsed.pageId === 'string' ? parsed.pageId : pageId,
30
- storeKey: 'main',
31
- version: typeof parsed.version === 'number' ? parsed.version : 0,
32
- });
33
- }
34
- catch {
35
- // Ignore invalid local files in offline mode
36
- }
37
- }
38
- return stores;
39
- }
40
- export const lsCommand = new Command('ls')
41
- .description('List all pages and their store status')
42
- .option('--offline', 'Skip Bridge WebSocket and list local store files only')
43
- .action(async (options) => {
44
- try {
45
- if (!isInitialized()) {
46
- consola.error('Project not initialized. Please run `agentstage init` first.');
47
- process.exit(1);
48
- }
49
- const workspaceDir = await getWorkspaceDir();
50
- const routesDir = join(workspaceDir, 'src', 'routes');
51
- let pages = [];
52
- if (existsSync(routesDir)) {
53
- const entries = await readdir(routesDir, { withFileTypes: true });
54
- pages = entries
55
- .filter(e => e.isFile() && e.name.endsWith('.tsx') && !e.name.startsWith('_'))
56
- .map(e => e.name.replace('.tsx', ''))
57
- .filter(name => name !== 'index'); // index is the home page
58
- }
59
- console.log();
60
- console.log(c.bold('Pages:'));
61
- console.log();
62
- let stores = [];
63
- const localPagesDir = join(homedir(), '.agentstage', 'webapp', 'pages');
64
- if (options.offline) {
65
- stores = await readLocalStores(localPagesDir);
66
- }
67
- else {
68
- const config = await readRuntimeConfig();
69
- if (config) {
70
- try {
71
- const client = new BridgeClient(`ws://localhost:${config.port}/_bridge`);
72
- await client.connect();
73
- stores = await client.listStores();
74
- client.disconnect();
75
- }
76
- catch {
77
- // Bridge 未运行
78
- }
79
- }
80
- }
81
- const pageSet = new Set(pages);
82
- for (const store of stores) {
83
- if (store.pageId !== 'index') {
84
- pageSet.add(store.pageId);
85
- }
86
- }
87
- const listedPages = Array.from(pageSet);
88
- // Show home page
89
- const homeStores = stores.filter(s => s.pageId === 'index');
90
- if (homeStores.length > 0) {
91
- console.log(` ${c.green('●')} ${c.bold('/ (home)')}`);
92
- for (const store of homeStores) {
93
- console.log(` └─ ${store.storeKey} v${store.version}`);
94
- }
95
- }
96
- else {
97
- console.log(` ${c.gray('○')} / (home)`);
98
- }
99
- // Show other pages
100
- if (listedPages.length === 0) {
101
- console.log(c.gray(' No additional pages. Create one with:'));
102
- console.log(c.gray(' agentstage add-page <name>'));
103
- }
104
- else {
105
- for (const page of listedPages) {
106
- const pageStores = stores.filter(s => s.pageId === page);
107
- if (pageStores.length > 0) {
108
- console.log(` ${c.green('●')} ${c.bold('/' + page)}`);
109
- for (const store of pageStores) {
110
- console.log(` └─ ${store.storeKey} v${store.version}`);
111
- }
112
- }
113
- else {
114
- console.log(` ${c.gray('○')} /${page}`);
115
- }
116
- }
117
- }
118
- console.log();
119
- if (stores.length === 0) {
120
- if (options.offline) {
121
- console.log(c.gray(`No local store files found in ${localPagesDir}`));
122
- }
123
- else {
124
- console.log(c.gray('Runtime is not running. Run `agentstage start` to see live status.'));
125
- }
126
- console.log();
127
- }
128
- }
129
- catch (error) {
130
- consola.error('Failed to list pages:', error.message);
131
- }
132
- });
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare const restartCommand: Command;
@@ -1,90 +0,0 @@
1
- import { Command } from 'commander';
2
- import * as p from '@clack/prompts';
3
- import consola from 'consola';
4
- import c from 'picocolors';
5
- import { execa } from 'execa';
6
- import { mkdir } from 'fs/promises';
7
- import { join } from 'pathe';
8
- import { getWorkspaceDir, saveRuntimeConfig, readRuntimeConfig, isInitialized } from '../utils/paths.js';
9
- async function killProcess(pid) {
10
- try {
11
- process.kill(pid, 'SIGTERM');
12
- let attempts = 0;
13
- while (attempts < 10) {
14
- await new Promise(r => setTimeout(r, 500));
15
- try {
16
- process.kill(pid, 0);
17
- attempts++;
18
- }
19
- catch {
20
- break;
21
- }
22
- }
23
- if (attempts >= 10) {
24
- process.kill(pid, 'SIGKILL');
25
- }
26
- }
27
- catch (error) {
28
- if (error.code !== 'ESRCH')
29
- throw error;
30
- }
31
- }
32
- export const restartCommand = new Command('restart')
33
- .description('Restart the Agentstage Runtime (stop and start)')
34
- .option('-p, --port <port>', 'Port to run the web server on', '3000')
35
- .action(async (options) => {
36
- // 1. 检查是否已初始化
37
- if (!isInitialized()) {
38
- consola.error('Project not initialized. Please run `agentstage init` first.');
39
- process.exit(1);
40
- }
41
- const workspaceDir = await getWorkspaceDir();
42
- const port = parseInt(options.port, 10);
43
- const s = p.spinner();
44
- // 2. 停止现有服务
45
- const existingConfig = await readRuntimeConfig();
46
- if (existingConfig) {
47
- s.start('Stopping current runtime...');
48
- try {
49
- await killProcess(existingConfig.pid);
50
- s.stop('Runtime stopped');
51
- }
52
- catch (error) {
53
- s.stop('Failed to stop runtime');
54
- consola.warn('Continuing with start...');
55
- }
56
- }
57
- // 3. 启动新服务
58
- s.start('Starting Agentstage Runtime...');
59
- try {
60
- // 启动 TanStack Start 项目(包含 Bridge Gateway)
61
- const subprocess = execa('npm', ['run', 'dev'], {
62
- cwd: workspaceDir,
63
- detached: true,
64
- stdio: 'ignore',
65
- env: {
66
- ...process.env,
67
- PORT: String(port),
68
- },
69
- });
70
- await mkdir(join(workspaceDir, '.agentstage'), { recursive: true });
71
- // 保存运行时配置
72
- await saveRuntimeConfig({
73
- pid: subprocess.pid,
74
- port,
75
- startedAt: new Date().toISOString(),
76
- });
77
- s.stop('Runtime restarted successfully');
78
- console.log();
79
- consola.success('Agentstage Runtime is running');
80
- console.log(` Web: ${c.cyan(`http://localhost:${port}`)}`);
81
- console.log(` Bridge: ${c.cyan(`ws://localhost:${port}/_bridge`)}`);
82
- console.log();
83
- console.log(` Workspace: ${c.gray(workspaceDir)}`);
84
- }
85
- catch (error) {
86
- s.stop('Failed to start runtime');
87
- consola.error(error.message);
88
- process.exit(1);
89
- }
90
- });
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare const rmPageCommand: Command;
@@ -1,32 +0,0 @@
1
- import { Command } from 'commander';
2
- import consola from 'consola';
3
- import { unlink } from 'fs/promises';
4
- import { existsSync } from 'fs';
5
- import { join } from 'pathe';
6
- import { getWorkspaceDir, isInitialized } from '../utils/paths.js';
7
- export const rmPageCommand = new Command('rm-page')
8
- .description('Remove a page from the routes directory')
9
- .argument('<name>', 'Page name')
10
- .action(async (name) => {
11
- // 检查是否已初始化
12
- if (!isInitialized()) {
13
- consola.error('Project not initialized. Please run `agentstage init` first.');
14
- process.exit(1);
15
- }
16
- try {
17
- const workspaceDir = await getWorkspaceDir();
18
- const routesDir = join(workspaceDir, 'src', 'routes');
19
- const pageFile = join(routesDir, `${name}.tsx`);
20
- if (!existsSync(pageFile)) {
21
- consola.error(`Page "${name}" not found at src/routes/${name}.tsx`);
22
- process.exit(1);
23
- }
24
- await unlink(pageFile);
25
- consola.success(`Page "${name}" deleted`);
26
- console.log(` Note: TanStack Router will automatically remove the route`);
27
- }
28
- catch (error) {
29
- consola.error('Failed to delete page:', error.message);
30
- process.exit(1);
31
- }
32
- });
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare const startCommand: Command;
@@ -1,82 +0,0 @@
1
- import { Command } from 'commander';
2
- import * as p from '@clack/prompts';
3
- import consola from 'consola';
4
- import c from 'picocolors';
5
- import { execa } from 'execa';
6
- import { mkdir } from 'fs/promises';
7
- import { existsSync } from 'fs';
8
- import { join } from 'pathe';
9
- import { getWorkspaceDir, saveRuntimeConfig, isInitialized, readRuntimeConfig } from '../utils/paths.js';
10
- export const startCommand = new Command('start')
11
- .description('Start the Agentstage Runtime (Vite dev server with Bridge)')
12
- .option('-p, --port <port>', 'Port to run the web server on', '3000')
13
- .action(async (options) => {
14
- // 1. 检查是否已初始化
15
- if (!isInitialized()) {
16
- consola.error('Project not initialized. Please run `agentstage init` first.');
17
- process.exit(1);
18
- }
19
- const workspaceDir = await getWorkspaceDir();
20
- const port = parseInt(options.port, 10);
21
- // 2. 检查是否已运行
22
- const existingConfig = await readRuntimeConfig();
23
- if (existingConfig) {
24
- try {
25
- process.kill(existingConfig.pid, 0);
26
- consola.warn(`Runtime is already running (PID: ${existingConfig.pid}, Port: ${existingConfig.port})`);
27
- console.log(` Web: ${c.cyan(`http://localhost:${existingConfig.port}`)}`);
28
- console.log(` Bridge: ${c.cyan(`ws://localhost:${existingConfig.port}/_bridge`)}`);
29
- return;
30
- }
31
- catch {
32
- // 进程不存在,继续启动
33
- }
34
- }
35
- // 3. 检查是否需要安装依赖
36
- const nodeModulesPath = join(workspaceDir, 'node_modules');
37
- if (!existsSync(nodeModulesPath)) {
38
- const s = p.spinner();
39
- s.start('Installing dependencies...');
40
- try {
41
- await execa('npm', ['install'], { cwd: workspaceDir, stdio: 'pipe' });
42
- s.stop('Dependencies installed');
43
- }
44
- catch (error) {
45
- s.stop('Failed to install dependencies');
46
- consola.error(error.message);
47
- process.exit(1);
48
- }
49
- }
50
- const s = p.spinner();
51
- s.start('Starting Agentstage Runtime...');
52
- try {
53
- // 4. 启动 Vite dev server
54
- // WebSocket 会通过 bridgePlugin() 自动挂载到 Vite server
55
- const subprocess = execa('npx', ['vite', '--port', String(port), '--host'], {
56
- cwd: workspaceDir,
57
- detached: true,
58
- stdio: 'ignore',
59
- });
60
- await mkdir(join(workspaceDir, '.agentstage'), { recursive: true });
61
- // 5. 保存运行时配置
62
- await saveRuntimeConfig({
63
- pid: subprocess.pid,
64
- port,
65
- startedAt: new Date().toISOString(),
66
- });
67
- // 6. 等待一下确保服务启动
68
- await new Promise(resolve => setTimeout(resolve, 2000));
69
- s.stop('Runtime started successfully');
70
- console.log();
71
- consola.success('Agentstage Runtime is running');
72
- console.log(` Web: ${c.cyan(`http://localhost:${port}`)}`);
73
- console.log(` Bridge: ${c.cyan(`ws://localhost:${port}/_bridge`)}`);
74
- console.log();
75
- console.log(` Workspace: ${c.gray(workspaceDir)}`);
76
- }
77
- catch (error) {
78
- s.stop('Failed to start runtime');
79
- consola.error(error.message);
80
- process.exit(1);
81
- }
82
- });
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare const watchCommand: Command;
@@ -1,54 +0,0 @@
1
- import { Command } from 'commander';
2
- import consola from 'consola';
3
- import c from 'picocolors';
4
- import { BridgeClient } from '@agentstage/bridge/sdk';
5
- import { readRuntimeConfig, isInitialized } from '../utils/paths.js';
6
- export const watchCommand = new Command('watch')
7
- .description('Watch a page for real-time changes')
8
- .argument('<page>', 'Page ID')
9
- .action(async (pageId) => {
10
- try {
11
- // 1. 检查是否已初始化
12
- if (!isInitialized()) {
13
- consola.error('Project not initialized. Please run `agentstage init` first.');
14
- process.exit(1);
15
- }
16
- // 2. 检查是否已启动
17
- const config = await readRuntimeConfig();
18
- if (!config) {
19
- consola.error('Runtime is not running. Please run `agentstage start` first.');
20
- process.exit(1);
21
- }
22
- const client = new BridgeClient(`ws://localhost:${config.port}/_bridge`);
23
- client.onEvent((event) => {
24
- const timestamp = new Date().toISOString();
25
- console.log(c.gray(`[${timestamp}]`), event);
26
- });
27
- await client.connect();
28
- // 查找并订阅所有该 page 的 stores
29
- const stores = await client.listStores();
30
- const pageStores = stores.filter(s => s.pageId === pageId);
31
- if (pageStores.length === 0) {
32
- consola.error(`Page "${pageId}" not found`);
33
- client.disconnect();
34
- process.exit(1);
35
- }
36
- for (const store of pageStores) {
37
- client.subscribe(store.id);
38
- }
39
- consola.success(`Watching ${c.cyan(pageId)}. Press Ctrl+C to exit.`);
40
- console.log();
41
- // 保持运行
42
- process.on('SIGINT', () => {
43
- console.log();
44
- consola.info('Stopped watching');
45
- client.disconnect();
46
- process.exit(0);
47
- });
48
- await new Promise(() => { });
49
- }
50
- catch (error) {
51
- consola.error('Failed to watch page:', error.message);
52
- process.exit(1);
53
- }
54
- });
@@ -1,17 +0,0 @@
1
- {
2
- "$schema": "https://ui.shadcn.com/schema.json",
3
- "style": "default",
4
- "rsc": false,
5
- "tsx": true,
6
- "tailwind": {
7
- "config": "tailwind.config.js",
8
- "css": "src/index.css",
9
- "baseColor": "neutral",
10
- "cssVariables": true,
11
- "prefix": ""
12
- },
13
- "aliases": {
14
- "components": "@/components",
15
- "utils": "@/lib/utils"
16
- }
17
- }
@@ -1,13 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Agentstage App</title>
8
- </head>
9
- <body>
10
- <div id="root"></div>
11
- <script type="module" src="/src/main.tsx"></script>
12
- </body>
13
- </html>
@@ -1,41 +0,0 @@
1
- {
2
- "name": "agentstage-app",
3
- "private": true,
4
- "version": "0.0.0",
5
- "type": "module",
6
- "scripts": {
7
- "dev": "vite",
8
- "build": "tsc && vite build",
9
- "preview": "vite preview",
10
- "type-check": "tsc --noEmit"
11
- },
12
- "dependencies": {
13
- "@agentstage/render": "workspace:*",
14
- "@tanstack/react-router": "^1.114.3",
15
- "@tanstack/router-core": "^1.114.3",
16
- "@tanstack/router-devtools": "^1.114.3",
17
- "agent-stage-bridge": "workspace:*",
18
- "class-variance-authority": "^0.7.0",
19
- "clsx": "^2.1.0",
20
- "lucide-react": "^0.564.0",
21
- "react": "^19.0.0",
22
- "react-dom": "^19.0.0",
23
- "tailwind-merge": "^2.2.0",
24
- "tailwindcss-animate": "^1.0.7",
25
- "zod": "^3.23.0",
26
- "zustand": "^4.5.0"
27
- },
28
- "devDependencies": {
29
- "@radix-ui/react-slot": "^1.0.2",
30
- "@tanstack/router-generator": "^1.114.3",
31
- "@tanstack/router-plugin": "^1.114.3",
32
- "@types/react": "^19.0.0",
33
- "@types/react-dom": "^19.0.0",
34
- "@vitejs/plugin-react": "^4.2.1",
35
- "autoprefixer": "^10.4.17",
36
- "postcss": "^8.5.0",
37
- "tailwindcss": "^4.0.0",
38
- "typescript": "^5.2.2",
39
- "vite": "^5.4.21"
40
- }
41
- }
@@ -1,6 +0,0 @@
1
- export default {
2
- plugins: {
3
- tailwindcss: {},
4
- autoprefixer: {},
5
- },
6
- }
@@ -1,108 +0,0 @@
1
- import { useEffect, useState } from 'react'
2
- import type { Spec } from '@agentstage/render'
3
- import { Renderer, defineRegistry, defineCatalog, schema } from '@agentstage/render'
4
- import { shadcnComponents, shadcnComponentDefinitions } from '@agentstage/render/shadcn'
5
- import type { Bridge } from '../lib/bridge'
6
- import { BridgeStateProvider } from './bridge-state-provider'
7
-
8
- interface PageRendererProps {
9
- pageId: string
10
- bridge: Bridge
11
- }
12
-
13
- // Create catalog with all shadcn components
14
- const catalog = defineCatalog(schema, {
15
- components: {
16
- Card: shadcnComponentDefinitions.Card,
17
- Button: shadcnComponentDefinitions.Button,
18
- Input: shadcnComponentDefinitions.Input,
19
- Stack: shadcnComponentDefinitions.Stack,
20
- Text: shadcnComponentDefinitions.Text,
21
- Heading: shadcnComponentDefinitions.Heading,
22
- Badge: shadcnComponentDefinitions.Badge,
23
- Separator: shadcnComponentDefinitions.Separator,
24
- Dialog: shadcnComponentDefinitions.Dialog,
25
- Tabs: shadcnComponentDefinitions.Tabs,
26
- Table: shadcnComponentDefinitions.Table,
27
- },
28
- actions: {},
29
- })
30
-
31
- // Create registry
32
- const { registry } = defineRegistry(catalog, {
33
- components: {
34
- Card: shadcnComponents.Card,
35
- Button: shadcnComponents.Button,
36
- Input: shadcnComponents.Input,
37
- Stack: shadcnComponents.Stack,
38
- Text: shadcnComponents.Text,
39
- Heading: shadcnComponents.Heading,
40
- Badge: shadcnComponents.Badge,
41
- Separator: shadcnComponents.Separator,
42
- Dialog: shadcnComponents.Dialog,
43
- Tabs: shadcnComponents.Tabs,
44
- Table: shadcnComponents.Table,
45
- },
46
- })
47
-
48
- export function PageRenderer({ pageId, bridge }: PageRendererProps) {
49
- const [uiSpec, setUiSpec] = useState<Spec | null>(null)
50
- const [loading, setLoading] = useState(true)
51
- const [error, setError] = useState<string | null>(null)
52
-
53
- useEffect(() => {
54
- // Load ui.json
55
- fetch(`/src/pages/${pageId}/ui.json`)
56
- .then((res) => {
57
- if (!res.ok) throw new Error(`Failed to load ui.json: ${res.status}`)
58
- return res.json()
59
- })
60
- .then((spec) => {
61
- setUiSpec(spec)
62
- setLoading(false)
63
- })
64
- .catch((err) => {
65
- setError(err.message)
66
- setLoading(false)
67
- })
68
- }, [pageId])
69
-
70
- // Connect to bridge
71
- useEffect(() => {
72
- bridge.connect().then((result: { storeId: string }) => {
73
- console.log('Connected to bridge:', result.storeId)
74
- })
75
- }, [bridge])
76
-
77
- if (loading) {
78
- return (
79
- <div className="flex items-center justify-center min-h-screen">
80
- <div className="animate-pulse text-muted-foreground">Loading UI...</div>
81
- </div>
82
- )
83
- }
84
-
85
- if (error) {
86
- return (
87
- <div className="flex items-center justify-center min-h-screen">
88
- <div className="text-destructive">Error: {error}</div>
89
- </div>
90
- )
91
- }
92
-
93
- if (!uiSpec) {
94
- return (
95
- <div className="flex items-center justify-center min-h-screen">
96
- <div className="text-muted-foreground">No UI spec found</div>
97
- </div>
98
- )
99
- }
100
-
101
- return (
102
- <BridgeStateProvider bridge={bridge}>
103
- <div className="min-h-screen bg-background p-8">
104
- <Renderer spec={uiSpec} registry={registry} />
105
- </div>
106
- </BridgeStateProvider>
107
- )
108
- }