Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
69a22b4
feat: 克隆仓库并配置开发环境
badhope Jun 12, 2026
808a419
feat: initialize Python project structure with FastAPI
badhope Jun 12, 2026
cfbba69
feat: add database models for files, projects, and operations
badhope Jun 12, 2026
d8ea664
feat: 克隆仓库并配置开发环境
badhope Jun 12, 2026
18c57e4
feat: add parameter validation and logging utilities
badhope Jun 12, 2026
4f23164
feat: 克隆仓库并配置开发环境
badhope Jun 12, 2026
b3ec440
fix: 修复 Pydantic Config 弃用警告和 datetime.utcnow 弃用警告
badhope Jun 12, 2026
82b6912
feat: 克隆仓库并配置开发环境
badhope Jun 12, 2026
b653d48
feat: 完成所有核心功能实现
badhope Jun 12, 2026
737dcf5
fix: 修复 Pydantic Config 弃用警告,使用 model_config
badhope Jun 12, 2026
6eb9a87
refactor: 修复所有代码质量问题,提升代码规范性
badhope Jun 12, 2026
32ae638
feat: 添加插件管理 API 接口
badhope Jun 12, 2026
f047d5c
feat: 克隆仓库并配置开发环境
badhope Jun 12, 2026
e448748
chore(deps)(deps): bump the production-dependencies group with 5 updates
dependabot[bot] Jun 15, 2026
670b22c
chore(deps)(deps-dev): bump the development-dependencies group with 6…
dependabot[bot] Jun 15, 2026
6e3f986
ci(deps): bump pnpm/action-setup in the production-dependencies group
dependabot[bot] Jun 15, 2026
82c1e96
ci(deps): merge pnpm/action-setup bump (production-dependencies group)
badhope Jun 17, 2026
ef07212
chore(deps): merge development-dependencies group bump
badhope Jun 17, 2026
b5b3295
chore(deps): merge production-dependencies group bump
badhope Jun 17, 2026
d41599f
feat: merge trae/solo-agent AI dev assistant (backend + desktop)
badhope Jun 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:

- name: Install pnpm
if: steps.pm.outputs.pm == 'pnpm'
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v4.1.0
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v4.1.0
with:
version: 9

Expand Down Expand Up @@ -116,7 +116,7 @@ jobs:

- name: Install pnpm
if: steps.pm.outputs.pm == 'pnpm'
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v4.1.0
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v4.1.0
with:
version: 9

Expand Down
18 changes: 18 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# 应用配置
DEBUG=false
API_HOST=127.0.0.1
API_PORT=8000

# 大模型配置
LLM_PROVIDER=openai
OPENAI_API_KEY=your-api-key-here
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=gpt-4-turbo-preview

# Ollama 配置
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama2

# 路径配置
GIT_WORKSPACE=./workspace
PLUGINS_DIR=./plugins
22 changes: 22 additions & 0 deletions backend/ai_dev_assistant.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Metadata-Version: 2.4
Name: ai-dev-assistant
Version: 0.1.0
Summary: AI-powered development assistant with plugin system
Requires-Python: >=3.11
Requires-Dist: fastapi>=0.109.0
Requires-Dist: uvicorn[standard]>=0.27.0
Requires-Dist: langchain-core>=0.1.0
Requires-Dist: langchain-openai>=0.0.5
Requires-Dist: langchain-community>=0.0.10
Requires-Dist: pygit2>=1.13.0
Requires-Dist: pluggy>=1.3.0
Requires-Dist: pydantic>=2.5.0
Requires-Dist: pydantic-settings>=2.1.0
Requires-Dist: aiosqlite>=0.19.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: black>=23.12.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=1.8.0; extra == "dev"
33 changes: 33 additions & 0 deletions backend/ai_dev_assistant.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
pyproject.toml
ai_dev_assistant.egg-info/PKG-INFO
ai_dev_assistant.egg-info/SOURCES.txt
ai_dev_assistant.egg-info/dependency_links.txt
ai_dev_assistant.egg-info/requires.txt
ai_dev_assistant.egg-info/top_level.txt
app/__init__.py
app/config.py
app/database.py
app/main.py
app/api/files.py
app/api/git.py
app/core/__init__.py
app/core/context.py
app/core/file_organizer.py
app/core/git_manager.py
app/core/llm.py
app/models/__init__.py
app/models/file.py
app/models/operation.py
app/models/project.py
app/plugins/__init__.py
app/plugins/hookspecs.py
app/plugins/manager.py
app/plugins/builtin/__init__.py
app/plugins/builtin/example_plugin.py
app/utils/__init__.py
app/utils/logger.py
app/utils/validator.py
tests/test_file_organizer.py
tests/test_git.py
tests/test_llm.py
tests/test_plugins.py
1 change: 1 addition & 0 deletions backend/ai_dev_assistant.egg-info/dependency_links.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

18 changes: 18 additions & 0 deletions backend/ai_dev_assistant.egg-info/requires.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
fastapi>=0.109.0
uvicorn[standard]>=0.27.0
langchain-core>=0.1.0
langchain-openai>=0.0.5
langchain-community>=0.0.10
pygit2>=1.13.0
pluggy>=1.3.0
pydantic>=2.5.0
pydantic-settings>=2.1.0
aiosqlite>=0.19.0
python-dotenv>=1.0.0

[dev]
pytest>=7.4.0
pytest-asyncio>=0.23.0
black>=23.12.0
ruff>=0.1.0
mypy>=1.8.0
1 change: 1 addition & 0 deletions backend/ai_dev_assistant.egg-info/top_level.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
app
1 change: 1 addition & 0 deletions backend/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""AI Dev Assistant Backend"""
Binary file added backend/app/__pycache__/__init__.cpython-314.pyc
Binary file not shown.
Binary file added backend/app/__pycache__/config.cpython-314.pyc
Binary file not shown.
Binary file not shown.
Binary file added backend/app/__pycache__/main.cpython-314.pyc
Binary file not shown.
1 change: 1 addition & 0 deletions backend/app/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""API 路由模块"""
Binary file not shown.
Binary file added backend/app/api/__pycache__/git.cpython-314.pyc
Binary file not shown.
143 changes: 143 additions & 0 deletions backend/app/api/files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
"""文件管理 API"""
from pathlib import Path
from typing import List, Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.file_organizer import FileOrganizer
from app.database import get_db
from app.models.file import FileMetadata
from app.utils.logger import logger

router = APIRouter(prefix="/files", tags=["files"])


class FileResponse(BaseModel):
"""文件响应模型"""
id: int
file_path: str
file_name: str
file_type: str
category: Optional[str]
tags: Optional[str]
description: Optional[str]
size_bytes: int
created_at: str
updated_at: str

model_config = {"from_attributes": True}


class ScanRequest(BaseModel):
directory: str
recursive: bool = True


class OrganizeRequest(BaseModel):
source: str
target_dir: str
category: Optional[str] = None


@router.get("/", response_model=List[FileResponse])
async def list_files(
keyword: Optional[str] = Query(None),
category: Optional[str] = Query(None),
file_type: Optional[str] = Query(None),
limit: int = Query(100, ge=1, le=1000),
db: AsyncSession = Depends(get_db)
):
"""获取文件列表"""
organizer = FileOrganizer(db)
files = await organizer.search_files(
keyword=keyword,
category=category,
file_type=file_type,
limit=limit
)
return files


@router.post("/scan", response_model=List[FileResponse])
async def scan_directory(
request: ScanRequest,
db: AsyncSession = Depends(get_db)
):
"""扫描目录并导入文件元数据"""
organizer = FileOrganizer(db)

try:
files = await organizer.scan_directory(
Path(request.directory),
recursive=request.recursive
)

# 保存到数据库
saved_files = []
for metadata in files:
saved = await organizer.save_metadata(metadata)
saved_files.append(saved)

return saved_files
except Exception as e:
logger.error(f"扫描目录失败: {e}")
raise HTTPException(status_code=400, detail=str(e))


@router.post("/organize", response_model=FileResponse)
async def organize_file(
request: OrganizeRequest,
db: AsyncSession = Depends(get_db)
):
"""归档文件"""
organizer = FileOrganizer(db)

try:
metadata = await organizer.organize_file(
Path(request.source),
Path(request.target_dir),
request.category
)
return metadata
except Exception as e:
logger.error(f"归档文件失败: {e}")
raise HTTPException(status_code=400, detail=str(e))


@router.get("/{file_id}", response_model=FileResponse)
async def get_file(
file_id: int,
db: AsyncSession = Depends(get_db)
):
"""获取单个文件详情"""
from sqlalchemy import select

stmt = select(FileMetadata).where(FileMetadata.id == file_id)
result = await db.execute(stmt)
file = result.scalar_one_or_none()

if not file:
raise HTTPException(status_code=404, detail="文件不存在")

return file


@router.delete("/{file_id}")
async def delete_file(
file_id: int,
db: AsyncSession = Depends(get_db)
):
"""删除文件记录(不删除实际文件)"""
from sqlalchemy import delete, select

stmt = select(FileMetadata).where(FileMetadata.id == file_id)
result = await db.execute(stmt)
file = result.scalar_one_or_none()

if not file:
raise HTTPException(status_code=404, detail="文件不存在")

await db.execute(delete(FileMetadata).where(FileMetadata.id == file_id))
return {"message": "删除成功"}
114 changes: 114 additions & 0 deletions backend/app/api/git.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"""Git 操作 API"""
from pathlib import Path
from typing import List, Optional

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

from app.core.git_manager import git_manager
from app.utils.logger import logger

router = APIRouter(prefix="/git", tags=["git"])


class CloneRequest(BaseModel):
url: str
name: Optional[str] = None


class CommitRequest(BaseModel):
repo_path: str
message: str
files: Optional[List[str]] = None


class GitStatusResponse(BaseModel):
branch: str
is_clean: bool
modified_files: List[str]
untracked_files: List[str]


class GitCommitResponse(BaseModel):
hash: str
message: str
author: str
timestamp: str


@router.post("/clone")
async def clone_repository(request: CloneRequest):
"""克隆 Git 仓库"""
try:
repo_path = git_manager.clone_repository(request.url, request.name)
return {
"status": "success",
"repo_path": str(repo_path),
"message": f"仓库克隆成功: {repo_path}"
}
except Exception as e:
logger.error(f"克隆仓库失败: {e}")
raise HTTPException(status_code=400, detail=str(e))


@router.get("/status/{repo_path:path}", response_model=GitStatusResponse)
async def get_git_status(repo_path: str):
"""获取仓库状态"""
try:
status = git_manager.get_status(Path(repo_path))
return status
except Exception as e:
logger.error(f"获取仓库状态失败: {e}")
raise HTTPException(status_code=400, detail=str(e))


@router.get("/commits/{repo_path:path}", response_model=List[GitCommitResponse])
async def get_recent_commits(
repo_path: str,
limit: int = 10
):
"""获取最近的提交记录"""
try:
commits = git_manager.get_recent_commits(Path(repo_path), limit)
return [
GitCommitResponse(
hash=c.hash,
message=c.message,
author=c.author,
timestamp=c.timestamp.isoformat()
)
for c in commits
]
except Exception as e:
logger.error(f"获取提交记录失败: {e}")
raise HTTPException(status_code=400, detail=str(e))


@router.post("/pull")
async def pull_repository(repo_path: str):
"""拉取远程更新"""
try:
result = git_manager.pull_repository(Path(repo_path))
return result
except Exception as e:
logger.error(f"拉取更新失败: {e}")
raise HTTPException(status_code=400, detail=str(e))


@router.post("/commit")
async def commit_changes(request: CommitRequest):
"""提交更改"""
try:
commit_hash = git_manager.commit_changes(
Path(request.repo_path),
request.message,
request.files
)
return {
"status": "success",
"commit_hash": commit_hash,
"message": "提交成功"
}
except Exception as e:
logger.error(f"提交失败: {e}")
raise HTTPException(status_code=400, detail=str(e))
Loading
Loading