Skip to content

Commit 62b56b8

Browse files
VicVic
authored andcommitted
pip install -e
1 parent 03e7278 commit 62b56b8

13 files changed

Lines changed: 250 additions & 95 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ __pycache__
22
.mypy_cache
33
*_cache
44
.DS_STORE
5+
src/pyob.egg-info
56
dist
67
build
78
ALF.md

README.md

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,27 @@ Interactive terminal checkpoints at every stage:
7575

7676
---
7777

78-
## 🚀 Getting Started
78+
Here is the updated **Getting Started** section for your `README.md`.
7979

80-
PyOB can be used either as a pre-compiled standalone application (Recommended) or by running the source code directly.
80+
I have refactored it to reflect the new professional `src/` layout, the Python 3.12 requirement, the `pyproject.toml` installation method, and the new `./check.sh` validation workflow.
81+
82+
---
83+
84+
### 🚀 Getting Started
85+
86+
PyOB can be used either as a pre-compiled standalone application (Recommended for Users) or installed as an editable package from source (Recommended for Developers).
8187

8288
### 📋 Prerequisites
8389

8490
Regardless of installation method, PyOB utilizes external tools for code verification and local LLM fallback.
8591

8692
| Requirement | Purpose | Required? |
8793
|---|---|---|
94+
| **Python 3.12+** | Core Runtime |**Mandatory** |
8895
| **[Ollama](https://ollama.ai)** | Local model server (fallback) | ⚡ Recommended |
8996
| **`ruff`** | Python linting & formatting | ⚡ Recommended |
9097
| **`mypy`** | Static type checking | ⚡ Recommended |
91-
| **Node.js** | JavaScript syntax validation | Optional |
98+
| **`pytest`** | Unit testing suite | ⚡ Recommended |
9299

93100
---
94101

@@ -97,41 +104,32 @@ Regardless of installation method, PyOB utilizes external tools for code verific
97104
Download the latest pre-built binaries from the **[Releases Page](https://github.com/vicsanity623/PyOB/releases)**.
98105

99106
#### **macOS (.dmg)**
100-
1. **Download and Mount:** Open `PyOB-v0.2.0.dmg`.
101-
2. **Install:** Drag the **PyOB** icon into your `/Applications` folder.
102-
3. **Launch:** Open PyOB via Spotlight (`Cmd + Space` > "PyOB").
103-
4. **Setup:** A Terminal window will open automatically. Follow the prompts to enter your Gemini API keys and select your AI models. These settings are saved to `~/.pyob_config`.
104-
105-
#### **Windows (.exe)**
106-
1. **Download:** Save `PyOB.exe` to a known directory.
107-
2. **Launch:** Double-click the executable or run it via PowerShell/CMD.
108-
3. **Setup:** Follow the on-screen prompts to configure your API keys and model preferences.
107+
1. **Download and Mount:** Open `Py-OB-v0.2.2.dmg`.
108+
2. **Install:** Drag the **Py-OB** icon into your `/Applications` folder.
109+
3. **Launch:** Open Py-OB via Spotlight (`Cmd + Space` > "Py-OB").
110+
4. **Setup:** A Terminal window will open automatically. Follow the prompts to configure your API keys.
109111

110112
---
111113

112114
### 🛠️ Option 2: Running from Source (Developers)
113115

114-
Use this method if you wish to modify PyOB or contribute to its development.
116+
Use this method to modify PyOB, add features, or run the test suite. PyOB now uses a professional `src/` layout.
115117

116-
#### **1. Environment Setup (iMac)**
118+
#### **1. Environment Setup**
117119
```bash
118120
# Clone the repository
119121
git clone https://github.com/vicsanity623/PyOB.git
120122
cd PyOB
121123

122-
brew install python@3.12
123-
124-
# 2. Wipe the old environment
125-
deactivate 2>/dev/null
124+
# Create a clean Python 3.12 environment
126125
rm -rf build_env
127-
128-
# 3. Create the 3.12 environment
129126
python3.12 -m venv build_env
130-
131-
# 4. Activate and Install
132127
source build_env/bin/activate
128+
129+
# Install PyOB in "Editable" mode with all dependencies
133130
pip install --upgrade pip
134-
pip install ruff mypy requests ollama pyinstaller psutil chardet charset-normalizer types-chardet
131+
pip install -e .
132+
pip install ruff mypy pytest
135133
```
136134

137135
#### **2. Local Model Preparation**
@@ -140,34 +138,42 @@ If you intend to use the local fallback feature, pull the recommended model:
140138
ollama pull qwen3-coder:30b
141139
```
142140

143-
#### **3. Execution**
144-
Run the launcher directly. On the first run, you will be prompted to configure your API keys and model settings.
141+
#### **3. Validation**
142+
Run the full validation suite (Linter + Type Checker + Tests) before running the agent:
143+
```bash
144+
./check.sh
145+
```
146+
147+
#### **4. Execution**
148+
Once installed via `pip install -e .`, you can launch PyOB from anywhere using the global command:
149+
*cd into the folder you want to scan first.
150+
*Do not run `pyob` from the pyob root folder unless of course you want it to evolve itself..
145151
```bash
146-
python PyOB_launcher.py
152+
pyob
147153
```
154+
*To target a specific project directory immediately:* `pyob /path/to/your/project`
155+
*To target pyob itself run this from inside pyob root:* `pyob`
148156

149157
---
150158

151159
### 🎯 Quick Start Workflow
152160

153161
1. **Targeting:** Provide the path to the project you want PyOB to manage.
154162
2. **Dashboard:** Open **`http://localhost:5000`** to watch the "Observer" dashboard in real-time.
155-
3. **Approve:** When PyOB proposes a fix or feature, review the diff and hit `ENTER`.
156-
4. **Observe:** Watch the **Cascade Queue** trigger as PyOB ripples changes through your files.
157-
5. **Self-Evolution:** To have PyOB improve itself, target its own root: `python pyob_launcher.py .`
158-
6. **Verification:** The system runs the 4-layer pipeline (XML Match → Lint → PIR → Runtime Test) to ensure the code is functional.
159-
7. **Persistence:** Your `MEMORY.md` and `HISTORY.md` are updated to maintain context for the next iteration.
163+
3. **Approve:** When PyOB proposes a fix or feature, review the diff in your terminal and hit `ENTER`.
164+
4. **Self-Evolution:** To have PyOB improve itself, target its own root directory: `pyob .`
165+
5. **Verification:** The system runs a 4-layer pipeline (XML Match → Lint → Runtime Test → Downstream Ripple Check) to ensure the code is functional.
166+
6. **Auto-Locking:** Any dependencies PyOB installs during auto-repair are automatically locked into your `requirements.txt`.
160167

168+
### 🔄 The Autonomous Loop
161169
PyOB will:
162-
1. 🔍 **Bootstrap** — Generate `ANALYSIS.md` (project map) and `SYMBOLS.json` (dependency graph)
163-
2. 🎯 **Target** — Intelligently select the next file to review based on history and dependencies
164-
3. 🔬 **Analyze** — Scan for bugs, lint errors, and architectural gaps
165-
4. 💡 **Propose** — Generate a `PEER_REVIEW.md` (bug fixes) or `FEATURE.md` (new features)
166-
5. ⏸️ **Checkpoint** — Wait for your approval before applying any changes
167-
6.**Verify** — Run the 4-layer verification pipeline and auto-heal if needed
168-
7. 🔗 **Cascade** — Detect and queue downstream dependency impacts
169-
8. 💾 **Persist** — Update `MEMORY.md` and `HISTORY.md` with session context
170-
9. 🔁 **Iterate** — Loop back to step 2 with a 2-minute cooldown
170+
1. 🔍 **Bootstrap** — Generate `ANALYSIS.md` (project map) and `SYMBOLS.json` (symbolic ledger).
171+
2. 🎯 **Target** — Intelligently select the next file to review based on history and symbolic ripples.
172+
3. 🔬 **Analyze** — Scan for bugs, type errors, and architectural bloat (>800 lines).
173+
4. 💡 **Propose** — Generate a `PEER_REVIEW.md` (fixes) or `FEATURE.md` (new logic).
174+
5.**Verify** — Perform a "Dry Run" and runtime check before finalizing any edit.
175+
6. 🔗 **Cascade** — Detect and queue downstream dependency impacts for immediate follow-up.
176+
7. 💾 **Persist** — Compress and update `MEMORY.md` to maintain context for the next iteration.
171177

172178
---
173179

build_pyinstaller_multiOS.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ def main():
1414
f"--name={APP_NAME}",
1515
"--clean",
1616
"--noconfirm",
17+
"--paths=src",
18+
"--collect-all=pyob",
1719
"--hidden-import=autoreviewer",
1820
"--hidden-import=reviewer_mixins",
1921
"--hidden-import=core_utils",
2022
"--hidden-import=prompts_and_memory",
23+
"--hidden-import=pyob.entrance",
2124
"--hidden-import=requests",
2225
"--hidden-import=ollama",
2326
"--hidden-import=textwrap",
@@ -32,7 +35,7 @@ def main():
3235
"--collect-all=ollama",
3336
"--collect-all=charset_normalizer",
3437
"--collect-all=chardet",
35-
"pyob_launcher.py",
38+
"src/pyob/pyob_launcher.py",
3639
]
3740

3841
if os_name == "darwin":

check.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
# Check if --fix argument was passed
6+
if [[ "$1" == "--fix" ]]; then
7+
echo "🛠️ Auto-fixing issues..."
8+
ruff check src/ --fix
9+
ruff format src/
10+
echo "✅ Fixes applied."
11+
echo "-------------------------------------"
12+
fi
13+
14+
echo "🚀 Starting PyOB Validation Suite..."
15+
16+
echo "-------------------------------------"
17+
echo "🧹 1. Running Ruff (Linter & Imports)..."
18+
ruff check src/
19+
20+
echo "-------------------------------------"
21+
echo "🪄 2. Running Ruff (Formatting Check)..."
22+
ruff format --check src/
23+
24+
echo "-------------------------------------"
25+
echo "🔎 3. Running Mypy (Type Checking)..."
26+
mypy src/
27+
28+
echo "-------------------------------------"
29+
echo "🧪 4. Running Pytest (Unit Tests)..."
30+
if [ -d "tests" ] && [ "$(ls -A tests 2>/dev/null)" ]; then
31+
pytest tests/
32+
else
33+
echo "⚠️ No tests found in 'tests/' directory."
34+
fi
35+
36+
echo "-------------------------------------"
37+
echo "✅ All checks passed!"

pyproject.toml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "pyob"
7+
version = "0.2.2"
8+
description = "PyOuroBoros: An autonomous Python coding agent."
9+
readme = "README.md"
10+
requires-python = ">=3.12"
11+
dependencies = [
12+
"requests",
13+
"charset-normalizer",
14+
"chardet",
15+
"ollama"
16+
]
17+
18+
[project.scripts]
19+
pyob = "pyob.pyob_launcher:main"
20+
21+
[tool.setuptools.packages.find]
22+
where = ["src"]
23+
24+
[tool.ruff]
25+
line-length = 88
26+
27+
[tool.ruff.lint]
28+
select = ["E", "F", "W", "I"] # Flake8, Pyflakes, Warnings, isort
29+
ignore = ["E501"] # Ignore line length violations (let formatter handle it)
30+
31+
[tool.mypy]
32+
python_version = "3.12"
33+
warn_return_any = true
34+
warn_unused_configs = true
35+
ignore_missing_imports = true
36+
explicit_package_bases = true
37+
38+
[tool.pytest.ini_options]
39+
pythonpath = ["src"]
40+
testpaths = ["tests"]

src/pyob/__init__.py

Whitespace-only changes.
Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
1+
import ast
2+
import difflib
13
import os
4+
import random
25
import re
3-
import difflib
4-
import ast
56
import subprocess
6-
import random
77
import sys
88
import time
99

10-
from core_utils import (
11-
logger,
10+
from pyob.core_utils import (
11+
ANALYSIS_FILE,
12+
FAILED_FEATURE_FILE_NAME,
13+
FAILED_PR_FILE_NAME,
14+
FEATURE_FILE_NAME,
15+
GEMINI_API_KEYS,
16+
HISTORY_FILE,
1217
IGNORE_DIRS,
1318
IGNORE_FILES,
14-
SUPPORTED_EXTENSIONS,
15-
CoreUtilsMixin,
16-
GEMINI_API_KEYS,
17-
PR_FILE_NAME,
18-
FEATURE_FILE_NAME,
19-
FAILED_PR_FILE_NAME,
20-
FAILED_FEATURE_FILE_NAME,
2119
MEMORY_FILE_NAME,
22-
ANALYSIS_FILE,
23-
HISTORY_FILE,
20+
PR_FILE_NAME,
21+
SUPPORTED_EXTENSIONS,
2422
SYMBOLS_FILE,
23+
CoreUtilsMixin,
24+
logger,
2525
)
26-
27-
from prompts_and_memory import PromptsAndMemoryMixin
28-
from reviewer_mixins import ValidationMixin, FeatureOperationsMixin
26+
from pyob.prompts_and_memory import PromptsAndMemoryMixin
27+
from pyob.reviewer_mixins import FeatureOperationsMixin, ValidationMixin
2928

3029

3130
class AutoReviewer(
@@ -125,15 +124,17 @@ def build_patch_prompt(
125124
if custom_issues
126125
else ""
127126
)
128-
return self.load_prompt(
129-
"PP.md",
130-
lang_name=lang_name,
131-
lang_tag=lang_tag,
132-
content=content,
133-
memory_section=memory_section,
134-
ruff_section=ruff_section,
135-
mypy_section=mypy_section,
136-
custom_issues_section=custom_issues_section,
127+
return str(
128+
self.load_prompt(
129+
"PP.md",
130+
lang_name=lang_name,
131+
lang_tag=lang_tag,
132+
content=content,
133+
memory_section=memory_section,
134+
ruff_section=ruff_section,
135+
mypy_section=mypy_section,
136+
custom_issues_section=custom_issues_section,
137+
)
137138
)
138139

139140
def get_valid_edit(

core_utils.py renamed to src/pyob/core_utils.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1+
import ast
2+
import json
3+
import logging
14
import os
25
import re
3-
import ast
6+
import select
7+
import shutil
48
import subprocess
5-
import logging
69
import sys
7-
import time
8-
import threading
9-
import json
10-
import requests
11-
import select
12-
import tty
1310
import termios
14-
import shutil
1511
import textwrap
12+
import threading
13+
import time
14+
import tty
15+
16+
import requests
1617

1718
try:
1819
import ollama

entrance.py renamed to src/pyob/entrance.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1-
import os
2-
import sys
31
import ast
4-
import re
52
import difflib
6-
import time
7-
import logging
83
import json
9-
import subprocess
4+
import logging
5+
import os
6+
import re
107
import shutil
11-
from http.server import BaseHTTPRequestHandler, HTTPServer
8+
import subprocess
9+
import sys
1210
import threading
13-
from autoreviewer import AutoReviewer
11+
import time
12+
from http.server import BaseHTTPRequestHandler, HTTPServer
1413
from pathlib import Path
1514
from typing import Any
1615

16+
from pyob.autoreviewer import AutoReviewer
17+
1718
logging.basicConfig(level=logging.INFO, format="%(asctime)s | %(message)s")
1819
logger = logging.getLogger(__name__)
1920

@@ -460,7 +461,7 @@ def val(text: str) -> bool:
460461
p = text.strip().strip("`").strip()
461462
return os.path.exists(os.path.join(self.target_dir, p)) and p != last_file
462463

463-
return (
464+
return str(
464465
self.llm_engine.get_valid_llm_response(
465466
prompt, val, context="Target Selector"
466467
)

0 commit comments

Comments
 (0)