diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..9203830f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,33 @@ +# https://editorconfig.org — shared whitespace rules for every editor. +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.{py,pyi}] +indent_size = 4 +max_line_length = 120 + +[*.{sh,ps1,ini,toml}] +indent_size = 4 + +[{Dockerfile,Dockerfile.*,*.dockerfile}] +indent_size = 4 + +# Two trailing spaces are a hard line break in Markdown. +[*.{md,mdx}] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab + +# Generated or vendored; leave as produced. +[{uv.lock,package-lock.json,docsgpt/requirements*.txt}] +indent_size = unset +insert_final_newline = unset +trim_trailing_whitespace = unset diff --git a/.gitignore b/.gitignore index 27013d3b..5bb2d60b 100644 --- a/.gitignore +++ b/.gitignore @@ -195,6 +195,11 @@ docsgpt/static/ node_modules/ .vscode/settings.json .vscode/sftp.json +# Zed: the shared project config is tracked, anything else under .zed/ is local +.zed/* +!.zed/settings.json +!.zed/tasks.json +!.zed/debug.json /models/ model/ diff --git a/.zed/debug.json b/.zed/debug.json new file mode 100644 index 00000000..6c116182 --- /dev/null +++ b/.zed/debug.json @@ -0,0 +1,44 @@ +// Debug configurations for the Zed editor (https://zed.dev/docs/debugger), +// the counterparts of .vscode/launch.json. Start one with `debugger: start`. +// Zed picks the interpreter from the checkout's `.venv`. +[ + { + "label": "API (uvicorn)", + "adapter": "Debugpy", + "request": "launch", + "module": "uvicorn", + "args": ["docsgpt.asgi:asgi_app", "--host", "127.0.0.1", "--port", "7091"], + "cwd": "$ZED_WORKTREE_ROOT", + "env": { "PYTHONPATH": "$ZED_WORKTREE_ROOT" }, + "justMyCode": true + }, + { + // The solo pool keeps tasks in the debugged process, so breakpoints hit. + "label": "Celery worker (solo pool)", + "adapter": "Debugpy", + "request": "launch", + "module": "celery", + "args": ["-A", "docsgpt.app.celery", "worker", "-l", "INFO", "--pool=solo"], + "cwd": "$ZED_WORKTREE_ROOT", + "env": { "PYTHONPATH": "$ZED_WORKTREE_ROOT" }, + "justMyCode": true + }, + { + "label": "pytest: this file", + "adapter": "Debugpy", + "request": "launch", + "module": "pytest", + "args": ["--no-cov", "$ZED_RELATIVE_FILE"], + "cwd": "$ZED_WORKTREE_ROOT", + "env": { "PYTHONPATH": "$ZED_WORKTREE_ROOT" }, + "justMyCode": false + }, + { + "label": "Python: this file", + "adapter": "Debugpy", + "request": "launch", + "program": "$ZED_FILE", + "cwd": "$ZED_WORKTREE_ROOT", + "env": { "PYTHONPATH": "$ZED_WORKTREE_ROOT" } + } +] diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 00000000..2a470819 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,89 @@ +// Project settings for the Zed editor (https://zed.dev/docs/configuring-zed). +// They mirror what CI and the pre-commit hook enforce; whitespace rules live in +// .editorconfig and the Python analysis config in pyproject.toml +// ([tool.pyright]) so other editors share them. Personal preferences belong in +// your user settings, not here. +{ + // Zed replaces its defaults when this key is set, so they are repeated first. + // Build outputs, caches and local runtime data only add noise to the file + // finder and project search. + "file_scan_exclusions": [ + "**/.git", + "**/.svn", + "**/.hg", + "**/.jj", + "**/.sl", + "**/.repo", + "**/CVS", + "**/.DS_Store", + "**/Thumbs.db", + "**/.classpath", + "**/.settings", + "**/__pycache__", + "**/.ruff_cache", + "**/.pytest_cache", + "**/.mypy_cache", + "**/htmlcov", + "**/.next", + "frontend/dist", + "docsgpt/static", + "**/indexes", + "**/inputs", + "**/vectors", + "models" + ], + // Never shared with collaborators or sent to an AI assistant. The first six + // are Zed's defaults, which this key also replaces. + "private_files": [ + "**/.env*", + "**/*.pem", + "**/*.key", + "**/*.cert", + "**/*.crt", + "**/secrets.yml", + "**/.jwt_secret_key" + ], + "file_types": { + "Shell Script": [".env-template"], + "Dockerfile": ["Dockerfile*"] + }, + "languages": { + "Python": { + "language_servers": ["basedpyright", "ruff", "..."], + "formatter": { "language_server": { "name": "ruff" } }, + // CI runs `ruff check` only and most of the tree is not `ruff format` + // clean, so formatting on save would bury a change in unrelated diffs. + "format_on_save": "off", + "preferred_line_length": 120, + "wrap_guides": [120] + }, + // Same order as the lint-staged hook: ESLint fixes, then Prettier. + "TypeScript": { + "formatter": "prettier", + "format_on_save": "on", + "code_actions_on_format": { "source.fixAll.eslint": true } + }, + "TSX": { + "formatter": "prettier", + "format_on_save": "on", + "code_actions_on_format": { "source.fixAll.eslint": true } + }, + "JavaScript": { + "formatter": "prettier", + "format_on_save": "on", + "code_actions_on_format": { "source.fixAll.eslint": true } + }, + // Docs prose is reviewed by Vale, not reflowed by a formatter. + "Markdown": { "format_on_save": "off" }, + "MDX": { "format_on_save": "off" } + }, + "lsp": { + // The ESLint config is frontend/eslint.config.js, not at the root. + "eslint": { + "settings": { "workingDirectory": { "mode": "auto" } } + }, + "tailwindcss-language-server": { + "settings": { "classFunctions": ["cn", "cva", "clsx", "twMerge"] } + } + } +} diff --git a/.zed/tasks.json b/.zed/tasks.json new file mode 100644 index 00000000..3daf7eae --- /dev/null +++ b/.zed/tasks.json @@ -0,0 +1,100 @@ +// Project tasks for the Zed editor (https://zed.dev/docs/tasks). Run one with +// `task: spawn`. Python commands go through `uv run --no-sync`, which uses the +// checkout's `.venv` without changing what is installed in it; create it first +// with `uv sync`. See AGENTS.md for what each command does. +[ + { + "label": "services: Postgres + Redis", + "command": "docker compose -f deployment/docker-compose-dev.yaml up", + "cwd": "$ZED_WORKTREE_ROOT", + "use_new_terminal": true + }, + { + "label": "dev: API + worker + frontend", + "command": "uv run --no-sync docsgpt dev --ui", + "cwd": "$ZED_WORKTREE_ROOT", + "use_new_terminal": true + }, + { + "label": "dev: API + worker + frontend (mock LLM, no API key)", + "command": "uv run --no-sync docsgpt dev --ui --mock-llm", + "cwd": "$ZED_WORKTREE_ROOT", + "use_new_terminal": true + }, + { + "label": "backend: API", + "command": "uv run --no-sync docsgpt api --reload", + "cwd": "$ZED_WORKTREE_ROOT", + "use_new_terminal": true + }, + { + "label": "backend: Celery worker", + "command": "uv run --no-sync docsgpt worker", + "cwd": "$ZED_WORKTREE_ROOT", + "use_new_terminal": true + }, + { + "label": "backend: run migrations", + "command": "uv run --no-sync docsgpt migrate", + "cwd": "$ZED_WORKTREE_ROOT" + }, + { + "label": "frontend: dev server", + "command": "npm run dev", + "cwd": "$ZED_WORKTREE_ROOT/frontend", + "use_new_terminal": true + }, + { + "label": "frontend: build into docsgpt/static", + "command": "bash scripts/build_frontend.sh", + "cwd": "$ZED_WORKTREE_ROOT" + }, + // Coverage is switched off for partial runs: pytest.ini turns it on, and a + // report for one file is slow and misleading. + { + "label": "pytest: all", + "command": "uv run --no-sync python -m pytest", + "cwd": "$ZED_WORKTREE_ROOT" + }, + { + "label": "pytest: this file", + "command": "uv run --no-sync python -m pytest --no-cov \"$ZED_RELATIVE_FILE\"", + "cwd": "$ZED_WORKTREE_ROOT" + }, + { + "label": "pytest: test under cursor ($ZED_SYMBOL)", + "command": "uv run --no-sync python -m pytest --no-cov \"$ZED_RELATIVE_FILE\" -k \"$ZED_SYMBOL\"", + "cwd": "$ZED_WORKTREE_ROOT" + }, + { + "label": "pytest: last failed", + "command": "uv run --no-sync python -m pytest --no-cov --lf", + "cwd": "$ZED_WORKTREE_ROOT" + }, + { + "label": "vitest: all", + "command": "npm run test", + "cwd": "$ZED_WORKTREE_ROOT/frontend" + }, + { + "label": "vitest: this file", + "command": "npx vitest run \"$ZED_FILE\"", + "cwd": "$ZED_WORKTREE_ROOT/frontend" + }, + { + "label": "lint: ruff check --fix", + "command": "uv run --no-sync ruff check --fix .", + "cwd": "$ZED_WORKTREE_ROOT" + }, + { + "label": "lint: frontend (eslint --fix + prettier)", + "command": "npm run lint-fix && npm run format", + "cwd": "$ZED_WORKTREE_ROOT/frontend" + }, + // CI fails when docsgpt/requirements*.txt are stale against uv.lock. + { + "label": "deps: uv lock + export requirements", + "command": "uv lock && bash scripts/export_requirements.sh", + "cwd": "$ZED_WORKTREE_ROOT" + } +] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2510c7e2..55b48499 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,7 +43,7 @@ Tech Stack Overview: ### 🌐 Frontend Contributions (⚛️ React, Vite) * The updated Figma design can be found [here](https://www.figma.com/file/OXLtrl1EAy885to6S69554/DocsGPT?node-id=0%3A1&t=hjWVuxRg9yi5YkJ9-1). Please try to follow the guidelines. -* **Coding Style:** We follow a strict coding style enforced by ESLint and Prettier. Please ensure your code adheres to the configuration provided in our repository's `fronetend/.eslintrc.js` file. We recommend configuring your editor with ESLint and Prettier to help with this. +* **Coding Style:** We follow a strict coding style enforced by ESLint and Prettier. Please ensure your code adheres to the configuration provided in our repository's `frontend/eslint.config.js` and `frontend/prettier.config.cjs` files. We recommend configuring your editor with ESLint and Prettier to help with this. * **Component Structure:** Strive for small, reusable components. Favor functional components and hooks over class components where possible. * **State Management** If you need to add stores, please use Redux. @@ -75,6 +75,32 @@ Tech Stack Overview: ... ``` +### Editor setup + +Some configuration is shared by every editor, so you rarely need to set anything up by hand: + +- [`.editorconfig`](https://editorconfig.org) holds the whitespace rules (4 spaces for Python, 2 for TypeScript/JSON/YAML, LF line endings, final newline). Most editors read it natively or through a plugin. +- `[tool.pyright]` in `pyproject.toml` points Pyright, basedpyright and Pylance at the `.venv` created by `uv sync` and at the repository root for imports. +- `.ruff.toml`, `frontend/eslint.config.js` and `frontend/prettier.config.cjs` are picked up by the matching editor integrations. + +Editor-specific configuration that is tracked: + +- **VS Code:** `.vscode/launch.json` has debug targets for the API, the Celery worker and the frontend. +- **Zed:** open the repository root (not `frontend/`). `.zed/settings.json` configures the language servers and formatters, `.zed/tasks.json` adds tasks (`task: spawn`) for the dev services, the API, the worker, the frontend, tests and linting, and `.zed/debug.json` adds debug targets (`debugger: start`). Python files are not formatted on save because most of the tree is not `ruff format` clean; frontend files are, with ESLint fixes followed by Prettier, as in the pre-commit hook. Project settings cannot install extensions, so if you want the matching syntax support add this to your own Zed settings: + + ```json + { + "auto_install_extensions": { + "dockerfile": true, + "docker-compose": true, + "toml": true, + "mdx": true + } + } + ``` + +Personal preferences belong in your user settings; `.vscode/settings.json` and any other file under `.zed/` are ignored by git. + ### Testing To run unit tests from the root of the repository, execute: diff --git a/pyproject.toml b/pyproject.toml index 30f07df6..5e24bbaa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -213,6 +213,28 @@ exclude = [ "docsgpt/vectors/", ] +# Shared by every editor's Python language server (pyright, basedpyright, +# Pylance) and by `pyright` on the command line. Imports are rooted at the +# checkout (`docsgpt.…`, `tests.…`), and the interpreter is the uv-managed +# `.venv`. "standard" keeps basedpyright from defaulting to its much stricter +# "recommended" mode; this is editor feedback, not a CI gate. +[tool.pyright] +pythonVersion = "3.12" +venvPath = "." +venv = ".venv" +extraPaths = ["."] +typeCheckingMode = "standard" +include = ["docsgpt", "application", "tests", "scripts"] +exclude = [ + "**/__pycache__", + "**/node_modules", + ".venv", + "docsgpt/static", + "docsgpt/indexes", + "docsgpt/inputs", + "docsgpt/vectors", +] + [[tool.uv.index]] name = "pytorch-cpu" url = "https://download.pytorch.org/whl/cpu"