auto-coder-web 0.1.14__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.
@@ -39,6 +39,7 @@ from autocoder.index.symbols_utils import (
39
39
  SymbolsInfo,
40
40
  SymbolType,
41
41
  )
42
+ from autocoder.utils.llms import get_single_llm
42
43
 
43
44
 
44
45
  class SymbolItem(BaseModel):
@@ -48,7 +49,7 @@ class SymbolItem(BaseModel):
48
49
 
49
50
 
50
51
  class AutoCoderRunner:
51
- def __init__(self, project_path: str):
52
+ def __init__(self, project_path: str, product_mode: str = "pro"):
52
53
  self.project_path = project_path
53
54
  self.base_persist_dir = os.path.join(
54
55
  project_path, ".auto-coder", "plugins", "chat-auto-coder")
@@ -61,6 +62,8 @@ class AutoCoderRunner:
61
62
  "exclude_dirs": [],
62
63
  }
63
64
  self.load_memory()
65
+ # Configure product mode
66
+ self.configure("product_mode", product_mode)
64
67
 
65
68
  @contextmanager
66
69
  def redirect_stdout(self):
@@ -366,7 +369,9 @@ class AutoCoderRunner:
366
369
  return_paths=True
367
370
  )
368
371
  args = self.convert_yaml_to_config(execute_file)
369
- llm = byzerllm.ByzerLLM.from_default_model(args.code_model or args.model)
372
+ product_mode = conf.get("product_mode", "pro")
373
+ target_model = args.code_model or args.model
374
+ llm = get_single_llm(target_model, product_mode)
370
375
  uncommitted_changes = git_utils.get_uncommitted_changes(".")
371
376
  commit_message = git_utils.generate_commit_message.with_llm(
372
377
  llm).run(uncommitted_changes)
auto_coder_web/proxy.py CHANGED
@@ -6,7 +6,6 @@ from fastapi.staticfiles import StaticFiles
6
6
  import uvicorn
7
7
  import httpx
8
8
  import uuid
9
- from typing import Optional, Dict, List, Any
10
9
  import os
11
10
  import argparse
12
11
  import aiofiles
@@ -18,6 +17,21 @@ import sys
18
17
  from .file_group import FileGroupManager
19
18
  from .file_manager import get_directory_tree
20
19
  from .auto_coder_runner import AutoCoderRunner
20
+ from autocoder.agent.auto_filegroup import AutoFileGroup
21
+ from .types import (
22
+ EventGetRequest,
23
+ EventResponseRequest,
24
+ CompletionItem,
25
+ CompletionResponse,
26
+ ChatList,
27
+ HistoryQuery,
28
+ ValidationResponse,
29
+ QueryWithFileNumber,
30
+ ValidationResponseWithFileNumbers,
31
+ FileContentResponse,
32
+ FileChange,
33
+ CommitDiffResponse,
34
+ )
21
35
 
22
36
  from rich.console import Console
23
37
  from prompt_toolkit.shortcuts import radiolist_dialog
@@ -26,7 +40,6 @@ import subprocess
26
40
  from prompt_toolkit import prompt
27
41
  from pydantic import BaseModel
28
42
  from autocoder.utils.log_capture import LogCapture
29
- from typing import Optional, Dict, List, Any
30
43
  from .terminal import terminal_manager
31
44
  from autocoder.common import AutoCoderArgs
32
45
  import json
@@ -35,69 +48,11 @@ import yaml
35
48
  import git
36
49
  import hashlib
37
50
  from datetime import datetime
51
+ from autocoder.utils import operate_config_api
52
+ from .routers import todo_router
53
+ from .routers import settings_router
38
54
 
39
55
 
40
- class EventGetRequest(BaseModel):
41
- request_id: str
42
-
43
-
44
- class EventResponseRequest(BaseModel):
45
- request_id: str
46
- event: Dict[str, str]
47
- response: str
48
-
49
-
50
- class CompletionItem(BaseModel):
51
- name: str
52
- path: str
53
- display: str
54
- location: Optional[str] = None
55
-
56
-
57
- class CompletionResponse(BaseModel):
58
- completions: List[CompletionItem]
59
-
60
-
61
- class ChatList(BaseModel):
62
- name: str
63
- messages: List[Dict[str, Any]]
64
-
65
- class HistoryQuery(BaseModel):
66
- query: str
67
- timestamp: Optional[str] = None
68
-
69
- class ValidationResponse(BaseModel):
70
- success: bool
71
- message: str = ""
72
- queries: List[HistoryQuery] = []
73
-
74
- class QueryWithFileNumber(BaseModel):
75
- query: str
76
- timestamp: Optional[str] = None
77
- file_number: int
78
- response: Optional[str] = None
79
- urls: Optional[List[str]] = None
80
-
81
- class ValidationResponseWithFileNumbers(BaseModel):
82
- success: bool
83
- message: str = ""
84
- queries: List[QueryWithFileNumber] = []
85
-
86
- class FileContentResponse(BaseModel):
87
- success: bool
88
- message: str = ""
89
- content: Optional[str] = None
90
-
91
- class FileChange(BaseModel):
92
- path: str
93
- change_type: str # "added" 或 "modified"
94
-
95
- class CommitDiffResponse(BaseModel):
96
- success: bool
97
- message: str = ""
98
- diff: Optional[str] = None
99
- file_changes: Optional[List[FileChange]] = None
100
-
101
56
  def check_environment():
102
57
  """Check and initialize the required environment"""
103
58
  console = Console()
@@ -114,10 +69,8 @@ def check_environment():
114
69
  console.print(f"✗ {message}", style="red")
115
70
  else:
116
71
  console.print(f" {message}")
117
-
118
- first_time = False
119
- if not os.path.exists("actions") or not os.path.exists(".auto-coder"):
120
- first_time = True
72
+
73
+ if not os.path.exists("actions") or not os.path.exists(".auto-coder"):
121
74
  print_status("Project not initialized", "warning")
122
75
  init_choice = input(
123
76
  " Do you want to initialize the project? (y/n): ").strip().lower()
@@ -271,23 +224,113 @@ def check_environment():
271
224
  return True
272
225
 
273
226
 
227
+ def check_environment_lite():
228
+ """Check and initialize the required environment for lite mode"""
229
+ console = Console()
230
+ console.print("\n[blue]Initializing the environment (Lite Mode)...[/blue]")
231
+
232
+ def check_project():
233
+ """Check if the current directory is initialized as an auto-coder project"""
234
+ def print_status(message, status):
235
+ if status == "success":
236
+ console.print(f"✓ {message}", style="green")
237
+ elif status == "warning":
238
+ console.print(f"! {message}", style="yellow")
239
+ elif status == "error":
240
+ console.print(f"✗ {message}", style="red")
241
+ else:
242
+ console.print(f" {message}")
243
+
244
+ first_time = False
245
+ if not os.path.exists("actions") or not os.path.exists(".auto-coder"):
246
+ first_time = True
247
+ print_status("Project not initialized", "warning")
248
+ init_choice = input(
249
+ " Do you want to initialize the project? (y/n): ").strip().lower()
250
+ if init_choice == "y":
251
+ try:
252
+ if not os.path.exists("actions"):
253
+ os.makedirs("actions", exist_ok=True)
254
+ print_status("Created actions directory", "success")
255
+
256
+ if not os.path.exists(".auto-coder"):
257
+ os.makedirs(".auto-coder", exist_ok=True)
258
+ print_status(
259
+ "Created .auto-coder directory", "success")
260
+
261
+ subprocess.run(
262
+ ["auto-coder", "init", "--source_dir", "."], check=True)
263
+ print_status("Project initialized successfully", "success")
264
+ except subprocess.CalledProcessError:
265
+ print_status("Failed to initialize project", "error")
266
+ print_status(
267
+ "Please try to initialize manually: auto-coder init --source_dir .", "warning")
268
+ return False
269
+ else:
270
+ print_status("Exiting due to no initialization", "warning")
271
+ return False
272
+
273
+ print_status("Project initialization check complete", "success")
274
+ return True
275
+
276
+ if not check_project():
277
+ return False
278
+
279
+ def print_status(message, status):
280
+ if status == "success":
281
+ console.print(f"✓ {message}", style="green")
282
+ elif status == "warning":
283
+ console.print(f"! {message}", style="yellow")
284
+ elif status == "error":
285
+ console.print(f"✗ {message}", style="red")
286
+ else:
287
+ console.print(f" {message}")
288
+
289
+ # Setup deepseek api key
290
+ api_key_dir = os.path.expanduser("~/.auto-coder/keys")
291
+ api_key_file = os.path.join(api_key_dir, "api.deepseek.com")
292
+
293
+ if not os.path.exists(api_key_file):
294
+ print_status("API key not found", "warning")
295
+ api_key = prompt(HTML("<b>Please enter your API key: </b>"))
296
+
297
+ # Create directory if it doesn't exist
298
+ os.makedirs(api_key_dir, exist_ok=True)
299
+
300
+ # Save the API key
301
+ with open(api_key_file, "w") as f:
302
+ f.write(api_key)
303
+
304
+ print_status(f"API key saved successfully: {api_key_file}", "success")
305
+
306
+ print_status("Environment initialization complete", "success")
307
+ return True
308
+
309
+
274
310
  class ProxyServer:
275
- def __init__(self, project_path: str, quick: bool = False):
311
+ def __init__(self, project_path: str, quick: bool = False, product_mode: str = "pro"):
276
312
  self.app = FastAPI()
277
313
 
278
314
  if not quick:
279
- # Check the environment if not in quick mode
280
- if not check_environment():
281
- print(
282
- "\033[31mEnvironment check failed. Some features may not work properly.\033[0m")
315
+ # Check the environment based on product mode
316
+ if product_mode == "lite":
317
+ if not check_environment_lite():
318
+ print(
319
+ "\033[31mEnvironment check failed. Some features may not work properly.\033[0m")
320
+ else:
321
+ if not check_environment():
322
+ print(
323
+ "\033[31mEnvironment check failed. Some features may not work properly.\033[0m")
324
+
283
325
  self.setup_middleware()
284
326
 
285
327
  self.setup_static_files()
286
328
 
287
329
  self.setup_routes()
330
+
288
331
  self.client = httpx.AsyncClient()
289
332
  self.project_path = project_path
290
- self.auto_coder_runner = AutoCoderRunner(project_path)
333
+ self.auto_coder_runner = AutoCoderRunner(project_path, product_mode=product_mode)
291
334
  self.file_group_manager = FileGroupManager(self.auto_coder_runner)
292
335
 
293
336
  def setup_middleware(self):
@@ -308,6 +351,10 @@ class ProxyServer:
308
351
  "/static", StaticFiles(directory=self.static_dir), name="static")
309
352
 
310
353
  def setup_routes(self):
354
+
355
+ self.app.include_router(todo_router.router)
356
+ self.app.include_router(settings_router.router)
357
+
311
358
  @self.app.on_event("shutdown")
312
359
  async def shutdown_event():
313
360
  await self.client.aclose()
@@ -357,6 +404,42 @@ class ProxyServer:
357
404
  group = await self.file_group_manager.create_group(name, description)
358
405
  return group
359
406
 
407
+ @self.app.post("/api/file-groups/auto")
408
+ async def auto_create_groups(request: Request):
409
+ try:
410
+ data = await request.json()
411
+ file_size_limit = data.get("file_size_limit", 100)
412
+ skip_diff = data.get("skip_diff", False)
413
+ group_num_limit = data.get("group_num_limit", 10)
414
+
415
+ # Create AutoFileGroup instance
416
+ auto_grouper = AutoFileGroup(
417
+ operate_config_api.get_llm(self.auto_coder_runner.memory),
418
+ self.project_path,
419
+ skip_diff=skip_diff,
420
+ file_size_limit=file_size_limit,
421
+ group_num_limit=group_num_limit
422
+ )
423
+
424
+ # Get groups
425
+ groups = auto_grouper.group_files()
426
+
427
+ # Create groups using file_group_manager
428
+ for group in groups:
429
+ await self.file_group_manager.create_group(
430
+ name=group.name,
431
+ description=group.description
432
+ )
433
+ # Add files to the group
434
+ await self.file_group_manager.add_files_to_group(
435
+ group.name,
436
+ group.urls
437
+ )
438
+
439
+ return {"status": "success", "message": f"Created {len(groups)} groups"}
440
+ except Exception as e:
441
+ raise HTTPException(status_code=500, detail=str(e))
442
+
360
443
  @self.app.get("/api/os")
361
444
  async def get_os():
362
445
  return {"os": os.name}
@@ -843,6 +926,17 @@ class ProxyServer:
843
926
 
844
927
 
845
928
  def main():
929
+ from autocoder.rag.variable_holder import VariableHolder
930
+ from tokenizers import Tokenizer
931
+ try:
932
+ tokenizer_path = pkg_resources.resource_filename(
933
+ "autocoder", "data/tokenizer.json"
934
+ )
935
+ VariableHolder.TOKENIZER_PATH = tokenizer_path
936
+ VariableHolder.TOKENIZER_MODEL = Tokenizer.from_file(tokenizer_path)
937
+ except FileNotFoundError:
938
+ tokenizer_path = None
939
+
846
940
  parser = argparse.ArgumentParser(description="Proxy Server")
847
941
  parser.add_argument(
848
942
  "--port",
@@ -861,9 +955,31 @@ def main():
861
955
  action="store_true",
862
956
  help="Skip environment check",
863
957
  )
958
+ parser.add_argument(
959
+ "--product_mode",
960
+ type=str,
961
+ default="pro",
962
+ help="The mode of the auto-coder.chat, lite/pro default is pro",
963
+ )
964
+ parser.add_argument(
965
+ "--lite",
966
+ action="store_true",
967
+ help="Run in lite mode (equivalent to --product_mode lite)",
968
+ )
969
+ parser.add_argument(
970
+ "--pro",
971
+ action="store_true",
972
+ help="Run in pro mode (equivalent to --product_mode pro)",
973
+ )
864
974
  args = parser.parse_args()
865
975
 
866
- proxy_server = ProxyServer(quick=args.quick, project_path=os.getcwd())
976
+ # Handle lite/pro flags
977
+ if args.lite:
978
+ args.product_mode = "lite"
979
+ elif args.pro:
980
+ args.product_mode = "pro"
981
+
982
+ proxy_server = ProxyServer(quick=args.quick, project_path=os.getcwd(), product_mode=args.product_mode)
867
983
  uvicorn.run(proxy_server.app, host=args.host, port=args.port)
868
984
 
869
985
 
File without changes
@@ -0,0 +1,76 @@
1
+
2
+ import os
3
+ import json
4
+ import logging
5
+ import aiofiles
6
+ from fastapi import APIRouter, HTTPException
7
+ from pydantic import BaseModel
8
+ from typing import Optional
9
+ from pathlib import Path
10
+ import asyncio
11
+
12
+ router = APIRouter()
13
+
14
+ # 配置存储路径
15
+ SETTINGS_FILE = Path(".auto-coder/auto-coder.web/settings/settings.json")
16
+
17
+ # 确保目录存在
18
+ SETTINGS_FILE.parent.mkdir(parents=True, exist_ok=True)
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ class SettingsModel(BaseModel):
23
+ language: str = "zh"
24
+ theme: str = "dark"
25
+ font_size: int = 14
26
+ auto_save: bool = True
27
+ show_line_numbers: bool = True
28
+
29
+ async def load_settings() -> SettingsModel:
30
+ """异步加载设置"""
31
+ if not await asyncio.to_thread(lambda: SETTINGS_FILE.exists()):
32
+ # 如果文件不存在,返回默认设置
33
+ return SettingsModel()
34
+
35
+ try:
36
+ async with aiofiles.open(SETTINGS_FILE, mode='r') as f:
37
+ content = await f.read()
38
+ return SettingsModel(**json.loads(content))
39
+ except (json.JSONDecodeError, FileNotFoundError):
40
+ logger.error("Failed to parse settings.json, returning default settings")
41
+ return SettingsModel()
42
+
43
+ async def save_settings(settings: SettingsModel):
44
+ """异步保存设置"""
45
+ async with aiofiles.open(SETTINGS_FILE, mode='w') as f:
46
+ await f.write(settings.json(indent=2, ensure_ascii=False))
47
+
48
+ @router.get("/api/settings")
49
+ async def get_settings():
50
+ """获取当前设置"""
51
+ return await load_settings()
52
+
53
+ @router.post("/api/settings")
54
+ async def update_settings(settings: dict):
55
+ """更新设置"""
56
+ current_settings = await load_settings()
57
+ updated_settings = current_settings.copy(update=settings)
58
+ await save_settings(updated_settings)
59
+ return updated_settings
60
+
61
+ @router.post("/api/settings/language")
62
+ async def set_language(language: str):
63
+ """设置语言"""
64
+ if language not in ["zh", "en"]:
65
+ raise HTTPException(status_code=400, detail="Invalid language, must be 'zh' or 'en'")
66
+
67
+ current_settings = await load_settings()
68
+ current_settings.language = language
69
+ await save_settings(current_settings)
70
+ return {"status": "success", "language": language}
71
+
72
+ @router.get("/api/settings/language")
73
+ async def get_language():
74
+ """获取当前语言设置"""
75
+ settings = await load_settings()
76
+ return {"language": settings.language}
@@ -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
@@ -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.14"
1
+ __version__ = "0.1.15"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: auto_coder_web
3
- Version: 0.1.14
3
+ Version: 0.1.15
4
4
  Summary: auto-coder.web: A Python Project
5
5
  Author: allwefantasy
6
6
  Classifier: Programming Language :: Python :: 3.9
@@ -14,6 +14,7 @@ Requires-Dist: sse-starlette
14
14
  Requires-Dist: websockets
15
15
  Requires-Dist: pyyaml
16
16
  Requires-Dist: gitpython
17
+ Requires-Dist: filelock >=3.13.1
17
18
  Requires-Dist: pywinpty ; sys_platform == "win32"
18
19
 
19
20
  # auto-coder.web
@@ -1,12 +1,16 @@
1
1
  auto_coder_web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- auto_coder_web/auto_coder_runner.py,sha256=EAmRz05k5EVB9qA5Spmpbvju3LK9Pxm3Xf7qg4baRsQ,33547
2
+ auto_coder_web/auto_coder_runner.py,sha256=PIP1A_MgZRNBa4UtClvInPh1Nx7WzqqP5feiIwpMNeA,33815
3
3
  auto_coder_web/file_group.py,sha256=wS52bHDT_gATIrHgVq62Mv1JMLGzdY_AU08iPzw4eLU,2540
4
4
  auto_coder_web/file_manager.py,sha256=wYe0NKqclhB22zTXT7du-5WRqne65tAZiTVAKsEZiaA,4236
5
5
  auto_coder_web/hello.py,sha256=H-BM5gdpcfTT4T2pn7Q1qWfquf0jwzGRuOBozbc8dbA,741
6
6
  auto_coder_web/json_file_storage.py,sha256=elthpcdclXITX3jew2EtT-ypyxZzDAzG1U7_k3looHI,1757
7
- auto_coder_web/proxy.py,sha256=YiQNy3u2aDvXT1jA-qwJtDslxOL5Smh8DlWDi5MUsuk,34025
7
+ auto_coder_web/proxy.py,sha256=0AzStYys2Icu1aa8ostDWMYUS3mzUbZ_wt5A8ckI8NA,39414
8
8
  auto_coder_web/terminal.py,sha256=jtAH7FaC573cgxc7FnI_mOZ3D2dSCO3PrZN0OehtbNQ,9521
9
- auto_coder_web/version.py,sha256=PIBqEOI-nqKFL9oJAWQQwlHuujG9Cd7EmdxDrThNQto,23
9
+ auto_coder_web/types.py,sha256=TT-0UruUi67wz7w1DpjFyYeaCnkdKYviJvlpSnrdtD4,1435
10
+ auto_coder_web/version.py,sha256=qb0TalpSt1CbprnFyeLUKqgrqNtmnk9IoQQ7umAoXVY,23
11
+ auto_coder_web/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ auto_coder_web/routers/settings_router.py,sha256=YeOY2GLhpu8kLRXrUrN7-IMt_Do__Y30G2wNRvGTPiM,2363
13
+ auto_coder_web/routers/todo_router.py,sha256=RLQJnutyqaZ99mQYCEhP6Sa-4YLTQY8h_w_u91wCET8,4835
10
14
  auto_coder_web/web/asset-manifest.json,sha256=wMZ0EWByFk1v5uZSvsHWM8hdXoPB5CElcLiuQ4pSjmo,517
11
15
  auto_coder_web/web/favicon.ico,sha256=PRD32mxgMXg0AIFmjErFs66XQ8qaJiqw_NMS-7n0i90,3870
12
16
  auto_coder_web/web/index.html,sha256=RLmx4rvfb2Pxd26PABAdNonGTNlVhcRqgMxXPD7F1cQ,644
@@ -80,8 +84,8 @@ auto_coder_web/web/static/js/main.ba643932.js.map,sha256=TnZnz40mVLDqMY_cD4XjcIo
80
84
  auto_coder_web/web/static/js/main.e42ddc5a.js,sha256=zM68fonOP_NPcDnxjhNJ0U3po_BseB4Txcw1jhvXX2Y,2411836
81
85
  auto_coder_web/web/static/js/main.e42ddc5a.js.LICENSE.txt,sha256=8jQ4oaoc73xj13em8wGFYhQ1yI-ptBKC6Xj0rm6Cn8w,29382
82
86
  auto_coder_web/web/static/js/main.e42ddc5a.js.map,sha256=nUwutRS_UcVLB2wVpZ2xZVTSQJB3V7LWR9Kv2TXHQGM,8524283
83
- auto_coder_web-0.1.14.dist-info/METADATA,sha256=XbqF6lzeGPF0NFR7eJtaHMKFD3EURqygtrifF6PlWsE,1345
84
- auto_coder_web-0.1.14.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
85
- auto_coder_web-0.1.14.dist-info/entry_points.txt,sha256=oh8kd1ZecWDgdv-bIj_ru3phvl4scuxwXl9DK0Khltg,61
86
- auto_coder_web-0.1.14.dist-info/top_level.txt,sha256=UCzEw494Im0KvR-FTYf2jh-okqHvLsC_0JLOrQZoSpg,15
87
- auto_coder_web-0.1.14.dist-info/RECORD,,
87
+ auto_coder_web-0.1.15.dist-info/METADATA,sha256=D_wl-DgXlt03J7b9QOxFcvdYPizsfogFwqraj8UEfRQ,1378
88
+ auto_coder_web-0.1.15.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
89
+ auto_coder_web-0.1.15.dist-info/entry_points.txt,sha256=oh8kd1ZecWDgdv-bIj_ru3phvl4scuxwXl9DK0Khltg,61
90
+ auto_coder_web-0.1.15.dist-info/top_level.txt,sha256=UCzEw494Im0KvR-FTYf2jh-okqHvLsC_0JLOrQZoSpg,15
91
+ auto_coder_web-0.1.15.dist-info/RECORD,,