diff --git a/README.md b/README.md index eea2b0d..469d9f8 100644 --- a/README.md +++ b/README.md @@ -29,14 +29,35 @@ infrastructure/ (Adapters, LLM Providers, Atomic Persistence, Keyring SecretStor ## 🚀 Quick Start -### 1. Run the Desktop Application -From the repository root: +### 1. Windows — two double-clicks + +``` +install.bat once, to install the Python dependencies +run.bat every time, to start the app +``` + +`install.bat` builds an isolated virtualenv under `%LOCALAPPDATA%\CoworkLocal` +(deliberately **outside** the repo — the quality gates walk the whole directory +tree, so a `.venv` in here would turn every vendored module into a Gate O +violation). Add `--dev` to also install the test dependencies, or `--system` to +skip the virtualenv and install into the Python already on `PATH`. + +Both scripts also make the source importable under its package name. That step +is not optional: `python -m cowork_local` only resolves when the checkout +directory is literally named `cowork_local`, and the MS365 MCP server is +launched as a subprocess with `python -m cowork_local.mcp_servers.ms365_server`, +so a differently-named checkout breaks the app *and* its subprocesses. The +scripts create a junction instead of forcing anyone to rename their folder. + +### 2. Any platform — run from source + +From the **parent** of a checkout directory named `cowork_local`: ```bash python -m cowork_local ``` -### 2. Run Automated Tests +### 3. Run Automated Tests ```bash python -m pip install -r requirements-test.txt pytest -q diff --git a/install.bat b/install.bat new file mode 100644 index 0000000..c689691 --- /dev/null +++ b/install.bat @@ -0,0 +1,205 @@ +@echo off +rem =========================================================================== +rem Cowork-Local BamBOO - cai dat thu vien Python (chay MOT lan) +rem +rem Cach dung: +rem install.bat cai vao moi truong ao rieng (khuyen dung) +rem install.bat --dev cai them thu vien de chay test +rem install.bat --system cai thang vao Python dang co, khong dung venv +rem install.bat --force dung lai moi truong ao tu dau +rem +rem Cai gi va cai o dau: +rem %LOCALAPPDATA%\CoworkLocal\venv moi truong ao +rem %LOCALAPPDATA%\CoworkLocal\launcher lien ket de import duoc goi +rem +rem Vi sao KHONG dat venv trong repo: cac cong chat luong +rem (scripts/check_orphan_modules.py, check_imports.py) quet TOAN BO cay thu +rem muc chu khong doc .gitignore, nen mot thu muc .venv o day se bien vai nghin +rem module cua thu vien thanh "ma production khong ai import" va lam cong do. +rem =========================================================================== +setlocal EnableExtensions EnableDelayedExpansion +chcp 65001 >nul 2>&1 + +set "REPO=%~dp0" +set "REPO=%REPO:~0,-1%" +set "APPHOME=%LOCALAPPDATA%\CoworkLocal" +set "VENV=%APPHOME%\venv" +set "LAUNCHER=%APPHOME%\launcher" + +set "DEV=0" +set "USE_SYSTEM=0" +set "FORCE=0" + +:parse_args +if "%~1"=="" goto args_done +if /I "%~1"=="--dev" set "DEV=1" & shift & goto parse_args +if /I "%~1"=="--system" set "USE_SYSTEM=1" & shift & goto parse_args +if /I "%~1"=="--force" set "FORCE=1" & shift & goto parse_args +if /I "%~1"=="-h" goto usage +if /I "%~1"=="--help" goto usage +echo [LOI] Khong hieu tham so: %~1 +goto usage +:args_done + +echo. +echo =========================================================================== +echo Cowork-Local BamBOO — cài đặt +echo =========================================================================== +echo Mã nguồn : %REPO% +echo Cài vào : %APPHOME% +echo. + +rem -------------------------------------------------------------------------- +rem 1. Tim Python +rem +rem Uu tien "py -3" chu khong phai "python": tren Windows 11, python.exe trong +rem WindowsApps thuong chi la lien ket mo Microsoft Store chu khong phai +rem Python that. +rem -------------------------------------------------------------------------- +set "PY=" +py -3 -c "import sys" >nul 2>&1 && set "PY=py -3" +if not defined PY ( + python -c "import sys" >nul 2>&1 && set "PY=python" +) +if not defined PY ( + echo [LỖI] Không tìm thấy Python trên máy này. + echo Cài Python 3.11 trở lên từ https://www.python.org/downloads/ + echo và nhớ tích "Add python.exe to PATH" khi cài. + goto fail +) + +for /f "delims=" %%V in ('%PY% -c "import sys;print('%%d.%%d'%%sys.version_info[:2])" 2^>nul') do set "PYVER=%%V" +echo [1/5] Python %PYVER% (%PY%) + +%PY% -c "import sys;raise SystemExit(0 if sys.version_info>=(3,11) else 1)" >nul 2>&1 +if errorlevel 1 ( + echo [LỖI] Cần Python 3.11 trở lên, máy đang có %PYVER%. + goto fail +) + +rem -------------------------------------------------------------------------- +rem 2. Moi truong ao +rem -------------------------------------------------------------------------- +if "%USE_SYSTEM%"=="1" ( + echo [2/5] Bỏ qua môi trường ảo — cài thẳng vào Python đang có ^(--system^) + set "PIP=%PY% -m pip" + goto deps +) + +if "%FORCE%"=="1" if exist "%VENV%" ( + echo [2/5] Xoá môi trường ảo cũ... + rmdir /s /q "%VENV%" 2>nul +) + +if exist "%VENV%\Scripts\python.exe" ( + echo [2/5] Môi trường ảo đã có — dùng lại +) else ( + echo [2/5] Tạo môi trường ảo... + %PY% -m venv "%VENV%" + if errorlevel 1 ( + echo [LỖI] Không tạo được môi trường ảo. + echo Thử lại với: install.bat --system + goto fail + ) +) +set "PIP="%VENV%\Scripts\python.exe" -m pip" + +rem -------------------------------------------------------------------------- +rem 3. Cai thu vien +rem -------------------------------------------------------------------------- +:deps +echo [3/5] Cập nhật pip... +%PIP% install --disable-pip-version-check --quiet --upgrade pip +if errorlevel 1 echo ^(bỏ qua — pip cũ vẫn dùng được^) + +echo [3/5] Cài thư viện từ requirements.txt ^(PySide6 khá nặng, chờ vài phút^)... +%PIP% install --disable-pip-version-check -r "%REPO%\requirements.txt" +if errorlevel 1 ( + echo [LỖI] Cài thư viện thất bại. + echo Nếu máy qua proxy công ty, đặt biến môi trường HTTPS_PROXY rồi chạy lại. + goto fail +) + +if "%DEV%"=="1" ( + echo [3/5] Cài thêm thư viện chạy test ^(--dev^)... + %PIP% install --disable-pip-version-check -r "%REPO%\requirements-test.txt" + if errorlevel 1 ( + echo [LỖI] Cài thư viện test thất bại. + goto fail + ) +) + +rem -------------------------------------------------------------------------- +rem 4. Lien ket de goi import duoc dung ten +rem +rem Ma nguon phai import duoc duoi dung ten "cowork_local". Thu muc nay ten la +rem "%~nx0"'s parent — neu no khong phai "cowork_local" thi ca +rem "python -m cowork_local" lan "python __main__.py" deu bao +rem ModuleNotFoundError, va tien trinh con chay may chu MCP MS365 +rem (state.py: python -m cowork_local.mcp_servers.ms365_server) cung hong theo. +rem +rem Junction giai quyet ca hai ma khong phai doi ten thu muc lam viec, khong +rem phai sua mot dong code nao, va khong can quyen quan tri. +rem -------------------------------------------------------------------------- +for %%I in ("%REPO%") do set "REPO_NAME=%%~nxI" +if /I "%REPO_NAME%"=="cowork_local" ( + echo [4/5] Thư mục đã đúng tên "cowork_local" — không cần liên kết + goto smoke +) + +if not exist "%LAUNCHER%" mkdir "%LAUNCHER%" >nul 2>&1 +if exist "%LAUNCHER%\cowork_local" rmdir "%LAUNCHER%\cowork_local" >nul 2>&1 +mklink /J "%LAUNCHER%\cowork_local" "%REPO%" >nul +if errorlevel 1 ( + echo [LỖI] Không tạo được liên kết thư mục. + echo Thư mục "%REPO_NAME%" không phải tên gói Python hợp lệ nên + echo ứng dụng không import được chính nó. Cách khác: đổi tên thư mục + echo mã nguồn thành "cowork_local". + goto fail +) +echo [4/5] Đã tạo liên kết: %LAUNCHER%\cowork_local + +rem -------------------------------------------------------------------------- +rem 5. Chay thu mot lan +rem -------------------------------------------------------------------------- +:smoke +if "%USE_SYSTEM%"=="1" (set "RUNPY=%PY%") else (set "RUNPY="%VENV%\Scripts\python.exe"") +if /I "%REPO_NAME%"=="cowork_local" ( + for %%I in ("%REPO%\..") do set "PKGPATH=%%~fI" +) else ( + set "PKGPATH=%LAUNCHER%" +) + +echo [5/5] Kiểm tra lại... +set "PYTHONPATH=!PKGPATH!" +%RUNPY% -c "import cowork_local, PySide6; print(' cowork_local + PySide6 nạp được')" +if errorlevel 1 ( + echo [LỖI] Cài xong nhưng vẫn chưa import được gói. + goto fail +) + +echo. +echo =========================================================================== +echo XONG. Từ giờ chỉ cần bấm đúp vào run.bat +echo =========================================================================== +echo. +pause +exit /b 0 + +:usage +echo. +echo install.bat [--dev] [--system] [--force] +echo. +echo --dev cài thêm thư viện để chạy test ^(pytest, pydantic^) +echo --system cài thẳng vào Python đang có, không tạo môi trường ảo +echo --force xoá môi trường ảo cũ rồi tạo lại từ đầu +echo. +pause +exit /b 2 + +:fail +echo. +echo Cài đặt KHÔNG thành công. Xem thông báo lỗi ở trên. +echo. +pause +exit /b 1 diff --git a/requirements.txt b/requirements.txt index a762b54..3151a94 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,4 +21,21 @@ msal>=1.24.0 # OAuth device-code flow for MS365 keyring>=24.0.0 # OS credential store (token cache) # --- MCP (Model Context Protocol) --- -mcp>=1.0.0 # MCP client SDK (stdio transport) \ No newline at end of file +mcp>=1.0.0 # MCP client SDK (stdio transport) + +# --- Bắt buộc: import KHÔNG có try/except, thiếu là app chết lúc khởi động --- +# Hai dòng dưới đây bị bỏ sót cho tới 30/08. Triệu chứng của việc thiếu chúng +# không phải "tính năng đó không chạy" mà là ModuleNotFoundError ngay khi dựng +# cửa sổ chính — cài đúng theo requirements.txt xong app vẫn không mở được. +pygments>=2.15.0 # tô màu cú pháp — presentation/folder/code_editor.py +pydantic>=2,<3 # kiểu dữ liệu định tuyến — core/routing/models.py + +# --- Tuỳ chọn: mỗi chỗ dùng đều bọc try/except, thiếu thì mất tính năng --- +# Vẫn cài mặc định vì đều nhẹ và đều là tính năng người dùng nhìn thấy được. +networkx>=3.0 # bố cục đồ thị đẹp hơn cho GraphRAG nhiều node +holidays>=0.40 # lịch nghỉ theo quốc gia cho màn Lịch task +pywin32>=306; sys_platform == "win32" # Office -> PDF, thông báo Outlook + +# opendataloader-pdf # bộ đọc PDF thay thế — KHÔNG cài sẵn có chủ ý: +# # application/workspaces/graph_index_service.py tự cài +# # khi cần, qua core/deps.py::ensure_module. diff --git a/run.bat b/run.bat new file mode 100644 index 0000000..6c54853 --- /dev/null +++ b/run.bat @@ -0,0 +1,112 @@ +@echo off +rem =========================================================================== +rem Cowork-Local BamBOO - chay ung dung +rem +rem Bam dup vao file nay la xong. +rem +rem Lan dau tien phai chay install.bat truoc. +rem +rem Tham so truyen vao duoc chuyen thang cho QApplication (xem app.py::run), +rem nen dung duoc cac co cua Qt, vi du: run.bat -style Fusion +rem =========================================================================== +setlocal EnableExtensions EnableDelayedExpansion +chcp 65001 >nul 2>&1 +title Cowork-Local BamBOO + +set "REPO=%~dp0" +set "REPO=%REPO:~0,-1%" +set "APPHOME=%LOCALAPPDATA%\CoworkLocal" +set "VENV=%APPHOME%\venv" +set "LAUNCHER=%APPHOME%\launcher" + +rem -------------------------------------------------------------------------- +rem 1. Chon trinh thong dich +rem +rem Uu tien moi truong ao do install.bat dung. Khong co thi quay ve Python cua +rem he thong — nguoi dung co the da chay "install.bat --system". +rem -------------------------------------------------------------------------- +rem Duong dan luon duoc boc trong dau nhay: %LOCALAPPDATA% co the chua khoang +rem trang neu ten dang nhap co khoang trang. +if exist "%VENV%\Scripts\python.exe" ( + set "RUNPY="%VENV%\Scripts\python.exe"" +) else ( + set "RUNPY=" + for /f "delims=" %%P in ('where py 2^>nul') do if not defined RUNPY set "RUNPY="%%P" -3" + if not defined RUNPY ( + for /f "delims=" %%P in ('where python 2^>nul') do if not defined RUNPY set "RUNPY="%%P"" + ) +) + +if not defined RUNPY ( + echo. + echo [LỖI] Không tìm thấy Python. Chạy install.bat trước đã. + echo. + pause + exit /b 1 +) + +rem Chua co moi truong ao thi kiem xem Python he thong co du thu vien khong. +rem Khong kiem thi nguoi dung chi nhan duoc mot ModuleNotFoundError tho, chang +rem biet la phai chay install.bat. +if not exist "%VENV%\Scripts\python.exe" ( + !RUNPY! -c "import PySide6" >nul 2>&1 + if errorlevel 1 ( + echo. + echo [LỖI] Thư viện chưa được cài. Chạy install.bat trước đã. + echo. + pause + exit /b 1 + ) +) + +rem -------------------------------------------------------------------------- +rem 2. Duong dan de import duoc goi "cowork_local" +rem +rem Thu muc ma nguon phai mang dung ten "cowork_local" thi Python moi import +rem duoc no. Neu khong, install.bat da tao mot junction; o day chi kiem tra va +rem tu dung lai neu no bi xoa — de nguoi dung khong phai chay lai install.bat +rem chi vi mot thu muc tam bi don. +rem -------------------------------------------------------------------------- +for %%I in ("%REPO%") do set "REPO_NAME=%%~nxI" +if /I "%REPO_NAME%"=="cowork_local" ( + for %%I in ("%REPO%\..") do set "PKGPATH=%%~fI" +) else ( + if not exist "%LAUNCHER%\cowork_local" ( + if not exist "%LAUNCHER%" mkdir "%LAUNCHER%" >nul 2>&1 + mklink /J "%LAUNCHER%\cowork_local" "%REPO%" >nul 2>&1 + if errorlevel 1 ( + echo. + echo [LỖI] Không tạo được liên kết thư mục. Chạy install.bat lại. + echo. + pause + exit /b 1 + ) + ) + set "PKGPATH=%LAUNCHER%" +) + +rem -------------------------------------------------------------------------- +rem 3. Chay +rem +rem Dat thu muc lam viec o goc ma nguon va PYTHONPATH tro toi thu muc CHA cua +rem goi — dung cach CI dang chay (.gitea/workflows/ci.yaml). Tien trinh con +rem (may chu MCP MS365) thua ke PYTHONPATH nay nen cung import duoc. +rem -------------------------------------------------------------------------- +if defined PYTHONPATH ( + set "PYTHONPATH=!PKGPATH!;%PYTHONPATH%" +) else ( + set "PYTHONPATH=!PKGPATH!" +) +set "PYTHONIOENCODING=utf-8" +cd /d "%REPO%" + +!RUNPY! -m cowork_local %* +set "RC=%ERRORLEVEL%" + +if not "%RC%"=="0" ( + echo. + echo Ứng dụng thoát với mã lỗi %RC%. Xem thông báo ở trên. + echo. + pause +) +exit /b %RC%