merge: cập nhật từ origin/feature/delta-team/epic-R04 (dọn dead code, gộp i18n/theme, CASAN Gate O, launcher)
Kéo 7 commit mới từ remote — chủ yếu dọn dẹp và siết chất lượng, không đổi API đang dùng: - Xoá 1.400 dòng mã chết + 5 gói rỗng còn sót sau các lần merge trước. - Thêm CASAN Gate O (LOC) áp cho toàn cây mã. - Sửa 5 checker UI hỏng sau đợt tách widget R08, vá 4 hồi quy. - install.bat/run.bat, gộp requirements-test.txt vào requirements.txt. - Gom i18n_*.py / theme_*.py rời rạc thành gói i18n/ và theme/. Merge sạch, không có conflict marker nào (git tự resolve toàn bộ). Đã kiểm tra lại 4 điểm đã vá ở 2 lần merge trước (config.py circular import, ai_edit_model_resolver.py dùng resolve() thay route_turn(), _confirm_routing_switch nhận timeout, RoutingApplicationService.resolve()) — cả 4 vẫn nguyên vẹn sau merge này. pytest tests/: 793 passed — giống hệt số liệu trước khi merge, không phát sinh fail/error mới (8 fail còn lại vẫn là do môi trường sandbox: thiếu keyring, tên thư mục cowork-local vs cowork_local). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,9 @@ class AtomicJsonFile:
|
||||
"""
|
||||
|
||||
def __init__(self, path: Path, *, indent: int = 2):
|
||||
"""Trỏ vào một file JSON. ``indent`` giữ file còn đọc và so sánh được bằng mắt
|
||||
trong git diff.
|
||||
"""
|
||||
self.path = Path(path)
|
||||
self.indent = indent
|
||||
|
||||
@@ -63,6 +66,10 @@ class AtomicJsonFile:
|
||||
return default
|
||||
|
||||
def _quarantine(self) -> Path | None:
|
||||
"""Đổi tên file JSON hỏng thành ``.bad-<mốc thời gian>`` thay vì xoá.
|
||||
|
||||
Giữ lại để còn cứu dữ liệu, và để lần ghi sau bắt đầu từ file sạch.
|
||||
"""
|
||||
stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
target = self.path.with_suffix(self.path.suffix + f".bad-{stamp}")
|
||||
try:
|
||||
@@ -125,7 +132,9 @@ class AtomicJsonFile:
|
||||
|
||||
# ---- tiện ích -------------------------------------------------------
|
||||
def exists(self) -> bool:
|
||||
"""File đã tồn tại trên đĩa chưa."""
|
||||
return self.path.exists()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Biểu diễn ngắn kèm đường dẫn, cho log và thông báo lỗi."""
|
||||
return f"AtomicJsonFile({self.path})"
|
||||
|
||||
@@ -22,6 +22,11 @@ class ConversationRepository:
|
||||
``directory`` (defaults to the app's real ``HISTORY_DIR``)."""
|
||||
|
||||
def __init__(self, directory: Optional[Path] = None) -> None:
|
||||
"""``directory`` để None thì dùng thư mục lịch sử mặc định.
|
||||
|
||||
Import muộn ngay trong thân hàm để nạp module này không kéo theo cả cây cấu
|
||||
hình — test trỏ thẳng vào ``tmp_path``.
|
||||
"""
|
||||
if directory is not None:
|
||||
self._directory = Path(directory)
|
||||
else:
|
||||
@@ -29,18 +34,28 @@ class ConversationRepository:
|
||||
self._directory = HISTORY_DIR
|
||||
|
||||
def new_session_id(self) -> str:
|
||||
"""Sinh id phiên mới cho một cuộc hội thoại."""
|
||||
return new_session_id()
|
||||
|
||||
def save(self, kind: str, session_id: str, messages: List[Dict[str, Any]], **kwargs) -> Path:
|
||||
"""Ghi hội thoại xuống đĩa (ghi nguyên tử) và trả về đường dẫn file."""
|
||||
return save_conversation(self._directory, kind, session_id, messages, **kwargs)
|
||||
|
||||
def load(self, path: Path) -> Dict[str, Any]:
|
||||
"""Đọc một hội thoại từ đường dẫn file."""
|
||||
return load_conversation(path)
|
||||
|
||||
def list(self, query: str = "", **kwargs) -> List[Dict[str, Any]]:
|
||||
"""Liệt kê hội thoại trong thư mục; ``query`` lọc theo tiêu đề và nội dung."""
|
||||
return list_conversations(self._directory, query=query)
|
||||
|
||||
def _resolve_path(self, target: Any) -> Path:
|
||||
"""Đổi id phiên (hoặc đường dẫn) thành đường dẫn file thật.
|
||||
|
||||
Nhận cả ba dạng: Path sẵn, đường dẫn tuyệt đối, và id phiên trần —
|
||||
id trần thì dò theo mẫu ``*__<id>.json`` vì tiền tố là loại hội thoại
|
||||
(cowork/co4e/...) mà chỗ gọi không phải lúc nào cũng biết.
|
||||
"""
|
||||
if isinstance(target, Path):
|
||||
return target
|
||||
p = Path(str(target))
|
||||
@@ -51,12 +66,15 @@ class ConversationRepository:
|
||||
return self._directory / f"cowork__{target}.json"
|
||||
|
||||
def rename(self, target: Any, new_title: str) -> None:
|
||||
"""Đổi tiêu đề một hội thoại."""
|
||||
rename_conversation(self._resolve_path(target), new_title)
|
||||
|
||||
def delete(self, target: Any) -> None:
|
||||
"""Xoá hẳn một hội thoại khỏi đĩa."""
|
||||
delete_conversation(self._resolve_path(target))
|
||||
|
||||
def set_pinned(self, target: Any, pinned: bool) -> None:
|
||||
"""Ghim/bỏ ghim một hội thoại để nó nằm trên đầu danh sách lịch sử."""
|
||||
set_pinned(self._resolve_path(target), pinned)
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,11 @@ class TaskRepository:
|
||||
folder)."""
|
||||
|
||||
def __init__(self, directory: Optional[Path] = None) -> None:
|
||||
"""``directory`` để None thì dùng thư mục task mặc định.
|
||||
|
||||
Hai đường import cho cùng một hằng số: gói có thể được nạp dưới tên đầy đủ
|
||||
``cowork_local`` hoặc dưới dạng tương đối tuỳ cách chạy.
|
||||
"""
|
||||
if directory is None:
|
||||
try:
|
||||
from cowork_local.core.tasks import TASKS_DIR
|
||||
@@ -39,6 +44,7 @@ class TaskRepository:
|
||||
self._directory = directory
|
||||
|
||||
def list(self) -> List[Dict[str, Any]]:
|
||||
"""Liệt kê mọi task trong thư mục."""
|
||||
try:
|
||||
from cowork_local.core.tasks import list_tasks
|
||||
except ImportError:
|
||||
@@ -46,6 +52,7 @@ class TaskRepository:
|
||||
return list_tasks(self._directory)
|
||||
|
||||
def get(self, task_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""Đọc một task theo id; trả về ``None`` nếu không có."""
|
||||
try:
|
||||
from cowork_local.core.tasks import load_task
|
||||
except ImportError:
|
||||
@@ -53,6 +60,7 @@ class TaskRepository:
|
||||
return load_task(task_id, self._directory)
|
||||
|
||||
def save(self, task: Dict[str, Any]) -> Path:
|
||||
"""Ghi task xuống đĩa (ghi nguyên tử) và trả về đường dẫn file."""
|
||||
try:
|
||||
from cowork_local.core.tasks import save_task
|
||||
except ImportError:
|
||||
@@ -60,6 +68,7 @@ class TaskRepository:
|
||||
return save_task(task, self._directory)
|
||||
|
||||
def create(self, title: str = "", **overrides: Any) -> Dict[str, Any]:
|
||||
"""Tạo một task mới trong bộ nhớ theo mẫu mặc định; chưa ghi đĩa."""
|
||||
try:
|
||||
from cowork_local.core.tasks import new_task
|
||||
except ImportError:
|
||||
@@ -67,6 +76,7 @@ class TaskRepository:
|
||||
return new_task(title, **overrides)
|
||||
|
||||
def duplicate(self, task: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Nhân bản một task (id mới, trạng thái và lịch sử chạy được đặt lại)."""
|
||||
try:
|
||||
from cowork_local.core.tasks import duplicate_task
|
||||
except ImportError:
|
||||
@@ -74,6 +84,7 @@ class TaskRepository:
|
||||
return duplicate_task(task)
|
||||
|
||||
def delete(self, task_id: str) -> None:
|
||||
"""Xoá hẳn một task khỏi đĩa."""
|
||||
try:
|
||||
from cowork_local.core.tasks import delete_task
|
||||
except ImportError:
|
||||
|
||||
@@ -16,6 +16,9 @@ class WorkspaceRepository:
|
||||
``tmp_path`` so nothing touches the user's real config folder)."""
|
||||
|
||||
def __init__(self, directory: Optional[Path] = None) -> None:
|
||||
"""``directory`` để None thì dùng thư mục dự án mặc định; import muộn để không
|
||||
kéo cấu hình vào lúc nạp module.
|
||||
"""
|
||||
if directory is not None:
|
||||
self._directory = Path(directory)
|
||||
else:
|
||||
@@ -23,25 +26,31 @@ class WorkspaceRepository:
|
||||
self._directory = PROJECTS_DIR
|
||||
|
||||
def list(self) -> List["Project"]:
|
||||
"""Liệt kê mọi project trong thư mục."""
|
||||
from cowork_local.core.projects import list_projects
|
||||
return list_projects(self._directory)
|
||||
|
||||
def get(self, project_id: str) -> Optional["Project"]:
|
||||
"""Đọc một project theo id; trả về ``None`` nếu không có."""
|
||||
from cowork_local.core.projects import load_project
|
||||
return load_project(project_id, self._directory)
|
||||
|
||||
def save(self, project: "Project") -> None:
|
||||
"""Ghi project xuống đĩa (ghi nguyên tử)."""
|
||||
from cowork_local.core.projects import save_project
|
||||
save_project(project, self._directory)
|
||||
|
||||
def create(self, name: str, **kwargs) -> "Project":
|
||||
"""Tạo project mới và ghi ngay xuống đĩa."""
|
||||
from cowork_local.core.projects import new_project
|
||||
return new_project(name, directory=self._directory, **kwargs)
|
||||
|
||||
def new(self, name: str, **kwargs) -> "Project":
|
||||
"""Bí danh của :meth:`create` — giữ cho mã cũ gọi ``new()`` vẫn chạy."""
|
||||
return self.create(name, **kwargs)
|
||||
|
||||
def delete(self, project_id: str) -> bool:
|
||||
"""Xoá project; trả về ``True`` nếu có project để xoá."""
|
||||
from cowork_local.core.projects import delete_project
|
||||
return delete_project(project_id, self._directory)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user