|
| 1 | +# Contributing Guide |
| 2 | + |
| 3 | +Thank you for your interest in ManualAid! This document will help you understand |
| 4 | +how to contribute to the project. |
| 5 | + |
| 6 | +Before you begin, please read the project's [README.md](README.md) to understand |
| 7 | +the basic information and technical constraints. |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## Legal Notice |
| 12 | + |
| 13 | +ManualAid is a **purely local, human-assisted tool**. It is designed to |
| 14 | +facilitate manual copy-paste workflows and **does not support** automated |
| 15 | +interaction with LLM platforms. |
| 16 | + |
| 17 | +**Users must take full responsibility for:** |
| 18 | + |
| 19 | +1. Complying with the Terms of Service (ToS) of the LLM platforms they use. |
| 20 | +2. Ensuring their usage does not violate rate limits, automation bans, or other |
| 21 | + policies. |
| 22 | + |
| 23 | +**The author of ManualAid explicitly disclaims all liability for:** |
| 24 | + |
| 25 | +- Misuse of this tool for automated requests, bypassing paywalls, or abusing LLM |
| 26 | + services. |
| 27 | +- Any account suspensions, legal actions, or losses resulting from such misuse. |
| 28 | + |
| 29 | +If you fork this project, **you must retain this disclaimer** and ensure that |
| 30 | +your modifications do not facilitate or enable automated abuse. |
| 31 | + |
| 32 | +--- |
| 33 | + |
| 34 | +## Issues and Pull Requests |
| 35 | + |
| 36 | +### Issues |
| 37 | + |
| 38 | +- **Titles and content must be bilingual (Chinese and English)**. |
| 39 | +- Clearly describe the problem or suggestion, with reproduction steps (if |
| 40 | + applicable). |
| 41 | + |
| 42 | +### Pull Requests |
| 43 | + |
| 44 | +- PR titles should be bilingual (Chinese/English) or Chinese only. |
| 45 | +- Ensure the local `npm run ci` check passes. |
| 46 | +- Link related issues (e.g., `Closes #42`). |
| 47 | +- Before contributing complex features, you must create an Issue to clarify the |
| 48 | + objective and avoid development directions that differ from the project's |
| 49 | + actual direction. |
| 50 | + |
| 51 | +--- |
| 52 | + |
| 53 | +## Environment Setup |
| 54 | + |
| 55 | +### Prerequisites |
| 56 | + |
| 57 | +- **Python >= 3.14** (specified in `pyproject.toml`) |
| 58 | +- **Node.js** (for development tools: Prettier, markdownlint) |
| 59 | +- **Git** |
| 60 | + |
| 61 | +### Clone the Repository |
| 62 | + |
| 63 | +```bash |
| 64 | +git clone https://github.com/SunYanbox/ManualAid.git |
| 65 | +cd ManualAid |
| 66 | +``` |
| 67 | + |
| 68 | +### Install Dependencies |
| 69 | + |
| 70 | +> It is recommended to create a dedicated virtual environment. |
| 71 | +
|
| 72 | +```bash |
| 73 | +pip install -r requirements.txt # Python dependencies (including dev dependencies) |
| 74 | +npm install # Node.js dev tools (for format checking) |
| 75 | +``` |
| 76 | + |
| 77 | +### Environment Variables (Optional) |
| 78 | + |
| 79 | +```bash |
| 80 | +cp .env.example .env # Modify the configuration as needed |
| 81 | +``` |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +## Development Workflow |
| 86 | + |
| 87 | +The standard development workflow is as follows: |
| 88 | + |
| 89 | +```bash |
| 90 | +# 1. Write code (in src/ or tests/) |
| 91 | + |
| 92 | +# 2. Auto-format |
| 93 | +npm run format:fix |
| 94 | + |
| 95 | +# 3. Run tests and check coverage |
| 96 | +npm run test |
| 97 | + |
| 98 | +# 4. Full pre-commit check (format fix -> test -> format check) |
| 99 | +npm run ci |
| 100 | +``` |
| 101 | + |
| 102 | +### NPM Script Quick Reference |
| 103 | + |
| 104 | +| Command | Description | |
| 105 | +| :--------------------- | :------------------------------------------------------------------- | |
| 106 | +| `npm run format:fix` | Auto-fix all formatting issues (Python + Markdown + fullwidth chars) | |
| 107 | +| `npm run format:check` | Check all formatting issues | |
| 108 | +| `npm run test` | Run pytest with coverage report | |
| 109 | +| `npm run ci` | Full CI pipeline: format fix -> test -> format check | |
| 110 | + |
| 111 | +#### Running the Application |
| 112 | + |
| 113 | +```bash |
| 114 | +python main.py # Launch with folder selection dialog |
| 115 | +python main.py -p /path # Launch with specified workspace path |
| 116 | +``` |
| 117 | + |
| 118 | +#### Running the Application (After Packaging) |
| 119 | + |
| 120 | +```bash |
| 121 | +manualaid # Launch with folder selection dialog |
| 122 | +manualaid -p /path # Launch with specified workspace path |
| 123 | +``` |
| 124 | + |
| 125 | +--- |
| 126 | + |
| 127 | +## Code Style Standards |
| 128 | + |
| 129 | +The project uses the following tools to ensure code style consistency: |
| 130 | + |
| 131 | +### Ruff (Python Linting) |
| 132 | + |
| 133 | +Configuration file: `ruff.toml`. Enabled rule sets: E, W, F, I, UP, B, SIM, RUF. |
| 134 | + |
| 135 | +```bash |
| 136 | +npm run ruff:format:check # Check |
| 137 | +npm run ruff:format:fix # Fix (Ruff format) |
| 138 | +``` |
| 139 | + |
| 140 | +### Prettier (Code Formatting) |
| 141 | + |
| 142 | +Configuration file: `.prettierrc.yml`. Rules: printWidth 80, no semicolons, |
| 143 | +single quotes. |
| 144 | + |
| 145 | +```bash |
| 146 | +npm run prettier:format:check # Check |
| 147 | +npm run prettier:format:fix # Fix |
| 148 | +``` |
| 149 | + |
| 150 | +### Markdown Lint (Markdown Syntax Check) |
| 151 | + |
| 152 | +Configuration file: `.markdownlint.yml`. Key rules: MD004 use dashes, MD013 line |
| 153 | +length 120. |
| 154 | + |
| 155 | +```bash |
| 156 | +npm run md:format:check # Check |
| 157 | +npm run md:format:fix # Fix |
| 158 | +``` |
| 159 | + |
| 160 | +For Chinese Markdown files, use `<!-- markdownlint-disable-file MD060 -->` below |
| 161 | +the file title to ignore MD060 issues (while keeping table pipe `|` basically |
| 162 | +aligned). |
| 163 | + |
| 164 | +### Fullwidth Character Check |
| 165 | + |
| 166 | +**`.py` and `.md` files must only use halfwidth punctuation** |
| 167 | +(RUF001/RUF002/RUF003). |
| 168 | + |
| 169 | +```bash |
| 170 | +npm run fw:format:check # Check |
| 171 | +npm run fw:format:fix # Fix (uses scripts/fix_fullwidth.py) |
| 172 | +``` |
| 173 | + |
| 174 | +### Other Standards |
| 175 | + |
| 176 | +- **Line length**: 120-character limit (Black configuration in `pyproject.toml`) |
| 177 | +- **Import sorting**: Isort configured with `known-first-party = ["src"]` (see |
| 178 | + `ruff.toml`) |
| 179 | + |
| 180 | +--- |
| 181 | + |
| 182 | +## Commit Convention |
| 183 | + |
| 184 | +This project follows the **Conventional Commits** specification, with the |
| 185 | +structure: |
| 186 | + |
| 187 | +```txt |
| 188 | +<type>(<scope>): <zh_desc> / <en_desc> |
| 189 | +``` |
| 190 | + |
| 191 | +### Type |
| 192 | + |
| 193 | +| Type | Meaning | Typical Scenario | |
| 194 | +| :--------- | :------------ | :--------------------------------------------------------------------------------- | |
| 195 | +| `feat` | New feature | Adding features, tools, UI components, etc. | |
| 196 | +| `fix` | Bug fix | Fixing code logic errors, exception handling, config inconsistencies, etc. | |
| 197 | +| `refactor` | Code refactor | Code optimization and structural reorganization without changing external behavior | |
| 198 | +| `chore` | Miscellaneous | Dependency updates, version upgrades, cleaning up unused files | |
| 199 | +| `docs` | Documentation | Modifying comments, README, API docs, etc. | |
| 200 | +| `ci` | CI/CD | Modifying GitHub Actions, CI pipeline configuration | |
| 201 | +| `test` | Tests | Adding or modifying test cases | |
| 202 | + |
| 203 | +### Scope |
| 204 | + |
| 205 | +| Scope | Related Modules | |
| 206 | +| :---------- | :--------------------------------------------------------------------------- | |
| 207 | +| `console` | Console interface, TUI layout, log output (`src/console/...`) | |
| 208 | +| `core` | Core logic, input parsing, tool registration mechanism (`src/core/...`) | |
| 209 | +| `workspace` | Workspace operations, file I/O, path validation (`src/workspace/...`) | |
| 210 | +| `tools` | Specific tool implementations (`read_tool`, `write_tool`, `edit_tool`, etc.) | |
| 211 | +| `ui` | UI component styles, layout (`src/console/ui/...`) | |
| 212 | +| `models` | Data models (`src/models/...`) | |
| 213 | +| `tests` | Unit tests (`tests/...`) | |
| 214 | + |
| 215 | +### Description (Subject) |
| 216 | + |
| 217 | +- **Must include Chinese**, in the format `<Chinese>`. Optional bilingual |
| 218 | + format: `<Chinese> / <English>`. |
| 219 | +- Use the imperative mood, capitalize the first letter of the English part, and |
| 220 | + do not end with a period. |
| 221 | +- Breaking changes must be explicitly declared. |
| 222 | +- Chinese is not strictly required for merge commits (e.g., |
| 223 | + `Merge ... from branch ...`). |
| 224 | + |
| 225 | +### Examples |
| 226 | + |
| 227 | +```bash |
| 228 | +# New feature |
| 229 | +feat(console): new session statistics panel |
| 230 | + |
| 231 | +# Bug fix |
| 232 | +fix(tools): fix empty record exception in get_avg_consume |
| 233 | + |
| 234 | +# Refactor |
| 235 | +refactor(core): simplify input parser ID generation logic |
| 236 | + |
| 237 | +# Documentation |
| 238 | +docs(README): add contributing guide |
| 239 | +``` |
| 240 | + |
| 241 | +--- |
| 242 | + |
| 243 | +## Project Architecture Overview |
| 244 | + |
| 245 | +### Core Concepts |
| 246 | + |
| 247 | +- **ToolRegistry**: Singleton pattern, manages registration and execution of all |
| 248 | + tools. Tools are invoked via `tool_registry.execute(name, **kwargs)`. |
| 249 | +- **Workspace**: Singleton implemented per workspace path, provides file |
| 250 | + operations and security boundaries. All path operations are validated through |
| 251 | + `PathValidator`. |
| 252 | +- **BaseTool**: Base class for all tools, defining tool name, documentation, |
| 253 | + permissions (read_permission / write_permission), and common methods. |
| 254 | +- **Path Security**: `PathValidator` prevents path traversal attacks, ensuring |
| 255 | + all file operations are restricted within the workspace root directory. |
| 256 | +- **Two-Phase Commit**: Write/edit operations first generate a diff preview and |
| 257 | + record a `PENDING_AUDIT` snapshot; actual disk writes only occur after manual |
| 258 | + review and approval. |
| 259 | + |
| 260 | +--- |
| 261 | + |
| 262 | +## How to Add a New Tool |
| 263 | + |
| 264 | +All tools are located in the `src/workspace/tools/` directory and inherit from |
| 265 | +the `BaseTool` base class. |
| 266 | + |
| 267 | +### Step Overview |
| 268 | + |
| 269 | +1. **Create the tool file**: Create `your_tool.py` under `src/workspace/tools/`. |
| 270 | + |
| 271 | +2. **Inherit from BaseTool**: |
| 272 | + |
| 273 | + ```python |
| 274 | + from src.workspace.tools.base_tool import BaseTool |
| 275 | + from src.workspace.workspace import Workspace |
| 276 | + |
| 277 | + class YourTool(BaseTool): |
| 278 | + def __init__(self, workspace: Workspace): |
| 279 | + super().__init__( |
| 280 | + workspace, |
| 281 | + name="your_tool_name", # Tool name (unique) |
| 282 | + doc=self.your_method.__doc__, # Reference the method's docstring |
| 283 | + read_permission=True, # Whether read permission is needed |
| 284 | + write_permission=False, # Whether write permission is needed |
| 285 | + ) |
| 286 | + self.func = self.your_method |
| 287 | + self.params = BaseTool.extract_params(self.your_method) |
| 288 | + |
| 289 | + @BaseTool.handle_tool_exceptions |
| 290 | + def your_method(self, param1: str, param2: int = 0) -> str: |
| 291 | + """ |
| 292 | + Tool description -- will be generated as LLM-readable documentation. |
| 293 | +
|
| 294 | + Parameters |
| 295 | + ---------- |
| 296 | + param1: Parameter description |
| 297 | + param2: Parameter description (with default value) |
| 298 | + """ |
| 299 | + # Path operations must be validated through PathValidator |
| 300 | + path = self.workspace.path_validator.validate(param1) |
| 301 | + # ... tool logic ... |
| 302 | + return f'{path}x{param2}' |
| 303 | + ``` |
| 304 | + |
| 305 | +3. **Special handling for write operations**: If the tool involves writing |
| 306 | + (`write_permission=True`), you need to: |
| 307 | + - Check if the file has been externally modified via |
| 308 | + `self._validate_mtime(path)` |
| 309 | + - Generate a diff and record a `PENDING_AUDIT` snapshot instead of writing |
| 310 | + directly to disk |
| 311 | + - Refer to the implementations of `WriteTool` and `EditTool` |
| 312 | + |
| 313 | +4. **Register the tool**: Import and instantiate your tool in the `register()` |
| 314 | + method of `src/core/tool_registry.py`: |
| 315 | + |
| 316 | +5. **Add tests**: Create corresponding test files under |
| 317 | + `tests/workspace/tools/`. At minimum, cover: |
| 318 | + - Normal execution paths |
| 319 | + - Parameter validation (e.g., empty parameters, invalid values) |
| 320 | + - Path security (e.g., out-of-bounds access) |
| 321 | + |
| 322 | +--- |
| 323 | + |
| 324 | +## Testing Requirements |
| 325 | + |
| 326 | +- Test files are located in the `tests/` directory, with a structure |
| 327 | + corresponding to `src/`. |
| 328 | +- Pytest is configured with `pythonpath = ["."]`, allowing direct import of the |
| 329 | + `src` package. |
| 330 | +- Coverage configuration: `--cov=src --cov-report=term-missing`. |
| 331 | +- **New features require tests** -- at minimum, cover core paths and edge cases. |
| 332 | + |
| 333 | +The project is currently in early development; 100% coverage is not strictly |
| 334 | +required, but gradual improvement is encouraged. |
| 335 | + |
| 336 | +### Running Tests |
| 337 | + |
| 338 | +```bash |
| 339 | +npm run test # All tests + coverage report |
| 340 | +pytest tests/path/to/test_file.py -v # Run a single test file |
| 341 | +``` |
| 342 | + |
| 343 | +--- |
| 344 | + |
| 345 | +## License |
| 346 | + |
| 347 | +ManualAid is licensed under the [AGPL-3.0](LICENSE) license. Contributing code |
| 348 | +means you agree to release your code under this license. |
0 commit comments