auto-coder-web 0.1.13__py3-none-any.whl → 0.1.15__py3-none-any.whl
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.
- auto_coder_web/auto_coder_runner.py +82 -1
- auto_coder_web/proxy.py +198 -74
- auto_coder_web/routers/__init__.py +0 -0
- auto_coder_web/routers/settings_router.py +76 -0
- auto_coder_web/routers/todo_router.py +156 -0
- auto_coder_web/types.py +72 -0
- auto_coder_web/version.py +1 -1
- auto_coder_web/web/asset-manifest.json +3 -3
- auto_coder_web/web/index.html +1 -1
- auto_coder_web/web/static/js/main.34adf43b.js +3 -0
- auto_coder_web/web/static/js/main.34adf43b.js.LICENSE.txt +144 -0
- auto_coder_web/web/static/js/main.34adf43b.js.map +1 -0
- {auto_coder_web-0.1.13.dist-info → auto_coder_web-0.1.15.dist-info}/METADATA +3 -2
- {auto_coder_web-0.1.13.dist-info → auto_coder_web-0.1.15.dist-info}/RECORD +17 -10
- {auto_coder_web-0.1.13.dist-info → auto_coder_web-0.1.15.dist-info}/WHEEL +0 -0
- {auto_coder_web-0.1.13.dist-info → auto_coder_web-0.1.15.dist-info}/entry_points.txt +0 -0
- {auto_coder_web-0.1.13.dist-info → auto_coder_web-0.1.15.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,156 @@
|
|
1
|
+
import os
|
2
|
+
import json
|
3
|
+
import uuid
|
4
|
+
import logging
|
5
|
+
import asyncio
|
6
|
+
import aiofiles
|
7
|
+
from fastapi import APIRouter, HTTPException
|
8
|
+
from pydantic import BaseModel
|
9
|
+
from typing import List, Optional
|
10
|
+
from datetime import datetime
|
11
|
+
from pathlib import Path
|
12
|
+
|
13
|
+
router = APIRouter()
|
14
|
+
|
15
|
+
# 配置存储路径
|
16
|
+
TODO_FILE = Path(".auto-coder/auto-coder.web/todos/todos.json")
|
17
|
+
|
18
|
+
# 确保目录存在
|
19
|
+
TODO_FILE.parent.mkdir(parents=True, exist_ok=True)
|
20
|
+
|
21
|
+
logger = logging.getLogger(__name__)
|
22
|
+
|
23
|
+
class TodoItem(BaseModel):
|
24
|
+
id: str
|
25
|
+
title: str
|
26
|
+
status: str # pending/developing/testing/done
|
27
|
+
priority: str # P0/P1/P2/P3
|
28
|
+
tags: List[str] = []
|
29
|
+
owner: Optional[str] = None
|
30
|
+
due_date: Optional[str] = None
|
31
|
+
created_at: str
|
32
|
+
updated_at: str
|
33
|
+
|
34
|
+
class CreateTodoRequest(BaseModel):
|
35
|
+
title: str
|
36
|
+
priority: str
|
37
|
+
tags: List[str] = []
|
38
|
+
|
39
|
+
class ReorderTodoRequest(BaseModel):
|
40
|
+
source_status: str
|
41
|
+
source_index: int
|
42
|
+
destination_status: str
|
43
|
+
destination_index: int
|
44
|
+
todo_id: str
|
45
|
+
|
46
|
+
async def load_todos() -> List[TodoItem]:
|
47
|
+
"""异步加载所有待办事项"""
|
48
|
+
if not await asyncio.to_thread(lambda: TODO_FILE.exists()):
|
49
|
+
return []
|
50
|
+
|
51
|
+
try:
|
52
|
+
async with aiofiles.open(TODO_FILE, mode='r') as f:
|
53
|
+
content = await f.read()
|
54
|
+
return [TodoItem(**item) for item in json.loads(content)]
|
55
|
+
except (json.JSONDecodeError, FileNotFoundError):
|
56
|
+
logger.error("Failed to parse todos.json, returning empty list")
|
57
|
+
return []
|
58
|
+
|
59
|
+
async def save_todos(todos: List[TodoItem]):
|
60
|
+
"""异步保存待办事项"""
|
61
|
+
async with aiofiles.open(TODO_FILE, mode='w') as f:
|
62
|
+
await f.write(json.dumps([todo.dict() for todo in todos], indent=2,ensure_ascii=False))
|
63
|
+
|
64
|
+
@router.get("/api/todos", response_model=List[TodoItem])
|
65
|
+
async def get_all_todos():
|
66
|
+
"""获取所有待办事项"""
|
67
|
+
return await load_todos()
|
68
|
+
|
69
|
+
@router.post("/api/todos", response_model=TodoItem)
|
70
|
+
async def create_todo(request: CreateTodoRequest):
|
71
|
+
"""创建新待办事项"""
|
72
|
+
todos = await load_todos()
|
73
|
+
|
74
|
+
new_todo = TodoItem(
|
75
|
+
id=str(uuid.uuid4()),
|
76
|
+
title=request.title,
|
77
|
+
status="pending",
|
78
|
+
priority=request.priority,
|
79
|
+
tags=request.tags,
|
80
|
+
created_at=datetime.now().isoformat(),
|
81
|
+
updated_at=datetime.now().isoformat()
|
82
|
+
)
|
83
|
+
|
84
|
+
todos.append(new_todo)
|
85
|
+
await save_todos(todos)
|
86
|
+
return new_todo
|
87
|
+
|
88
|
+
@router.put("/api/todos/{todo_id}", response_model=TodoItem)
|
89
|
+
async def update_todo(todo_id: str, update_data: dict):
|
90
|
+
"""更新待办事项"""
|
91
|
+
todos = await load_todos()
|
92
|
+
|
93
|
+
for index, todo in enumerate(todos):
|
94
|
+
if todo.id == todo_id:
|
95
|
+
updated_data = todos[index].dict()
|
96
|
+
updated_data.update(update_data)
|
97
|
+
updated_data["updated_at"] = datetime.now().isoformat()
|
98
|
+
todos[index] = TodoItem(**updated_data)
|
99
|
+
await save_todos(todos)
|
100
|
+
return todos[index]
|
101
|
+
|
102
|
+
raise HTTPException(status_code=404, detail="Todo not found")
|
103
|
+
|
104
|
+
@router.delete("/api/todos/{todo_id}")
|
105
|
+
async def delete_todo(todo_id: str):
|
106
|
+
"""删除待办事项"""
|
107
|
+
todos = await load_todos()
|
108
|
+
new_todos = [todo for todo in todos if todo.id != todo_id]
|
109
|
+
|
110
|
+
if len(new_todos) == len(todos):
|
111
|
+
raise HTTPException(status_code=404, detail="Todo not found")
|
112
|
+
|
113
|
+
await save_todos(new_todos)
|
114
|
+
return {"status": "success"}
|
115
|
+
|
116
|
+
@router.post("/api/todos/reorder")
|
117
|
+
async def reorder_todos(request: ReorderTodoRequest):
|
118
|
+
"""处理拖放排序"""
|
119
|
+
todos = await load_todos()
|
120
|
+
|
121
|
+
# 找到移动的待办事项
|
122
|
+
moved_todo = next((t for t in todos if t.id == request.todo_id), None)
|
123
|
+
if not moved_todo:
|
124
|
+
raise HTTPException(status_code=404, detail="Todo not found")
|
125
|
+
|
126
|
+
# 移除原位置
|
127
|
+
todos = [t for t in todos if t.id != request.todo_id]
|
128
|
+
|
129
|
+
# 更新状态
|
130
|
+
moved_todo.status = request.destination_status
|
131
|
+
moved_todo.updated_at = datetime.now().isoformat()
|
132
|
+
|
133
|
+
# 插入新位置
|
134
|
+
todos.insert(
|
135
|
+
await get_insert_index(todos, request.destination_status, request.destination_index),
|
136
|
+
moved_todo
|
137
|
+
)
|
138
|
+
|
139
|
+
await save_todos(todos)
|
140
|
+
return {"status": "success"}
|
141
|
+
|
142
|
+
async def get_insert_index(todos: List[TodoItem], status: str, destination_index: int) -> int:
|
143
|
+
"""计算插入位置的绝对索引"""
|
144
|
+
status_todos = [i for i, t in enumerate(todos) if t.status == status]
|
145
|
+
if not status_todos:
|
146
|
+
return len(todos)
|
147
|
+
|
148
|
+
# 确保目标索引在有效范围内
|
149
|
+
destination_index = min(max(destination_index, 0), len(status_todos))
|
150
|
+
|
151
|
+
# 如果目标列没有项目,直接插入到最后
|
152
|
+
if not status_todos:
|
153
|
+
return len(todos)
|
154
|
+
|
155
|
+
# 返回目标列中对应位置的索引
|
156
|
+
return status_todos[destination_index] if destination_index < len(status_todos) else status_todos[-1] + 1
|
auto_coder_web/types.py
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
from pydantic import BaseModel
|
2
|
+
from typing import List, Dict, Any, Optional
|
3
|
+
from datetime import datetime
|
4
|
+
|
5
|
+
|
6
|
+
class EventGetRequest(BaseModel):
|
7
|
+
request_id: str
|
8
|
+
|
9
|
+
|
10
|
+
class EventResponseRequest(BaseModel):
|
11
|
+
request_id: str
|
12
|
+
event: Dict[str, str]
|
13
|
+
response: str
|
14
|
+
|
15
|
+
|
16
|
+
class CompletionItem(BaseModel):
|
17
|
+
name: str
|
18
|
+
path: str
|
19
|
+
display: str
|
20
|
+
location: Optional[str] = None
|
21
|
+
|
22
|
+
|
23
|
+
class CompletionResponse(BaseModel):
|
24
|
+
completions: List[CompletionItem]
|
25
|
+
|
26
|
+
|
27
|
+
class ChatList(BaseModel):
|
28
|
+
name: str
|
29
|
+
messages: List[Dict[str, Any]]
|
30
|
+
|
31
|
+
|
32
|
+
class HistoryQuery(BaseModel):
|
33
|
+
query: str
|
34
|
+
timestamp: Optional[str] = None
|
35
|
+
|
36
|
+
|
37
|
+
class ValidationResponse(BaseModel):
|
38
|
+
success: bool
|
39
|
+
message: str = ""
|
40
|
+
queries: List[HistoryQuery] = []
|
41
|
+
|
42
|
+
|
43
|
+
class QueryWithFileNumber(BaseModel):
|
44
|
+
query: str
|
45
|
+
timestamp: Optional[str] = None
|
46
|
+
file_number: int
|
47
|
+
response: Optional[str] = None
|
48
|
+
urls: Optional[List[str]] = None
|
49
|
+
|
50
|
+
|
51
|
+
class ValidationResponseWithFileNumbers(BaseModel):
|
52
|
+
success: bool
|
53
|
+
message: str = ""
|
54
|
+
queries: List[QueryWithFileNumber] = []
|
55
|
+
|
56
|
+
|
57
|
+
class FileContentResponse(BaseModel):
|
58
|
+
success: bool
|
59
|
+
message: str = ""
|
60
|
+
content: Optional[str] = None
|
61
|
+
|
62
|
+
|
63
|
+
class FileChange(BaseModel):
|
64
|
+
path: str
|
65
|
+
change_type: str # "added" 或 "modified"
|
66
|
+
|
67
|
+
|
68
|
+
class CommitDiffResponse(BaseModel):
|
69
|
+
success: bool
|
70
|
+
message: str = ""
|
71
|
+
diff: Optional[str] = None
|
72
|
+
file_changes: Optional[List[FileChange]] = None
|
auto_coder_web/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.15"
|
@@ -1,15 +1,15 @@
|
|
1
1
|
{
|
2
2
|
"files": {
|
3
3
|
"main.css": "/static/css/main.10e5dd19.css",
|
4
|
-
"main.js": "/static/js/main.
|
4
|
+
"main.js": "/static/js/main.34adf43b.js",
|
5
5
|
"static/js/453.d855a71b.chunk.js": "/static/js/453.d855a71b.chunk.js",
|
6
6
|
"index.html": "/index.html",
|
7
7
|
"main.10e5dd19.css.map": "/static/css/main.10e5dd19.css.map",
|
8
|
-
"main.
|
8
|
+
"main.34adf43b.js.map": "/static/js/main.34adf43b.js.map",
|
9
9
|
"453.d855a71b.chunk.js.map": "/static/js/453.d855a71b.chunk.js.map"
|
10
10
|
},
|
11
11
|
"entrypoints": [
|
12
12
|
"static/css/main.10e5dd19.css",
|
13
|
-
"static/js/main.
|
13
|
+
"static/js/main.34adf43b.js"
|
14
14
|
]
|
15
15
|
}
|
auto_coder_web/web/index.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.34adf43b.js"></script><link href="/static/css/main.10e5dd19.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|