Skip to content

Commit 712f20a

Browse files
authored
Feat: Server refactor v1 (#1509)
1 parent 1e542f9 commit 712f20a

179 files changed

Lines changed: 5583 additions & 6053 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-view.yml

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ jobs:
1212
timeout-minutes: 120
1313

1414
strategy:
15+
fail-fast: false
1516
matrix:
1617
include:
1718
- os: macos-latest
@@ -39,6 +40,22 @@ jobs:
3940
run: |
4041
rm -rf node_modules
4142
rm -rf release
43+
rm -rf dist out build .vite
44+
rm -rf node_modules/.cache || true
45+
46+
# Clean build outputs on GitHub-hosted runners to avoid stale artifacts in current job
47+
- name: Clean build outputs (non-Windows)
48+
if: "!contains(matrix.os, 'self-hosted') && runner.os != 'Windows'"
49+
run: |
50+
rm -rf release dist out .vite
51+
rm -rf node_modules/.cache || true
52+
53+
- name: Clean build outputs (Windows)
54+
if: "!contains(matrix.os, 'self-hosted') && runner.os == 'Windows'"
55+
shell: pwsh
56+
run: |
57+
Remove-Item -Recurse -Force release, dist, out, .vite -ErrorAction SilentlyContinue
58+
Remove-Item -Recurse -Force node_modules/.cache -ErrorAction SilentlyContinue
4259
4360
- name: Setup Node.js
4461
if: "!contains(matrix.os, 'self-hosted')"
@@ -92,6 +109,20 @@ jobs:
92109
echo "LLVM_DIR=$(brew --prefix llvm@20)/lib/cmake/llvm" >> $GITHUB_ENV
93110
echo "CMAKE_PREFIX_PATH=$(brew --prefix llvm@20)/lib/cmake/llvm" >> $GITHUB_ENV
94111
112+
# Prebuild separately on macOS so signing/package issues are isolated
113+
- name: Build Release Files (macOS prebuild)
114+
if: runner.os == 'macOS'
115+
timeout-minutes: 45
116+
run: |
117+
npm run prebuild
118+
env:
119+
VITE_BASE_URL: ${{ secrets.VITE_BASE_URL }}
120+
VITE_PROXY_URL: ${{ secrets.VITE_PROXY_URL }}
121+
VITE_STACK_PROJECT_ID: ${{ secrets.VITE_STACK_PROJECT_ID }}
122+
VITE_STACK_PUBLISHABLE_CLIENT_KEY: ${{ secrets.VITE_STACK_PUBLISHABLE_CLIENT_KEY }}
123+
VITE_STACK_SECRET_SERVER_KEY: ${{ secrets.VITE_STACK_SECRET_SERVER_KEY }}
124+
USE_NPM_INSTALL_BUN: 'true'
125+
95126
# Step for macOS builds with signing
96127
- name: Build Release Files (macOS with signing)
97128
if: runner.os == 'macOS'
@@ -104,15 +135,28 @@ jobs:
104135
fi
105136
ulimit -n 65536 2>/dev/null || ulimit -n 10240 2>/dev/null || true
106137
echo "File descriptor limit: $(ulimit -n) (hard: $(ulimit -Hn 2>/dev/null || echo 'N/A'))"
107-
npm run prebuild
108-
npx electron-builder --mac --${{ matrix.arch }} --publish never
138+
139+
set +e
140+
npx electron-builder --mac dmg --${{ matrix.arch }} --publish never
141+
BUILD_EXIT=$?
142+
143+
if [ $BUILD_EXIT -ne 0 ]; then
144+
echo "First attempt failed with exit code $BUILD_EXIT"
145+
echo "Retrying once in 5 seconds..."
146+
sleep 5
147+
npx electron-builder --mac dmg --${{ matrix.arch }} --publish never
148+
BUILD_EXIT=$?
149+
fi
150+
151+
exit $BUILD_EXIT
109152
env:
110153
CSC_LINK: ${{ secrets.CERT_P12 }}
111154
CSC_KEY_PASSWORD: ${{ secrets.CERT_PASSWORD }}
112155
APPLE_ID: ${{ secrets.APPLE_ID }}
113156
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
114157
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
115158
VITE_BASE_URL: ${{ secrets.VITE_BASE_URL }}
159+
VITE_PROXY_URL: ${{ secrets.VITE_PROXY_URL }}
116160
VITE_STACK_PROJECT_ID: ${{ secrets.VITE_STACK_PROJECT_ID }}
117161
VITE_STACK_PUBLISHABLE_CLIENT_KEY: ${{ secrets.VITE_STACK_PUBLISHABLE_CLIENT_KEY }}
118162
VITE_STACK_SECRET_SERVER_KEY: ${{ secrets.VITE_STACK_SECRET_SERVER_KEY }}
@@ -127,6 +171,7 @@ jobs:
127171
npx electron-builder --win --${{ matrix.arch }} --publish never
128172
env:
129173
VITE_BASE_URL: ${{ secrets.VITE_BASE_URL }}
174+
VITE_PROXY_URL: ${{ secrets.VITE_PROXY_URL }}
130175
VITE_STACK_PROJECT_ID: ${{ secrets.VITE_STACK_PROJECT_ID }}
131176
VITE_STACK_PUBLISHABLE_CLIENT_KEY: ${{ secrets.VITE_STACK_PUBLISHABLE_CLIENT_KEY }}
132177
VITE_STACK_SECRET_SERVER_KEY: ${{ secrets.VITE_STACK_SECRET_SERVER_KEY }}
@@ -141,6 +186,7 @@ jobs:
141186
npx electron-builder --linux --${{ matrix.arch }} --publish never
142187
env:
143188
VITE_BASE_URL: ${{ secrets.VITE_BASE_URL }}
189+
VITE_PROXY_URL: ${{ secrets.VITE_PROXY_URL }}
144190
VITE_STACK_PROJECT_ID: ${{ secrets.VITE_STACK_PROJECT_ID }}
145191
VITE_STACK_PUBLISHABLE_CLIENT_KEY: ${{ secrets.VITE_STACK_PUBLISHABLE_CLIENT_KEY }}
146192
VITE_STACK_SECRET_SERVER_KEY: ${{ secrets.VITE_STACK_SECRET_SERVER_KEY }}
@@ -195,6 +241,7 @@ jobs:
195241
path: |
196242
release/*.AppImage
197243
retention-days: 5
244+
198245
merge-release:
199246
needs: build
200247
runs-on: ubuntu-latest

backend/app/controller/tool_controller.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import logging
1616
import os
1717
import shutil
18+
import threading
1819
import time
1920

2021
from fastapi import APIRouter, HTTPException
@@ -779,15 +780,13 @@ def is_port_in_use(port):
779780
bufsize=1, # Line buffered
780781
)
781782

782-
# Create async task to log Electron output
783-
async def log_electron_output():
783+
def log_electron_output():
784784
for line in iter(process.stdout.readline, ""):
785785
if line:
786786
logger.info(f"[ELECTRON OUTPUT] {line.strip()}")
787787

788-
import asyncio
789-
790-
asyncio.create_task(log_electron_output())
788+
log_thread = threading.Thread(target=log_electron_output, daemon=True)
789+
log_thread.start()
791790

792791
# Wait a bit for Electron to start
793792
import asyncio

backend/app/router.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ def register_routers(app: FastAPI, prefix: str = "") -> None:
7373
},
7474
]
7575

76+
app.include_router(health_controller.router, tags=["Health"])
77+
logger.info(
78+
"Registered Health router at root level for Docker health checks"
79+
)
80+
7681
for config in routers_config:
7782
app.include_router(
7883
config["router"], prefix=prefix, tags=config["tags"]

server/alembic/env.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
2-
# Licensed under the Apache License, Version 2.0 (the "License");
3-
# you may not use this file except in compliance with the License.
4-
# You may obtain a copy of the License at
5-
#
6-
# http://www.apache.org/licenses/LICENSE-2.0
7-
#
8-
# Unless required by applicable law or agreed to in writing, software
9-
# distributed under the License is distributed on an "AS IS" BASIS,
10-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11-
# See the License for the specific language governing permissions and
12-
# limitations under the License.
13-
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
1+
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
1414

1515
import pathlib
1616
import sys
@@ -25,7 +25,7 @@
2525
from sqlmodel import SQLModel
2626

2727
from alembic import context
28-
from app.component.environment import auto_import, env_not_empty
28+
from app.core.environment import auto_import, env_not_empty
2929

3030
# this is the Alembic Config object, which provides
3131
# access to the values within the .ini file in use.

server/alembic/versions/2026_02_06_0440-9464b9d89de7_feat_trigger.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424
from alembic import op
2525
import sqlalchemy as sa
2626
import sqlmodel.sql.sqltypes
27-
from app.type.trigger_types import ExecutionStatus
28-
from app.type.trigger_types import ExecutionType
29-
from app.type.trigger_types import ListenerType
30-
from app.type.trigger_types import RequestType
31-
from app.type.trigger_types import TriggerStatus
32-
from app.type.trigger_types import TriggerType
27+
from app.shared.types.trigger_types import ExecutionStatus
28+
from app.shared.types.trigger_types import ExecutionType
29+
from app.shared.types.trigger_types import ListenerType
30+
from app.shared.types.trigger_types import RequestType
31+
from app.shared.types.trigger_types import TriggerStatus
32+
from app.shared.types.trigger_types import TriggerType
3333
from sqlalchemy_utils.types import ChoiceType
3434

3535
# revision identifiers, used by Alembic.

server/app/__init__.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
2-
# Licensed under the Apache License, Version 2.0 (the "License");
3-
# you may not use this file except in compliance with the License.
4-
# You may obtain a copy of the License at
5-
#
6-
# http://www.apache.org/licenses/LICENSE-2.0
7-
#
8-
# Unless required by applicable law or agreed to in writing, software
9-
# distributed under the License is distributed on an "AS IS" BASIS,
10-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11-
# See the License for the specific language governing permissions and
12-
# limitations under the License.
13-
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
1+
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
1414

1515
from contextlib import asynccontextmanager
16-
from fastapi import FastAPI
16+
from fastapi import APIRouter, FastAPI
1717
from fastapi_pagination import add_pagination
1818
from fastapi_limiter import FastAPILimiter
19-
from app.component.environment import env_or_fail
19+
from app.core.environment import env_or_fail
2020
from redis import asyncio as aioredis
2121
import logging
2222

@@ -43,3 +43,5 @@ async def lifespan(app: FastAPI):
4343
lifespan=lifespan
4444
)
4545
add_pagination(api)
46+
47+
router = APIRouter()

server/app/api/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
14+
15+
"""Non-domain v1 API endpoints."""

server/app/api/demo_controller.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
14+
15+
"""Demo endpoint - uses v1 auth."""
16+
17+
from fastapi import APIRouter, Depends
18+
from fastapi_babel import _
19+
20+
from app.shared.auth import auth_optional
21+
22+
router = APIRouter(tags=["demo"])
23+
24+
25+
@router.get("/demo")
26+
def get(user=Depends(auth_optional)):
27+
return {"message": user.id if user else _("no auth"), "content": _("hello")}

server/app/controller/redirect_controller.py renamed to server/app/api/redirect_controller.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
2-
# Licensed under the Apache License, Version 2.0 (the "License");
3-
# you may not use this file except in compliance with the License.
4-
# You may obtain a copy of the License at
5-
#
6-
# http://www.apache.org/licenses/LICENSE-2.0
7-
#
8-
# Unless required by applicable law or agreed to in writing, software
9-
# distributed under the License is distributed on an "AS IS" BASIS,
10-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11-
# See the License for the specific language governing permissions and
12-
# limitations under the License.
131
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
14+
15+
"""Redirect controller - H11 XSS fix with json.dumps + encodeURIComponent."""
1416

1517
import json
1618

@@ -24,6 +26,7 @@
2426
def redirect_callback(code: str, request: Request):
2527
cookies = request.cookies
2628
cookies_json = json.dumps(cookies)
29+
safe_code = json.dumps(code)
2730

2831
html_content = f"""
2932
<!DOCTYPE html>
@@ -72,10 +75,10 @@ def redirect_callback(code: str, request: Request):
7275
<script>
7376
(function() {{
7477
const allCookies = {cookies_json};
75-
const baseUrl = "eigent://callback?code={code}";
78+
const code = {safe_code};
79+
const baseUrl = "eigent://callback?code=" + encodeURIComponent(code);
7680
let finalUrl = baseUrl;
7781
78-
// 自动跳转到应用
7982
window.location.href = finalUrl;
8083
}})();
8184
</script>

0 commit comments

Comments
 (0)