diff --git a/.gitignore b/.gitignore index 65512c2..d65ea02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,31 +1,31 @@ # ---- 依赖与构建产物 ---- # # 前端只在**构建期**用到 npm:`npm run build` 出的 dist/ 被 cp 进 -# gateway/internal/static/static/ 再由 go:embed 编进二进制。 +# server/internal/static/static/ 再由 go:embed 编进二进制。 # 部署机上没有 node,产物就是「一个二进制 + 一个 .db 文件」。 # 因此这三样都不进版本库:装依赖与构建都能从 package-lock.json 复现。 -web/node_modules/ -web/dist/ +client/electron/node_modules/ +client/electron/dist/ plugins/*/node_modules/ # dsh-mail-bridge 是 TypeScript 写的,dist/ 是 tsc 的产物。 -# 与 web/dist 同一个理由:装依赖与构建都能从 package-lock.json 复现, +# 与 client/electron/dist 同一个理由:装依赖与构建都能从 package-lock.json 复现, # 产物不进版本库。注意它**必须在装插件前构建**(package.json 的 # main 指向 dist/index.js),deploy/install.sh 负责这一步。 plugins/*/dist/ -# go:embed 的输入目录 = web/dist 的副本,同属构建产物。 +# go:embed 的输入目录 = client/electron/dist 的副本,同属构建产物。 # # 但目录本身要留下:go:embed 要求它存在才能编译,否则新克隆连 # `go test ./...` 都跑不起来 —— 只改后端的人不该被迫先装 node。 # 因此忽略构建产物,只保留 placeholder.html(见该文件内注释: # 之所以不叫 index.html,是因为那正是 Vite 产物的名字,会被反复覆盖)。 -gateway/internal/static/static/* -!gateway/internal/static/static/placeholder.html +server/internal/static/static/* +!server/internal/static/static/placeholder.html # Go 构建产物 -gateway/agentmail-gateway -gateway/gw +server/agentmail-gateway +server/gw *.test # ---- 运行态数据 ---- diff --git a/README.md b/README.md index 8eb0a06..776e449 100644 --- a/README.md +++ b/README.md @@ -32,12 +32,12 @@ ```bash # 后端:默认用内置 SQLite,无需任何外部依赖 -cd gateway +cd server ADMIN_USER=admin ADMIN_PASSWORD=你的密码 go run ./cmd/server # → http://localhost:8180 # 前端(另开一个终端) -cd web +cd client/electron npm install npm run dev # → http://localhost:5173,自动代理到 8180 ``` @@ -75,10 +75,10 @@ bash deploy/redeploy-gateway.sh # 落地 ### 构建期依赖 npm 只在构建期用到:Node ≥ 18(`npm run build`)与 Go ≥ 1.22。 -`web/dist` 会被复制进 `gateway/internal/static/static/` 再由 `go:embed` 编入二进制, +`client/electron/dist` 会被复制进 `server/internal/static/static/` 再由 `go:embed` 编入二进制, **部署机上不需要 node**。 -`web/node_modules`、`web/dist`、`gateway/internal/static/static/` 的内容与编译出的二进制 +`client/electron/node_modules`、`client/electron/dist`、`server/internal/static/static/` 的内容与编译出的二进制 都是构建产物,不进版本库(见 `.gitignore`)。 新克隆**可以直接 `go build` / `go test`**:`static/` 目录里留了一个占位 index.html @@ -87,9 +87,13 @@ npm 只在构建期用到:Node ≥ 18(`npm run build`)与 Go ≥ 1.22。 `deploy/install.sh`,或手工: ```bash -cd web && npm ci && npm run build -rm -rf ../gateway/internal/static/static && cp -r dist ../gateway/internal/static/static -cd ../gateway && go build ./cmd/server +# 在仓库根目录执行 +npm --prefix client/electron ci +npm --prefix client/electron run build +rm -rf server/internal/static/static/assets +rm -f server/internal/static/static/index.html +cp -r client/electron/dist/. server/internal/static/static/ +(cd server && go build ./cmd/server) ``` ### 数据库 @@ -186,7 +190,7 @@ agentmail/ │ ├── PLAN.md # 分阶段实施计划 │ ├── MVP-SPEC.md # MVP 技术规格书 │ └── PLUGIN-CONTRACT.md # Agent 平台插件契约(规格 + 验收清单) -├── gateway/ # 后端(Go,单二进制) +├── server/ # 后端(Go,单二进制) │ ├── cmd/server/ # 入口与路由表 │ └── internal/ │ ├── db/ # 连接 + 方言适配 + 内嵌迁移 @@ -200,8 +204,10 @@ agentmail/ │ ├── opencode-mail-bridge/ # opencode(插件) │ ├── dsh-mail-bridge/ # DeepSeek Harness(Cordis 插件) │ └── pi-mail-bridge/ # pi(常驻守护进程,用 SDK 起会话) -├── web/ # 前端(React + Vite + Tailwind) -│ └── test/manual/ # 浏览器实测脚本(量真实盒子与命中区,不进 npm test) +├── client/ +│ ├── electron/ # Electron + React + Vite + Tailwind 客户端 +│ │ └── test/manual/ # 浏览器实测脚本(量真实盒子与命中区,不进 npm test) +│ └── harmony/ # HarmonyOS ArkUI 客户端 └── deploy/ # systemd 单元 + 安装脚本 ├── redeploy-gateway.sh # 二进制热替换(.backup + 原子 install + 后置验证 + 自动回滚) └── remote-agent-demo.py # 最小跨主机 Agent(纯标准库,验证协议层能力) @@ -223,8 +229,8 @@ agentmail/ ## 验证 ```bash -cd gateway && go build ./... && go test ./... # 后端 -cd web && npm run typecheck && npm test # 前端(含 Markdown XSS 回归测试) +cd server && go build ./... && go test ./... # 后端 +cd client/electron && npm run typecheck && npm test # 前端(含 Markdown XSS 回归测试) ``` ## WebAPI diff --git a/web/.gitignore b/client/electron/.gitignore similarity index 100% rename from web/.gitignore rename to client/electron/.gitignore diff --git a/web/electron/main.cjs b/client/electron/electron/main.cjs similarity index 96% rename from web/electron/main.cjs rename to client/electron/electron/main.cjs index a934bc9..d687f2a 100644 --- a/web/electron/main.cjs +++ b/client/electron/electron/main.cjs @@ -5,10 +5,10 @@ * - 创建 BrowserWindow 加载前端(dev=<ELECTRON_START_URL>,prod=../dist/index.html) * - 系统托盘(Phase 4 完整实现) * - 离线缓存(Phase 4) - * - 把 Gateway 地址与用户密钥注入渲染进程(Phase 2:让 web/src 以独立客户端身份连任意 Gateway) + * - 把 Gateway 地址与用户密钥注入渲染进程(Phase 2:让 client/electron/src 以独立客户端身份连任意 Gateway) * * 设计约束: - * - 渲染进程复用 web/src 的 React 代码,零改动 + * - 渲染进程复用 client/electron/src 的 React 代码,零改动 * - 只通过 contextBridge 暴露必要 API,不放开 nodeIntegration */ diff --git a/web/electron/preload.cjs b/client/electron/electron/preload.cjs similarity index 93% rename from web/electron/preload.cjs rename to client/electron/electron/preload.cjs index d9967b3..7fc26a9 100644 --- a/web/electron/preload.cjs +++ b/client/electron/electron/preload.cjs @@ -1,7 +1,7 @@ /** * AgentMail Electron preload —— 通过 contextBridge 暴露安全 API 给渲染进程。 * - * 渲染进程是 web/src 的 React,跑在 sandbox: true 下(无 nodeIntegration)。 + * 渲染进程是 client/electron/src 的 React,跑在 sandbox: true 下(无 nodeIntegration)。 * 需要桌面能力时(文件选择、通知、托盘角标、SSE 转发)走这里暴露的桥。 * * Phase 1 只暴露最小集;后续 Phase 逐步加。 diff --git a/web/index.html b/client/electron/index.html similarity index 95% rename from web/index.html rename to client/electron/index.html index fd4b893..0695bf1 100644 --- a/web/index.html +++ b/client/electron/index.html @@ -2,7 +2,7 @@ - + AgentMail