@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.
- package/package.json +1 -1
- package/src/commands/create.ts +31 -31
- package/src/commands/workspace.ts +112 -105
- package/src/lib/copy.ts +1 -0
- package/templates/agent/electron/main.js +46 -0
- package/templates/agent/electron/preload.js +5 -0
- package/templates/agent/electron-builder.json +40 -0
- package/templates/agent/eslint.config.mjs +2 -0
- package/templates/agent/package.json +60 -2
- package/templates/agent/src/mainview/App.tsx +29 -26
- package/templates/agent/src/mainview/components/chat/ChatPanel.tsx +88 -88
- package/templates/agent/src/mainview/components/file-preview/VirtualizedCodeView.tsx +105 -81
- package/templates/agent/src/mainview/components/search/SearchPanel.tsx +427 -378
- package/templates/agent/src/mainview/components/todo/TodoPanel.tsx +3 -3
- package/templates/agent/src/mainview/hooks/use-input-history.ts +70 -61
- package/templates/agent/src/mainview/lib/api-client.ts +1 -4
- package/templates/agent/src/mainview/main.tsx +4 -10
- package/templates/agent/src/mainview/stores/use-feed-store.ts +107 -107
- package/templates/agent/src/mainview/utils/drop-handler.ts +114 -115
- package/templates/agent/src/server-config.ts +1 -1
- package/templates/agent/src/server.ts +1 -2
- package/templates/agent/src/shared/handlers/chat.ts +5 -5
- package/templates/agent/src/shared/handlers/debug.ts +5 -1
- package/templates/agent/src/shared/handlers/git.ts +286 -243
- package/templates/agent/src/shared/http-routes.ts +1 -1
- package/templates/agent/src/shared/lib/bash-security.ts +43 -43
- package/templates/agent/tsconfig.ipc.json +5 -1
- package/templates/agent/tsconfig.json +3 -1
- package/templates/chat/package.json +3 -0
- package/templates/chat/src/mainview/hooks/use-input-history.ts +70 -61
- package/templates/chat/src/mainview/lib/api-client.ts +2 -5
- package/templates/chat/src/mainview/main.tsx +10 -7
- package/templates/chat/src/server-config.ts +1 -1
- package/templates/chat/src/server.ts +1 -2
- package/templates/chat/src/shared/handlers/chat.ts +5 -5
- package/templates/chat/src/shared/handlers/debug.ts +5 -1
- package/templates/chat/src/shared/http-routes.ts +1 -1
- package/templates/chat/tsconfig.ipc.json +5 -1
- package/templates/chat/tsconfig.json +12 -2
- package/templates/general/package.json +3 -0
- package/templates/general/src/mainview/components/file-preview/VirtualizedCodeView.tsx +101 -81
- package/templates/general/src/mainview/components/search/SearchPanel.tsx +429 -378
- package/templates/general/src/mainview/hooks/use-input-history.ts +70 -61
- package/templates/general/src/mainview/lib/api-client.ts +2 -5
- package/templates/general/src/mainview/main.tsx +10 -7
- package/templates/general/src/mainview/stores/use-feed-store.ts +107 -107
- package/templates/general/src/mainview/utils/drop-handler.ts +114 -115
- package/templates/general/src/server-config.ts +1 -1
- package/templates/general/src/server.ts +1 -2
- package/templates/general/src/shared/handlers/chat.ts +5 -5
- package/templates/general/src/shared/handlers/debug.ts +5 -1
- package/templates/general/src/shared/handlers/git.ts +286 -243
- package/templates/general/src/shared/http-routes.ts +1 -1
- package/templates/general/tsconfig.ipc.json +5 -1
- package/templates/general/tsconfig.json +12 -2
- package/templates/shared/components/ErrorBoundary.tsx +50 -49
- package/templates/shared/http-routes.ts +210 -190
package/package.json
CHANGED
package/src/commands/create.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { resolve } from
|
|
2
|
-
import { resolveTemplateDir, getRootDir } from
|
|
3
|
-
import { copyTemplate } from
|
|
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
|
-
|
|
7
|
-
|
|
6
|
+
let templateType = "general";
|
|
7
|
+
let customDir: string | undefined;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
37
|
-
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
await copyTemplate({
|
|
45
|
+
projectName: sanitized,
|
|
46
|
+
templateDir,
|
|
47
|
+
targetDir,
|
|
48
|
+
});
|
|
49
49
|
}
|
|
@@ -1,45 +1,50 @@
|
|
|
1
|
-
import { resolve } from
|
|
2
|
-
import { execSync } from
|
|
3
|
-
import { existsSync, readFileSync, mkdirSync } from
|
|
4
|
-
import { createServer } from
|
|
5
|
-
import type { PortEntry } from
|
|
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 ||
|
|
7
|
+
const PORT_REGISTRY = resolve(process.env.HOME || "~", ".pi-agent", "ports.json");
|
|
8
8
|
|
|
9
9
|
function readRegistry(): Record<string, PortEntry> {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
44
|
+
const subCommand = args[0];
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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,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
|
+
}
|
|
@@ -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
|
-
|
|
11
|
-
|
|
13
|
+
const ready = useConnectionStore((s) => s.ready);
|
|
14
|
+
const [centerTab, setCenterTab] = useState<CenterTab>("chat");
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
useBreakpointSync();
|
|
17
|
+
useRpcInit();
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
const { sidebarWidth, handleResizeStart } = useSidebarResize();
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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;
|