@dyyz1993/create-agent 2.0.1 → 2.1.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 (57) hide show
  1. package/package.json +1 -1
  2. package/src/commands/create.ts +31 -31
  3. package/src/commands/workspace.ts +112 -105
  4. package/src/lib/copy.ts +1 -0
  5. package/templates/agent/electron/main.js +46 -0
  6. package/templates/agent/electron/preload.js +5 -0
  7. package/templates/agent/electron-builder.json +40 -0
  8. package/templates/agent/eslint.config.mjs +2 -0
  9. package/templates/agent/package.json +60 -2
  10. package/templates/agent/src/mainview/App.tsx +29 -26
  11. package/templates/agent/src/mainview/components/chat/ChatPanel.tsx +88 -88
  12. package/templates/agent/src/mainview/components/file-preview/VirtualizedCodeView.tsx +105 -81
  13. package/templates/agent/src/mainview/components/search/SearchPanel.tsx +427 -378
  14. package/templates/agent/src/mainview/components/todo/TodoPanel.tsx +3 -3
  15. package/templates/agent/src/mainview/hooks/use-input-history.ts +70 -61
  16. package/templates/agent/src/mainview/lib/api-client.ts +1 -4
  17. package/templates/agent/src/mainview/main.tsx +4 -10
  18. package/templates/agent/src/mainview/stores/use-feed-store.ts +107 -107
  19. package/templates/agent/src/mainview/utils/drop-handler.ts +114 -115
  20. package/templates/agent/src/server-config.ts +1 -1
  21. package/templates/agent/src/server.ts +1 -2
  22. package/templates/agent/src/shared/handlers/chat.ts +5 -5
  23. package/templates/agent/src/shared/handlers/debug.ts +5 -1
  24. package/templates/agent/src/shared/handlers/git.ts +286 -243
  25. package/templates/agent/src/shared/http-routes.ts +1 -1
  26. package/templates/agent/src/shared/lib/bash-security.ts +43 -43
  27. package/templates/agent/tsconfig.ipc.json +5 -1
  28. package/templates/agent/tsconfig.json +3 -1
  29. package/templates/chat/package.json +3 -0
  30. package/templates/chat/src/mainview/hooks/use-input-history.ts +70 -61
  31. package/templates/chat/src/mainview/lib/api-client.ts +2 -5
  32. package/templates/chat/src/mainview/main.tsx +10 -7
  33. package/templates/chat/src/server-config.ts +1 -1
  34. package/templates/chat/src/server.ts +1 -2
  35. package/templates/chat/src/shared/handlers/chat.ts +5 -5
  36. package/templates/chat/src/shared/handlers/debug.ts +5 -1
  37. package/templates/chat/src/shared/http-routes.ts +1 -1
  38. package/templates/chat/tsconfig.ipc.json +5 -1
  39. package/templates/chat/tsconfig.json +12 -2
  40. package/templates/general/package.json +3 -0
  41. package/templates/general/src/mainview/components/file-preview/VirtualizedCodeView.tsx +101 -81
  42. package/templates/general/src/mainview/components/search/SearchPanel.tsx +429 -378
  43. package/templates/general/src/mainview/hooks/use-input-history.ts +70 -61
  44. package/templates/general/src/mainview/lib/api-client.ts +2 -5
  45. package/templates/general/src/mainview/main.tsx +10 -7
  46. package/templates/general/src/mainview/stores/use-feed-store.ts +107 -107
  47. package/templates/general/src/mainview/utils/drop-handler.ts +114 -115
  48. package/templates/general/src/server-config.ts +1 -1
  49. package/templates/general/src/server.ts +1 -2
  50. package/templates/general/src/shared/handlers/chat.ts +5 -5
  51. package/templates/general/src/shared/handlers/debug.ts +5 -1
  52. package/templates/general/src/shared/handlers/git.ts +286 -243
  53. package/templates/general/src/shared/http-routes.ts +1 -1
  54. package/templates/general/tsconfig.ipc.json +5 -1
  55. package/templates/general/tsconfig.json +12 -2
  56. package/templates/shared/components/ErrorBoundary.tsx +50 -49
  57. package/templates/shared/http-routes.ts +210 -190
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyyz1993/create-agent",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Create Agent project scaffolding CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,27 +1,27 @@
1
- import { resolve } from 'path';
2
- import { resolveTemplateDir, getRootDir } from '../lib/templates.js';
3
- import { copyTemplate } from '../lib/copy.js';
1
+ import { resolve } from "path";
2
+ import { resolveTemplateDir, getRootDir } from "../lib/templates.js";
3
+ import { copyTemplate } from "../lib/copy.js";
4
4
 
5
5
  export async function runCreate(args: string[]): Promise<void> {
6
- let templateType = 'general';
7
- let customDir: string | undefined;
6
+ let templateType = "general";
7
+ let customDir: string | undefined;
8
8
 
9
- const positional: string[] = [];
10
- for (let i = 0; i < args.length; i++) {
11
- const arg = args[i];
12
- if (arg === '--type' && args[i + 1]) {
13
- templateType = args[++i];
14
- } else if (arg === '--dir' && args[i + 1]) {
15
- customDir = args[++i];
16
- } else if (!arg.startsWith('--')) {
17
- positional.push(arg);
18
- }
19
- }
9
+ const positional: string[] = [];
10
+ for (let i = 0; i < args.length; i++) {
11
+ const arg = args[i]!;
12
+ if (arg === "--type" && args[i + 1]) {
13
+ templateType = args[++i]!;
14
+ } else if (arg === "--dir" && args[i + 1]) {
15
+ customDir = args[++i]!;
16
+ } else if (!arg.startsWith("--")) {
17
+ positional.push(arg);
18
+ }
19
+ }
20
20
 
21
- const projectName = positional[0];
22
- const targetArg = customDir || positional[1];
23
- if (!projectName) {
24
- console.log(`
21
+ const projectName = positional[0];
22
+ const targetArg = customDir || positional[1];
23
+ if (!projectName) {
24
+ console.log(`
25
25
  Usage: create-agent create <name> [--type <type>] [--dir <path>]
26
26
 
27
27
  Options:
@@ -33,17 +33,17 @@ Examples:
33
33
  create-agent create my-app --type chat
34
34
  create-agent create my-app --dir ~/projects/my-app
35
35
  `);
36
- process.exit(1);
37
- }
36
+ process.exit(1);
37
+ }
38
38
 
39
- const sanitized = projectName.replace(/[^a-zA-Z0-9-_]/g, '-');
40
- const targetDir = targetArg ? resolve(targetArg) : resolve(process.cwd(), sanitized);
41
- const rootDir = getRootDir();
42
- const templateDir = resolveTemplateDir(rootDir, templateType);
39
+ const sanitized = projectName.replace(/[^a-zA-Z0-9-_]/g, "-");
40
+ const targetDir = targetArg ? resolve(targetArg) : resolve(process.cwd(), sanitized);
41
+ const rootDir = getRootDir();
42
+ const templateDir = resolveTemplateDir(rootDir, templateType);
43
43
 
44
- await copyTemplate({
45
- projectName: sanitized,
46
- templateDir,
47
- targetDir,
48
- });
44
+ await copyTemplate({
45
+ projectName: sanitized,
46
+ templateDir,
47
+ targetDir,
48
+ });
49
49
  }
@@ -1,45 +1,50 @@
1
- import { resolve } from 'path';
2
- import { execSync } from 'child_process';
3
- import { existsSync, readFileSync, mkdirSync } from 'fs';
4
- import { createServer } from 'net';
5
- import type { PortEntry } from '../lib/types.js';
1
+ import { resolve } from "path";
2
+ import { execSync } from "child_process";
3
+ import { existsSync, readFileSync, mkdirSync } from "fs";
4
+ import { createServer } from "net";
5
+ import type { PortEntry } from "../lib/types.js";
6
6
 
7
- const PORT_REGISTRY = resolve(process.env.HOME || '~', '.pi-agent', 'ports.json');
7
+ const PORT_REGISTRY = resolve(process.env.HOME || "~", ".pi-agent", "ports.json");
8
8
 
9
9
  function readRegistry(): Record<string, PortEntry> {
10
- try {
11
- return JSON.parse(readFileSync(PORT_REGISTRY, 'utf-8'));
12
- } catch {
13
- return {};
14
- }
10
+ try {
11
+ return JSON.parse(readFileSync(PORT_REGISTRY, "utf-8"));
12
+ } catch {
13
+ return {};
14
+ }
15
15
  }
16
16
 
17
17
  function isPortFree(port: number): Promise<boolean> {
18
- return new Promise((resolve) => {
19
- const server = createServer();
20
- server.once('error', () => resolve(false));
21
- server.once('listening', () => { server.close(); resolve(true); });
22
- server.listen(port);
23
- });
18
+ return new Promise((resolve) => {
19
+ const server = createServer();
20
+ server.once("error", () => resolve(false));
21
+ server.once("listening", () => {
22
+ server.close();
23
+ resolve(true);
24
+ });
25
+ server.listen(port);
26
+ });
24
27
  }
25
28
 
26
- async function findFreePorts(entries: Record<string, PortEntry>): Promise<{ backend: number; vite: number }> {
27
- const usedPorts = new Set<number>();
28
- for (const entry of Object.values(entries)) {
29
- usedPorts.add(entry.port);
30
- }
31
- let backend = 3100;
32
- while (usedPorts.has(backend) || !(await isPortFree(backend))) backend++;
33
- let vite = 5173;
34
- while (usedPorts.has(vite) || !(await isPortFree(vite))) vite++;
35
- return { backend, vite };
29
+ async function findFreePorts(
30
+ entries: Record<string, PortEntry>
31
+ ): Promise<{ backend: number; vite: number }> {
32
+ const usedPorts = new Set<number>();
33
+ for (const entry of Object.values(entries)) {
34
+ usedPorts.add(entry.port);
35
+ }
36
+ let backend = 3100;
37
+ while (usedPorts.has(backend) || !(await isPortFree(backend))) backend++;
38
+ let vite = 5173;
39
+ while (usedPorts.has(vite) || !(await isPortFree(vite))) vite++;
40
+ return { backend, vite };
36
41
  }
37
42
 
38
43
  export async function runWorkspace(args: string[]): Promise<void> {
39
- const subCommand = args[0];
44
+ const subCommand = args[0];
40
45
 
41
- if (!subCommand || subCommand === '--help' || subCommand === '-h') {
42
- console.log(`
46
+ if (!subCommand || subCommand === "--help" || subCommand === "-h") {
47
+ console.log(`
43
48
  Usage: create-agent workspace add <name> [--base <branch>]
44
49
 
45
50
  Creates an isolated git worktree in .workspace/<name> with its own branch and ports.
@@ -51,79 +56,81 @@ Examples:
51
56
  create-agent workspace add feature-chat-ui
52
57
  create-agent workspace add fix-login --base develop
53
58
  `);
54
- return;
55
- }
56
-
57
- if (subCommand !== 'add') {
58
- console.error(`Unknown workspace subcommand: "${subCommand}"`);
59
- console.log('Usage: create-agent workspace add <name>');
60
- return;
61
- }
62
-
63
- let name = '';
64
- let baseBranch = '';
65
- const rest = args.slice(1);
66
- for (let i = 0; i < rest.length; i++) {
67
- if (rest[i] === '--base' && rest[i + 1]) {
68
- baseBranch = rest[++i];
69
- } else if (!rest[i].startsWith('--')) {
70
- name = rest[i];
71
- }
72
- }
73
-
74
- if (!name) {
75
- console.error('Error: workspace name is required');
76
- process.exit(1);
77
- }
78
-
79
- const projectRoot = process.cwd();
80
- const workspaceDir = resolve(projectRoot, '.workspace', name);
81
-
82
- if (existsSync(workspaceDir)) {
83
- console.error(`Error: workspace "${name}" already exists at ${workspaceDir}`);
84
- process.exit(1);
85
- }
86
-
87
- const branchName = `workspace/${name}`;
88
- const baseArg = baseBranch ? baseBranch : 'HEAD';
89
-
90
- console.log(`Creating workspace: ${name}`);
91
- console.log(` Branch: ${branchName}`);
92
- console.log(` Directory: .workspace/${name}`);
93
-
94
- mkdirSync(resolve(projectRoot, '.workspace'), { recursive: true });
95
-
96
- try {
97
- execSync(`git worktree add "${workspaceDir}" -b ${branchName} ${baseArg}`, {
98
- cwd: projectRoot,
99
- stdio: 'pipe',
100
- });
101
- } catch (err: unknown) {
102
- const message = err instanceof Error ? err.message : String(err);
103
- console.error(`Failed to create worktree: ${message}`);
104
- process.exit(1);
105
- }
106
-
107
- const registry = readRegistry();
108
- const ports = await findFreePorts(registry);
109
-
110
- console.log(` Backend port: ${ports.backend}`);
111
- console.log(` Vite port: ${ports.vite}`);
112
- console.log('');
113
- console.log('Installing dependencies...');
114
- try {
115
- execSync('bun install', { cwd: workspaceDir, stdio: 'pipe' });
116
- } catch {
117
- console.log('(bun install skipped)');
118
- }
119
-
120
- console.log('');
121
- console.log('Workspace created successfully!');
122
- console.log('');
123
- console.log('To start developing:');
124
- console.log(` cd .workspace/${name}`);
125
- console.log(` PORT=${ports.backend} VITE_PORT=${ports.vite} bun run dev:web`);
126
- console.log('');
127
- console.log('Or start from project root:');
128
- console.log(` PORT=${ports.backend} VITE_PORT=${ports.vite} bun run dev:web`);
59
+ return;
60
+ }
61
+
62
+ if (subCommand !== "add") {
63
+ console.error(`Unknown workspace subcommand: "${subCommand}"`);
64
+ console.log("Usage: create-agent workspace add <name>");
65
+ return;
66
+ }
67
+
68
+ let name = "";
69
+ let baseBranch = "";
70
+ const rest = args.slice(1);
71
+ for (let i = 0; i < rest.length; i++) {
72
+ const arg = rest[i];
73
+ if (arg === undefined) continue;
74
+ if (arg === "--base" && rest[i + 1]) {
75
+ baseBranch = rest[++i] as string;
76
+ } else if (!arg.startsWith("--")) {
77
+ name = arg;
78
+ }
79
+ }
80
+
81
+ if (!name) {
82
+ console.error("Error: workspace name is required");
83
+ process.exit(1);
84
+ }
85
+
86
+ const projectRoot = process.cwd();
87
+ const workspaceDir = resolve(projectRoot, ".workspace", name);
88
+
89
+ if (existsSync(workspaceDir)) {
90
+ console.error(`Error: workspace "${name}" already exists at ${workspaceDir}`);
91
+ process.exit(1);
92
+ }
93
+
94
+ const branchName = `workspace/${name}`;
95
+ const baseArg = baseBranch ? baseBranch : "HEAD";
96
+
97
+ console.log(`Creating workspace: ${name}`);
98
+ console.log(` Branch: ${branchName}`);
99
+ console.log(` Directory: .workspace/${name}`);
100
+
101
+ mkdirSync(resolve(projectRoot, ".workspace"), { recursive: true });
102
+
103
+ try {
104
+ execSync(`git worktree add "${workspaceDir}" -b ${branchName} ${baseArg}`, {
105
+ cwd: projectRoot,
106
+ stdio: "pipe",
107
+ });
108
+ } catch (err: unknown) {
109
+ const message = err instanceof Error ? err.message : String(err);
110
+ console.error(`Failed to create worktree: ${message}`);
111
+ process.exit(1);
112
+ }
113
+
114
+ const registry = readRegistry();
115
+ const ports = await findFreePorts(registry);
116
+
117
+ console.log(` Backend port: ${ports.backend}`);
118
+ console.log(` Vite port: ${ports.vite}`);
119
+ console.log("");
120
+ console.log("Installing dependencies...");
121
+ try {
122
+ execSync("bun install", { cwd: workspaceDir, stdio: "pipe" });
123
+ } catch {
124
+ console.log("(bun install skipped)");
125
+ }
126
+
127
+ console.log("");
128
+ console.log("Workspace created successfully!");
129
+ console.log("");
130
+ console.log("To start developing:");
131
+ console.log(` cd .workspace/${name}`);
132
+ console.log(` PORT=${ports.backend} VITE_PORT=${ports.vite} bun run dev:web`);
133
+ console.log("");
134
+ console.log("Or start from project root:");
135
+ console.log(` PORT=${ports.backend} VITE_PORT=${ports.vite} bun run dev:web`);
129
136
  }
package/src/lib/copy.ts CHANGED
@@ -178,6 +178,7 @@ function updatePackageJson(targetDir: string, _projectName: string): void {
178
178
  let inRpcSection = false;
179
179
  for (let i = 0; i < lines.length; i++) {
180
180
  const line = lines[i];
181
+ if (line === undefined) continue;
181
182
 
182
183
  if (line.includes("import rpcPlugin") && line.includes("@dyyz1993/eslint-plugin-rpc")) {
183
184
  continue;
@@ -0,0 +1,46 @@
1
+ const { app, BrowserWindow, ipcMain } = require('electron');
2
+ const path = require('path');
3
+
4
+ let mainWindow;
5
+
6
+ function createWindow() {
7
+ mainWindow = new BrowserWindow({
8
+ width: 1200,
9
+ height: 800,
10
+ webPreferences: {
11
+ preload: path.join(__dirname, 'preload.js'),
12
+ nodeIntegration: false,
13
+ contextIsolation: true,
14
+ },
15
+ });
16
+
17
+ if (process.env.NODE_ENV === 'development') {
18
+ mainWindow.loadURL('http://localhost:5173');
19
+ } else {
20
+ mainWindow.loadFile(path.join(__dirname, '../dist/index.html'));
21
+ }
22
+
23
+ mainWindow.on('closed', () => {
24
+ mainWindow = null;
25
+ });
26
+ }
27
+
28
+ app.whenReady().then(() => {
29
+ createWindow();
30
+ });
31
+
32
+ app.on('window-all-closed', () => {
33
+ if (process.platform !== 'darwin') {
34
+ app.quit();
35
+ }
36
+ });
37
+
38
+ app.on('activate', () => {
39
+ if (BrowserWindow.getAllWindows().length === 0) {
40
+ createWindow();
41
+ }
42
+ });
43
+
44
+ ipcMain.handle('ping', async () => {
45
+ return 'pong';
46
+ });
@@ -0,0 +1,5 @@
1
+ const { contextBridge, ipcRenderer } = require('electron');
2
+
3
+ contextBridge.exposeInMainWorld('electronAPI', {
4
+ ping: () => ipcRenderer.invoke('ping'),
5
+ });
@@ -0,0 +1,40 @@
1
+ {
2
+ "appId": "com.piagent.app",
3
+ "productName": "Pi Agent",
4
+ "copyright": "Copyright © 2024 dyyz1993",
5
+ "directories": {
6
+ "output": "dist-electron",
7
+ "buildResources": "build"
8
+ },
9
+ "files": ["dist/**/*", "electron/**/*", "package.json"],
10
+ "mac": {
11
+ "category": "public.app-category.developer-tools",
12
+ "hardenedRuntime": true,
13
+ "gatekeeperAssess": false,
14
+ "entitlements": ["com.apple.security.cs.allow-jit"],
15
+ "target": [
16
+ {
17
+ "target": "dmg",
18
+ "arch": ["x64", "arm64"]
19
+ }
20
+ ]
21
+ },
22
+ "win": {
23
+ "target": [
24
+ {
25
+ "target": "nsis",
26
+ "arch": ["x64"]
27
+ }
28
+ ],
29
+ "artifactName": "${productName}-${version}-${arch}.${ext}"
30
+ },
31
+ "linux": {
32
+ "target": ["AppImage", "deb"],
33
+ "category": "Development"
34
+ },
35
+ "publish": {
36
+ "provider": "github",
37
+ "owner": "dyyz1993",
38
+ "repo": "pi-agent-app"
39
+ }
40
+ }
@@ -13,6 +13,8 @@ export default tseslint.config(
13
13
  'node_modules/**',
14
14
  'build/**',
15
15
  'dist/**',
16
+ 'dist-electron/**',
17
+ 'electron/**',
16
18
  'postcss.config.js',
17
19
  'tailwind.config.js',
18
20
  ],
@@ -2,6 +2,54 @@
2
2
  "name": "pi-agent-app",
3
3
  "version": "1.0.0",
4
4
  "description": "Coding agent template with Bash, Rules, and Todo management",
5
+ "author": {
6
+ "name": "xuyingzhou",
7
+ "email": "xuyingzhou@tuzhanai.com"
8
+ },
9
+ "homepage": "https://github.com/dyyz1993/pi-agent-template",
10
+ "main": "electron/main.js",
11
+ "build": {
12
+ "appId": "com.piagent.app",
13
+ "productName": "Pi Agent",
14
+ "directories": {
15
+ "output": "dist-electron"
16
+ },
17
+ "files": [
18
+ "dist/**/*",
19
+ "electron/**/*",
20
+ "package.json"
21
+ ],
22
+ "mac": {
23
+ "category": "public.app-category.developer-tools",
24
+ "target": [
25
+ {
26
+ "target": "dmg",
27
+ "arch": [
28
+ "x64",
29
+ "arm64"
30
+ ]
31
+ }
32
+ ]
33
+ },
34
+ "win": {
35
+ "target": [
36
+ {
37
+ "target": "nsis",
38
+ "arch": [
39
+ "x64"
40
+ ]
41
+ }
42
+ ]
43
+ },
44
+ "linux": {
45
+ "maintainer": "xuyingzhou <xuyingzhou@tuzhanai.com>",
46
+ "target": [
47
+ "AppImage",
48
+ "deb"
49
+ ],
50
+ "category": "Development"
51
+ }
52
+ },
5
53
  "scripts": {
6
54
  "start": "vite build && electrobun dev",
7
55
  "dev": "electrobun dev --watch",
@@ -12,6 +60,11 @@
12
60
  "build:mac": "vite build && electrobun build --env=canary",
13
61
  "build:win": "vite build && electrobun build --env=canary",
14
62
  "build:linux": "vite build && electrobun build --env=canary",
63
+ "electron:dev": "vite build && electron .",
64
+ "electron:build": "vite build && electron-builder --mac --win --linux",
65
+ "electron:build:mac": "vite build && electron-builder --mac",
66
+ "electron:build:win": "vite build && electron-builder --win",
67
+ "electron:build:linux": "vite build && electron-builder --linux",
15
68
  "lint": "eslint .",
16
69
  "lint:fix": "eslint . --fix",
17
70
  "test": "vitest run",
@@ -45,10 +98,11 @@
45
98
  "@types/react": "^18.3.12",
46
99
  "@types/react-dom": "^18.3.1",
47
100
  "@types/ws": "^8.18.1",
48
- "ws": "^8.18.0",
49
101
  "@vitejs/plugin-react": "^4.3.4",
50
102
  "autoprefixer": "^10.4.20",
51
103
  "concurrently": "^9.1.0",
104
+ "electron": "^42.1.0",
105
+ "electron-builder": "^26.8.1",
52
106
  "eslint": "^9.0.0",
53
107
  "eslint-plugin-jsx-a11y": "^6.10.0",
54
108
  "eslint-plugin-react-hooks": "^5.2.0",
@@ -61,6 +115,10 @@
61
115
  "typescript": "^5.7.2",
62
116
  "typescript-eslint": "^8.0.0",
63
117
  "vite": "^6.0.3",
64
- "vitest": "^4.1.5"
118
+ "vitest": "^4.1.5",
119
+ "ws": "^8.18.0"
120
+ },
121
+ "overrides": {
122
+ "minimatch": "^10.0.1"
65
123
  }
66
124
  }
@@ -1,41 +1,44 @@
1
+ import type { ReactNode } from "react";
1
2
  import { useState } from "react";
2
3
  import { useConnectionStore } from "./stores/use-connection-store";
3
4
  import { useBreakpointSync } from "./hooks/use-breakpoint";
4
5
  import { useRpcInit } from "./hooks/use-rpc-init";
5
6
  import { useSidebarResize } from "./hooks/use-sidebar-resize";
6
7
  import { AppLayout, type CenterTab } from "./components/layout/AppLayout";
7
- import { ErrorBoundary } from "./components/common/ErrorBoundary";
8
+ import { ErrorBoundary as _EB } from "./components/common/ErrorBoundary";
9
+
10
+ const ErrorBoundary = _EB as unknown as React.FC<{ children: ReactNode }>;
8
11
 
9
12
  function App() {
10
- const ready = useConnectionStore((s) => s.ready);
11
- const [centerTab, setCenterTab] = useState<CenterTab>("chat");
13
+ const ready = useConnectionStore((s) => s.ready);
14
+ const [centerTab, setCenterTab] = useState<CenterTab>("chat");
12
15
 
13
- useBreakpointSync();
14
- useRpcInit();
16
+ useBreakpointSync();
17
+ useRpcInit();
15
18
 
16
- const { sidebarWidth, handleResizeStart } = useSidebarResize();
19
+ const { sidebarWidth, handleResizeStart } = useSidebarResize();
17
20
 
18
- if (!ready) {
19
- return (
20
- <div className="h-screen bg-gray-900 flex items-center justify-center">
21
- <div className="text-center">
22
- <div className="inline-block w-8 h-8 border-2 border-indigo-400 border-t-transparent rounded-full animate-spin mb-4" />
23
- <div className="text-gray-400 text-sm">Connecting to RPC server...</div>
24
- </div>
25
- </div>
26
- );
27
- }
21
+ if (!ready) {
22
+ return (
23
+ <div className="h-screen bg-gray-900 flex items-center justify-center">
24
+ <div className="text-center">
25
+ <div className="inline-block w-8 h-8 border-2 border-indigo-400 border-t-transparent rounded-full animate-spin mb-4" />
26
+ <div className="text-gray-400 text-sm">Connecting to RPC server...</div>
27
+ </div>
28
+ </div>
29
+ );
30
+ }
28
31
 
29
- return (
30
- <ErrorBoundary>
31
- <AppLayout
32
- centerTab={centerTab}
33
- setCenterTab={setCenterTab}
34
- sidebarWidth={sidebarWidth}
35
- handleResizeStart={handleResizeStart}
36
- />
37
- </ErrorBoundary>
38
- );
32
+ return (
33
+ <ErrorBoundary>
34
+ <AppLayout
35
+ centerTab={centerTab}
36
+ setCenterTab={setCenterTab}
37
+ sidebarWidth={sidebarWidth}
38
+ handleResizeStart={handleResizeStart}
39
+ />
40
+ </ErrorBoundary>
41
+ );
39
42
  }
40
43
 
41
44
  export default App;