初始化提交

This commit is contained in:
陈二狗 2026-05-21 09:08:59 +08:00
parent 7459416316
commit fdb4e439cf
25 changed files with 75 additions and 78 deletions

View File

@ -1,8 +1,8 @@
# Neta Monorepo 环境变量配置示例
# GPU Guard Monorepo 环境变量配置示例
# 注意:后端数据库配置在 packages/backend/src/config/config.local.ts 中
# 后端端口
NODE_ENV=local
# AI 配置 (AI Flow 后端使用)
# AI 配置 (GPU Guard 后端使用)
OPENAI_API_KEY=your_openai_key

5
.gitignore vendored
View File

@ -62,10 +62,7 @@ coverage/
.cache/
.worktrees/
# Claude Code
.claude/settings.local.json
# Agent tooling
.claude/
.husky/
.superpowers/
/.husky/
/.claude/

View File

@ -1,6 +1,6 @@
# Neta AI电商 - AI驱动的电商自动化运营平台
# GPU Guard - GPU 智能监控与防护平台
> 基于 Midway.js + Vue 3 + NetaClaw AI引擎 的智能电商运营平台Monorepo 架构
> 基于 Midway.js + Vue 3 + AI引擎 的智能 GPU 监控平台Monorepo 架构
## 技术架构
@ -8,7 +8,7 @@
|------|---------|------|
| **后端** | Midway.js 3.20 + TypeScript 5.9 + TypeORM + Cool Admin | 8003 |
| **前端** | Vue 3.5 + Vite 5.4 + Element Plus 2.9 + Pinia | 9001 |
| **AI 引擎** | NetaClaw (ReAct 循环 + TypeBox Schema + WebSocket) | - |
| **AI 引擎** | AI Agent 引擎 (ReAct 循环 + TypeBox Schema + WebSocket) | - |
| **数据库** | MySQL 8.0+ | 3306 |
## 项目结构
@ -62,7 +62,7 @@ pnpm dev:frontend # 前端 http://localhost:9001
| 模块 | 路由前缀 | 用途 |
|------|---------|------|
| **agent** | `/agent/*` | Agent 对话、Skill 管理、模型渠道管理 |
| **agent** | `/agent/*` | 智能体对话、技能管理、模型渠道管理 |
| **base** | `/` | 登录、用户、角色、菜单、部门 |
## 数据库

View File

@ -1,8 +1,8 @@
{
"name": "neta-monorepo",
"name": "gpu-guard-monorepo",
"version": "0.1.0",
"private": true,
"description": "Neta AI电商 - AI驱动的电商自动化运营平台",
"description": "GPU Guard - GPU 智能监控与防护平台",
"pnpm": {
"overrides": {
"@cool-midway/core": "8.0.7"
@ -13,9 +13,9 @@
]
},
"scripts": {
"dev": "pnpm --parallel --filter @neta/backend --filter @neta/frontend dev",
"dev:backend": "pnpm --filter @neta/backend dev",
"dev:frontend": "pnpm --filter @neta/frontend dev",
"dev": "pnpm --parallel --filter @gpu-guard/backend --filter @gpu-guard/frontend dev",
"dev:backend": "pnpm --filter @gpu-guard/backend dev",
"dev:frontend": "pnpm --filter @gpu-guard/frontend dev",
"build": "pnpm --filter './packages/*' build",
"test": "pnpm --filter './packages/*' test",
"lint": "pnpm --filter './packages/*' lint",

View File

@ -1,8 +1,8 @@
# CLAUDE.md - Neta AI电商 后端
# CLAUDE.md - GPU Guard 后端
## 项目概述
Neta AI电商 后端 - 基于 Midway.js + Cool Admin 框架的 AI 电商运营平台后端。
GPU Guard 后端 - 基于 Midway.js + Cool Admin 框架的 GPU 智能监控平台后端。
**技术栈**: Midway.js 3.20 + TypeScript 5.9 + TypeORM + Cool Admin 8.x + MySQL 8+
**端口**: 8003

View File

@ -4,10 +4,10 @@ const { resolveTraySecret } = require('./dist/comm/runtime-secret');
const traySecret = resolveTraySecret(process.argv, process.env);
if (traySecret) {
process.env.NETA_TRAY_SECRET = traySecret;
process.env.GPU_GUARD_TRAY_SECRET = traySecret;
}
if (process.argv.includes('--no-browser')) {
process.env.NETA_NO_BROWSER = 'true';
process.env.GPU_GUARD_NO_BROWSER = 'true';
}
if (process.argv.includes('--version')) {
@ -17,7 +17,7 @@ if (process.argv.includes('--version')) {
const configArgIndex = process.argv.indexOf('--config');
if (configArgIndex > -1 && process.argv[configArgIndex + 1]) {
process.env.NETA_CONFIG_PATH = process.argv[configArgIndex + 1];
process.env.GPU_GUARD_CONFIG_PATH = process.argv[configArgIndex + 1];
}
try {

View File

@ -2,7 +2,7 @@ server:
port: 8003
data:
dir: "C:\\NetaData"
dir: "C:\\GPUGuardData"
autoOpenBrowser: true
@ -10,6 +10,6 @@ database:
type: mysql
host: "120.48.5.80"
port: 3306
username: "neta_test"
username: "cpu_guard"
password: "m8FmsnnfJ3znPkdx"
database: "neta_test"
database: "cpu_guard"

View File

@ -1,7 +1,7 @@
{
"name": "@neta/backend",
"name": "@gpu-guard/backend",
"version": "8.0.0",
"description": "AI Flow 审核平台后端 - 基于 Midway.js + Cool Admin 的 AI 流程编排引擎",
"description": "GPU Guard 平台后端 - 基于 Midway.js + Cool Admin 的 GPU 智能监控引擎",
"private": true,
"overrides": {
"@cool-midway/core": "8.0.7"

View File

@ -3,8 +3,8 @@
*
* Cool Admin LocationUtil.getRunPath() 通过 Error stack trace 中的
* node_modules 位置反推项目根目录 pnpm monorepo node_modules
* 被提升到根目录导致解析到 Neta-monorepo/dist 而非
* Neta-monorepo/packages/backend/dist(或src)使得模块配置无法加载
* 被提升到根目录导致解析到 GPU_GUARD_MONOREPO/dist 而非
* GPU_GUARD_MONOREPO/packages/backend/dist(或src)使得模块配置无法加载
*
* 本脚本通过 --require NODE_OPTIONS 在所有模块加载前修补 getRunPath
*/

View File

@ -12,9 +12,9 @@ export function acquireRuntimeLock(lockPath: string) {
const current = JSON.parse(fs.readFileSync(lockPath, 'utf8')) as { pid: number };
try {
process.kill(current.pid, 0);
throw new Error(`Neta 已在运行PID=${current.pid}`);
throw new Error(`GPU Guard 已在运行PID=${current.pid}`);
} catch (e: any) {
if (e.message?.includes('Neta 已在运行')) throw e;
if (e.message?.includes('GPU Guard 已在运行')) throw e;
// Stale lock — remove and retry
fs.rmSync(lockPath, { force: true });
fs.writeFileSync(lockPath, data, 'utf8');

View File

@ -16,7 +16,7 @@ export function validateRuntimeSecret(expected?: string, actual?: string | null)
export function resolveTraySecret(argv: string[], env: NodeJS.ProcessEnv) {
const index = argv.indexOf('--tray-secret');
if (index > -1 && argv[index + 1]) return argv[index + 1];
return env.NETA_TRAY_SECRET || '';
return env.GPU_GUARD_TRAY_SECRET || '';
}
export function createRuntimeSecret() {

View File

@ -109,15 +109,15 @@ export default {
},
},
autoOpenBrowser:
process.env.NETA_NO_BROWSER !== 'true' &&
((global as any).__NETA_EXTERNAL_CONFIG__?.autoOpenBrowser ?? false),
// NetaClaw Agent 引擎配置
process.env.GPU_GUARD_NO_BROWSER !== 'true' &&
((global as any).__GPU_GUARD_EXTERNAL_CONFIG__?.autoOpenBrowser ?? false),
// GPU Guard AI 引擎配置
netaclaw: {
defaultModel: 'anthropic:claude-sonnet-4-20250514',
apiKeys: {
anthropic: process.env.NETACLAW_ANTHROPIC_KEY ?? '',
openai: process.env.NETACLAW_OPENAI_KEY ?? '',
deepseek: process.env.NETACLAW_DEEPSEEK_KEY ?? '',
anthropic: process.env.GPUCLAW_ANTHROPIC_KEY ?? '',
openai: process.env.GPUCLAW_OPENAI_KEY ?? '',
deepseek: process.env.GPUCLAW_DEEPSEEK_KEY ?? '',
},
skillsDir: path.join(resolvedDataDir, 'skills'),
dataDir: resolvedDataDir,

View File

@ -3,7 +3,7 @@ import { MidwayConfig } from '@midwayjs/core';
import { entities } from '../entities';
import { TenantSubscriber } from '../modules/base/db/tenant';
const external = (global as any).__NETA_EXTERNAL_CONFIG__;
const external = (global as any).__GPU_GUARD_EXTERNAL_CONFIG__;
export default {
typeorm: {

View File

@ -86,20 +86,20 @@ export class MainConfiguration {
ensureDpiAware();
const dataDir = pDataPath();
const lockPath = path.join(dataDir, 'neta.lock');
const lockPath = path.join(dataDir, 'gpu-guard.lock');
const runtimeInfoPath = path.join(dataDir, 'runtime-info.json');
const configDir = path.dirname(process.env.NETA_CONFIG_PATH || process.execPath);
const configDir = path.dirname(process.env.GPU_GUARD_CONFIG_PATH || process.execPath);
const port = this.app.getConfig('koa.port');
const startedAt = new Date().toISOString();
(global as any).__NETA_RUNTIME_STARTED_AT__ = startedAt;
(global as any).__NETA_RUNTIME_READY__ = false;
(global as any).__GPU_GUARD_RUNTIME_STARTED_AT__ = startedAt;
(global as any).__GPU_GUARD_RUNTIME_READY__ = false;
acquireRuntimeLock(lockPath);
process.on('exit', () => releaseRuntimeLock(lockPath));
registerGracefulShutdown(async () => {
(global as any).__NETA_RUNTIME_READY__ = false;
(global as any).__GPU_GUARD_RUNTIME_READY__ = false;
clearRuntimeInfo(runtimeInfoPath);
releaseRuntimeLock(lockPath);
setTimeout(() => process.exit(0), 50);
@ -122,7 +122,7 @@ export class MainConfiguration {
.getAsync(DesktopOpConfigBootstrap);
await desktopOpBootstrap.ensureConfigAndLoad();
(global as any).__NETA_RUNTIME_READY__ = true;
(global as any).__GPU_GUARD_RUNTIME_READY__ = true;
writeRuntimeInfo(runtimeInfoPath, {
pid: process.pid,
ready: true,

View File

@ -1,7 +1,7 @@
# 【开发】环境变量
# 应用名称
VITE_NAME = "AI Flow 智能审核平台"
VITE_NAME = "GPU Guard 智能监控平台"
# 前端开发服务器端口
VITE_PORT = 9001

View File

@ -1,5 +1,5 @@
# 应用名称
VITE_NAME = "AI Flow 智能审核平台"
VITE_NAME = "GPU Guard 智能监控平台"
# 网络超时请求时间
VITE_TIMEOUT = 30000

View File

@ -1,8 +1,8 @@
# CLAUDE.md - Neta AI电商 前端
# CLAUDE.md - GPU Guard 前端
## 项目概述
Neta AI电商 前端 - 基于 Vue 3 + Cool Admin UI 的 AI 电商运营平台前端。
GPU Guard 前端 - 基于 Vue 3 + Cool Admin UI 的 GPU 智能监控平台前端。
**技术栈**: Vue 3.5 + TypeScript 5.5 + Vite 5.4 + Element Plus 2.9 + Pinia
**端口**: 9001
@ -95,7 +95,7 @@ service.project.info.info({ id: 1 }) // GET /admin/project/info/i
| 模块 | 路由前缀 | 关键页面 |
|------|---------|---------|
| **base** | `/` | 登录(Canvas星河动画)、首页、用户管理、角色管理、菜单管理、部门管理 |
| **agent** | `/agent/*` | Agent对话(WebSocket)、Agent管理、Skill管理、模型渠道管理、检测结果 |
| **agent** | `/agent/*` | 智能体对话(WebSocket)、智能体管理、技能管理、模型渠道管理、检测结果 |
| **project** | `/project/*` | 项目列表、项目详情(甘特图/日历/看板/列表四视图) |
| **data** | `/data/*` | 商业健康险创新药、医保药品管理 |
| **dict** | `/dict/*` | 字典管理 |

View File

@ -1,5 +1,5 @@
{
"name": "@neta/frontend",
"name": "@gpu-guard/frontend",
"version": "8.0.0",
"type": "module",
"scripts": {

View File

@ -3,27 +3,27 @@ import { type ModuleConfig } from '/@/cool';
export default (): ModuleConfig => {
return {
name: 'agent',
label: 'Agent 对话',
label: 'AI 智能体',
order: 100,
views: [
{
path: '/agent/chat',
meta: { label: 'Agent 对话' },
meta: { label: '智能体对话' },
component: () => import('./views/chat.vue')
},
{
path: '/agent/agents',
meta: { label: 'Agent 管理' },
meta: { label: '智能体管理' },
component: () => import('./views/agent-list.vue')
},
{
path: '/agent/tools',
meta: { label: 'Tool 管理' },
meta: { label: '工具管理' },
component: () => import('./views/tools.vue')
},
{
path: '/agent/skills',
meta: { label: 'Skill 管理' },
meta: { label: '技能管理' },
component: () => import('./views/skills.vue')
},
{
@ -43,7 +43,7 @@ export default (): ModuleConfig => {
},
{
path: '/agent/crew-editor',
meta: { label: 'Agent 编排' },
meta: { label: '智能体编排' },
component: () => import('./views/crew-editor.vue')
},
{

View File

@ -3,7 +3,7 @@
<div class="channel-page__header">
<div class="channel-page__title">
<h2>频道管理</h2>
<p>支持两种模式<strong>ClawBot 私聊助手</strong>扫码登录独立 bot 账号用于一对一私聊<strong>微信本地代理 weixin-db</strong>从本机 PC 微信数据库读取消息用于群聊场景 Windows + 已登录 PC 微信</p>
<p>支持两种模式<strong>微信私聊助手</strong>扫码登录独立 bot 账号用于一对一私聊<strong>微信本地代理 weixin-db</strong>从本机 PC 微信数据库读取消息用于群聊场景 Windows + 已登录 PC 微信</p>
</div>
<div class="channel-page__actions">
<el-select v-model="filters.loginStatus" clearable placeholder="连接状态" style="width: 140px">
@ -96,7 +96,7 @@
<div class="channel-card__footer">
<el-button link type="primary" @click="handleEdit(item)">编辑</el-button>
<el-button v-if="item.type === 'weixin'" link type="success" @click="openQrDialog(item)">
ClawBot 扫码登录
微信Bot 扫码登录
</el-button>
<el-button
v-if="(item.type === 'weixin' && item.loginStatus === 'connected') || item.type === 'weixin-db'"
@ -151,7 +151,7 @@
<el-select v-model="drawer.form.type" style="width: 100%" :disabled="drawer.isEdit">
<el-option v-for="item in options.types" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<div class="form-hint">微信本地代理 weixin-db 从本机 PC 微信数据库读取消息 Windows 可用ClawBot 通过扫码登录 iLink编辑后不可修改类型</div>
<div class="form-hint">微信本地代理 weixin-db 从本机 PC 微信数据库读取消息 Windows 可用微信Bot 通过扫码登录 iLink编辑后不可修改类型</div>
</el-form-item>
<el-form-item
v-if="drawer.form.type === 'weixin'"
@ -168,7 +168,7 @@
</el-select>
</el-form-item>
<!-- ClawBot 专属字段 -->
<!-- 微信Bot 专属字段 -->
<template v-if="drawer.form.type === 'weixin'">
<el-form-item label="机器人昵称" prop="botAlias">
<el-input
@ -283,7 +283,7 @@
</template>
</el-drawer>
<el-dialog v-model="qrDialog.visible" title="ClawBot 扫码登录(个人微信助手)" width="420px" @closed="stopQrPolling">
<el-dialog v-model="qrDialog.visible" title="微信Bot 扫码登录(个人微信助手)" width="420px" @closed="stopQrPolling">
<div class="qr-dialog" v-loading="qrDialog.loading">
<template v-if="qrDialog.qrcodeUrl">
<img class="qr-image" :src="qrImageSrc(qrDialog.qrcodeUrl)" alt="微信二维码" />
@ -340,7 +340,7 @@ const desktopAgents = computed(() => allAgents.value);
const options = reactive({
types: [
{ value: 'weixin', label: '微信 ClawBot个人助手 · 仅私聊)' },
{ value: 'weixin', label: '微信Bot个人助手 · 仅私聊)' },
{ value: 'weixin-db', label: '微信本地代理(群聊 · 需 Windows + PC 微信)' },
],
loginStatuses: [] as Array<{ value: string; label: string }>,
@ -414,7 +414,7 @@ const rules = computed<FormRules>(() => ({
? [{ required: true, message: '请选择要绑定的 Agent', trigger: 'change' }]
: [],
botAlias: drawer.form.type === 'weixin'
? [{ required: true, message: 'ClawBot 渠道必须填写机器人昵称', trigger: 'blur' }]
? [{ required: true, message: '微信Bot 渠道必须填写机器人昵称', trigger: 'blur' }]
: [],
wxid: drawer.form.type === 'weixin-db'
? [{ required: true, message: 'weixin-db 渠道必须填写 wxid', trigger: 'blur' }]
@ -471,7 +471,7 @@ async function loadOptions() {
merged.push({ value: 'weixin-db', label: '微信本地代理(群聊 · 需 Windows + PC 微信)' });
}
if (!merged.find((t: any) => t.value === 'weixin')) {
merged.unshift({ value: 'weixin', label: '微信 ClawBot个人助手 · 仅私聊)' });
merged.unshift({ value: 'weixin', label: '微信Bot个人助手 · 仅私聊)' });
}
options.types = merged;
options.loginStatuses = data.data.loginStatuses || [];
@ -535,7 +535,7 @@ function handleEdit(item: AgentChannelInfo) {
const normalizedType: 'weixin' | 'weixin-db' =
allowedTypes.includes(item.type as any) ? (item.type as 'weixin' | 'weixin-db') : 'weixin';
if (item.type && !allowedTypes.includes(item.type as any)) {
ElMessage.warning(`未知频道类型 "${item.type}",已退化为 ClawBot`);
ElMessage.warning(`未知频道类型 "${item.type}",已退化为微信Bot`);
}
const wr = (item.config as any)?.weixinReply;
drawer.form = {
@ -581,7 +581,7 @@ async function handleSave() {
try {
const trimmedAlias = (drawer.form.botAlias || '').trim();
const existingConfig = drawer.form.config || {};
// :ClawBot credential, normalizePayload existing( iLink token)
// :Bot credential, normalizePayload existing( iLink token)
// weixin-db wxid credential ( wxid PC )
const payload: Record<string, any> = {
id: drawer.form.id,
@ -741,7 +741,7 @@ async function refreshQr() {
const data = await apiPost('/admin/netaclaw/agent_channel/weixin/qr', { id: qrDialog.channelId });
if (data.code === 1000) {
qrDialog.qrcodeUrl = data.data.qrcodeUrl;
qrDialog.tip = '请使用个人微信扫码 ClawBot,扫码后页面会自动确认登录状态';
qrDialog.tip = '请使用个人微信扫码登录,扫码后页面会自动确认登录状态';
startQrPolling();
} else {
ElMessage.error(data.message || '二维码获取失败');

View File

@ -23,7 +23,7 @@
/>
<section class="conversation-panel">
<conversation-header
:title="currentAgent?.label || currentAgent?.name || 'Neta Runtime'"
:title="currentAgent?.label || currentAgent?.name || 'GPU Guard Runtime'"
:entry-count="visibleConversationEntries.length"
:session-provider-label="sessionProviderLabel"
:session-cwd-label="sessionCwdLabel"

View File

@ -12,7 +12,7 @@
<span>{{ app.info.name }}</span>
</div>
<p class="desc">{{ $t('AI 智能审核与流程编排平台') }}</p>
<p class="desc">{{ $t('GPU 智能监控与防护平台') }}</p>
<div class="form">
<el-form label-position="top" class="form" :disabled="saving">
@ -65,7 +65,7 @@
</div>
</div>
<span class="copyright">Copyright © 睿智毅行 v1.0</span>
<span class="copyright">Copyright © GPU Guard v1.0</span>
</div>
</template>

View File

@ -1,7 +1,7 @@
{
"name": "@neta/netabrowser-cli",
"name": "@gpu-guard/netabrowser-cli",
"version": "0.1.0",
"description": "Neta 反风控+拟人化浏览器自动化 CLI",
"description": "GPU Guard 反检测浏览器自动化 CLI",
"private": true,
"type": "module",
"bin": {

View File

@ -1,5 +1,5 @@
{
"name": "@neta/shared",
"name": "@gpu-guard/shared",
"version": "0.1.0",
"type": "module",
"main": "./index.ts",

View File

@ -6,18 +6,18 @@ const { exec } = require('child_process')
const services = [
{
name: '后端',
title: 'Neta - 后端 (8003)',
command: 'pnpm --filter @neta/backend dev'
title: 'GPU Guard - 后端 (8003)',
command: 'pnpm --filter @gpu-guard/backend dev'
},
{
name: '前端',
title: 'Neta - 前端 (9001)',
command: 'pnpm --filter @neta/frontend dev'
title: 'GPU Guard - 前端 (9001)',
command: 'pnpm --filter @gpu-guard/frontend dev'
},
{
name: '桌面端',
title: 'Neta - 桌面端 (Tauri)',
command: 'pnpm --filter @neta/desktop dev'
title: 'GPU Guard - 桌面端 (Tauri)',
command: 'pnpm --filter @gpu-guard/desktop dev'
}
]