Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions .claude/commands/lint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Python Linter

Run Python code linting and formatting tools.

## Purpose

This command helps you maintain code quality using Python's best linting and formatting tools.

## Usage

```
/lint
```

## What this command does

1. **Runs multiple linters** (flake8, pylint, black, isort)
2. **Provides detailed feedback** on code quality issues
3. **Auto-fixes formatting** where possible
4. **Checks type hints** if mypy is configured

## Example Commands

### Black (code formatting)
```bash
# Format all Python files
black .

# Check formatting without changing files
black --check .

# Format specific file
black src/main.py
```

### flake8 (style guide enforcement)
```bash
# Check all Python files
flake8 .

# Check specific directory
flake8 src/

# Check with specific rules
flake8 --max-line-length=88 .
```

### isort (import sorting)
```bash
# Sort imports in all files
isort .

# Check import sorting
isort --check-only .

# Sort imports in specific file
isort src/main.py
```

### pylint (comprehensive linting)
```bash
# Run pylint on all files
pylint src/

# Run with specific score threshold
pylint --fail-under=8.0 src/

# Generate detailed report
pylint --output-format=html src/ > pylint_report.html
```

### mypy (type checking)
```bash
# Check types in all files
mypy .

# Check specific module
mypy src/models.py

# Check with strict mode
mypy --strict src/
```

## Configuration Files

Most projects benefit from configuration files:

### .flake8
```ini
[flake8]
max-line-length = 88
exclude = .git,__pycache__,venv
ignore = E203,W503
```

### pyproject.toml
```toml
[tool.black]
line-length = 88

[tool.isort]
profile = "black"
```
Comment on lines +88 to +103
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistência na configuração de exemplo, tolo!

Escuta aqui! Os exemplos de configuração mostram line-length = 88 (padrão do Black), mas o pyproject.toml do projeto usa line-length = 100. Tenho pena do tolo que copia esse exemplo e acha que tá certo! Ajusta essa documentação pra refletir o projeto, sacou?

🔧 Correção proposta
 [tool.black]
-line-length = 88
+line-length = 100

 [tool.isort]
 profile = "black"
+line_length = 100
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 88-88: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 89-89: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 96-96: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 97-97: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🤖 Prompt for AI Agents
In @.claude/commands/lint.md around lines 88 - 103, A documentação de exemplo
está inconsistente: o bloco .flake8 e a seção [tool.black] usam line-length = 88
enquanto o projeto usa 100; atualize os exemplos para usar line-length = 100
(ajustando tanto o arquivo .flake8 exemplo quanto a chave [tool.black] no
pyproject.toml exemplo) para que os valores reflitam o valor real do projeto e
evitem confusão ao copiar a configuração.


## Best Practices

- Run linters before committing code
- Use consistent formatting across the project
- Fix linting issues promptly
- Configure linters to match your team's style
- Use type hints for better code documentation
73 changes: 73 additions & 0 deletions .claude/commands/test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Test Runner

Run Python tests with pytest, unittest, or other testing frameworks.

## Purpose

This command helps you run Python tests effectively with proper configuration and reporting.

## Usage

```
/test
```

## What this command does

1. **Detects test framework** (pytest, unittest, nose2)
2. **Runs appropriate tests** with proper configuration
3. **Provides coverage reporting** if available
4. **Shows clear test results** with failure details

## Example Commands

### pytest (recommended)
```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=src --cov-report=html

# Run specific test file
pytest tests/test_models.py

# Run with verbose output
pytest -v

# Run tests matching pattern
pytest -k "test_user"
```

### unittest
```bash
# Run all tests
python -m unittest discover

# Run specific test file
python -m unittest tests.test_models

# Run with verbose output
python -m unittest -v
```

### Django tests
```bash
# Run all Django tests
python manage.py test

# Run specific app tests
python manage.py test myapp

# Run with coverage
coverage run --source='.' manage.py test
coverage report
```

## Best Practices

- Write tests for all critical functionality
- Use descriptive test names
- Keep tests isolated and independent
- Mock external dependencies
- Aim for high test coverage (80%+)
151 changes: 151 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
{
"permissions": {
"allow": [
"Bash",
"Edit",
"MultiEdit",
"Write",
"Bash(python:*)",
"Bash(pytest:*)",
"Bash(pip:*)",
"Bash(uv:*)",
"Bash(uv pip:*)",
"Bash(black:*)",
"Bash(isort:*)",
"Bash(flake8:*)",
"Bash(mypy:*)",
"Bash(git:*)"
],
"deny": [
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(rm -rf:*)"
],
"defaultMode": "dontAsk"
},
"env": {
"BASH_DEFAULT_TIMEOUT_MS": "60000",
"BASH_MAX_OUTPUT_LENGTH": "20000",
"CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR": "1",
"PYTHONPATH": "."
},
"includeCoAuthoredBy": true,
"cleanupPeriodDays": 30,
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
}
]
},
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"); CONTENT=$(echo $STDIN_JSON | jq -r '.tool_input.content // \"\"); if [[ \"$FILE\" =~ \\.py$ ]] && echo \"$CONTENT\" | grep -q 'print('; then echo 'Warning: print() statements should be replaced with logging' >&2; exit 2; fi"
}
]
},
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" == \"requirements.txt\" ]] || [[ \"$FILE\" == \"pyproject.toml\" ]] || [[ \"$FILE\" == \"setup.py\" ]]; then echo 'Checking for vulnerable dependencies...'; if command -v safety >/dev/null 2>&1; then safety check; elif command -v pip-audit >/dev/null 2>&1; then pip-audit; else echo 'No security audit tool found. Install safety or pip-audit'; fi; fi",
"timeout": 60
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.py$ ]]; then black \"$FILE\" 2>/dev/null || echo 'Black formatting skipped (not installed)'; fi",
"timeout": 30
}
]
},
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.py$ ]]; then isort \"$FILE\" 2>/dev/null || echo 'isort skipped (not installed)'; fi",
"timeout": 30
}
]
},
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.py$ ]]; then RESULT=$(flake8 \"$FILE\" 2>&1); if [ $? -ne 0 ] && command -v flake8 >/dev/null 2>&1; then echo \"Flake8 linting issues found: $RESULT\" >&2; exit 2; fi; fi",
"timeout": 30
}
]
},
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.py$ ]]; then RESULT=$(mypy \"$FILE\" 2>&1); if [ $? -ne 0 ] && command -v mypy >/dev/null 2>&1; then echo \"MyPy type checking issues found: $RESULT\" >&2; exit 2; fi; fi",
"timeout": 30
}
]
Comment on lines +86 to +104
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Lógica invertida na verificação do Flake8 e MyPy, malandro!

Escuta aqui, tolo! Nas linhas 91 e 101, o código primeiro executa o flake8/mypy e depois verifica se a ferramenta está instalada. Isso significa que se a ferramenta não existir, o shell imprime um erro feio antes de descobrir que não precisava rodar. Verifica a existência antes de executar, sacou?

♻️ Correção proposta para flake8 (linha 91)
-"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.py$ ]]; then RESULT=$(flake8 \"$FILE\" 2>&1); if [ $? -ne 0 ] && command -v flake8 >/dev/null 2>&1; then echo \"Flake8 linting issues found: $RESULT\" >&2; exit 2; fi; fi",
+"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.py$ ]] && command -v flake8 >/dev/null 2>&1; then RESULT=$(flake8 \"$FILE\" 2>&1); if [ $? -ne 0 ]; then echo \"Flake8 linting issues found: $RESULT\" >&2; exit 2; fi; fi",

Mesma correção se aplica ao MyPy na linha 101.

🤖 Prompt for AI Agents
In @.claude/settings.json around lines 86 - 104, O hook executa flake8/mypy
antes de checar se a ferramenta existe; ajuste as duas commands para verificar
"command -v flake8" / "command -v mypy" antes de rodar a ferramenta (use a
verificação de disponibilidade primeiro) e só então executar RESULT=$(flake8
"$FILE" 2>&1) ou RESULT=$(mypy "$FILE" 2>&1) quando FILE terminar em .py;
aplique a mesma inversão na string do hook que referencia $FILE e os comandos
flake8/mypy para evitar erros de comando não encontrado.

},
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.py$ && \"$FILE\" != *\"test_\"* && \"$FILE\" != *\"_test.py\" ]]; then DIR=$(dirname \"$FILE\"); BASENAME=$(basename \"$FILE\" .py); for TEST_FILE in \"$DIR/test_$BASENAME.py\" \"$DIR/${BASENAME}_test.py\" \"tests/test_$BASENAME.py\"; do if [ -f \"$TEST_FILE\" ]; then echo \"Running tests for $TEST_FILE...\"; if command -v pytest >/dev/null 2>&1; then pytest \"$TEST_FILE\" -v; elif python -m pytest \"$TEST_FILE\" 2>/dev/null; then python -m pytest \"$TEST_FILE\" -v; else python -m unittest \"$TEST_FILE\" 2>/dev/null || echo 'No test runner found'; fi; break; fi; done; fi",
"timeout": 60
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo \"Claude Code notification: $(date)\" >> ~/.claude/notifications.log"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "if [[ -f requirements.txt || -f pyproject.toml || -f setup.py ]] && [[ $(git status --porcelain | grep '\\.py$') ]]; then echo 'Running linter on changed Python files...'; if command -v flake8 >/dev/null 2>&1; then flake8 $(git diff --name-only --diff-filter=ACMR | grep '\\.py$'); elif command -v pylint >/dev/null 2>&1; then pylint $(git diff --name-only --diff-filter=ACMR | grep '\\.py$'); else echo 'No Python linter found (flake8/pylint)'; fi; fi",
"timeout": 60
}
]
},
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "if [[ -f requirements.txt || -f pyproject.toml || -f setup.py ]] && [[ $(git status --porcelain | grep '\\.py$') ]]; then echo 'Running type checking on changed files...'; if command -v mypy >/dev/null 2>&1; then mypy $(git diff --name-only --diff-filter=ACMR | grep '\\.py$') || echo 'Type checking completed with issues'; else echo 'MyPy not found for type checking'; fi; fi",
"timeout": 60
}
]
}
]
}
}
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
API_ID=123456
API_HASH=your_api_hash_here

# Optional: session file name (default: session)
# Optional: session file name or path
# - Nome simples (ex.: session) salva em ~/.clean_telegram/
# - Caminho absoluto/relativo permite personalizar local
SESSION_NAME=session
13 changes: 13 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[flake8]
max-line-length = 100
exclude =
.git,
__pycache__,
.venv,
venv,
build,
dist,
*.egg-info
ignore = E203, W503
per-file-ignores =
__init__.py:F401
Loading