Skip to content

Commit 3b47ef9

Browse files
GeneAIclaude
authored andcommitted
chore: Release v3.2.0
## Highlights - Unified Typer CLI consolidating 5 entry points - Dev Container for one-click development - CI/CD enhancements (Python 3.13, mypy, Codecov, Dependabot) - Documentation restructured with Diátaxis framework - Async pattern detection for Level 3 interactions ## Changes - 2968 tests passing, 57.84% coverage - Package verified with twine 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 2b7f710 commit 3b47ef9

File tree

6 files changed

+79
-28
lines changed

6 files changed

+79
-28
lines changed

CHANGELOG.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,70 @@ All notable changes to the Empathy Framework will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [3.2.0] - 2025-12-24
9+
10+
### Added
11+
12+
**Unified Typer CLI**
13+
- New `empathy` command consolidating 5 entry points into one
14+
- Beautiful Rich output with colored panels and tables
15+
- Subcommand groups: `memory`, `provider`, `workflow`, `wizard`
16+
- Cheatsheet command: `empathy cheatsheet`
17+
- Backward-compatible legacy entry points preserved
18+
19+
**Dev Container Support**
20+
- One-click development environment with VS Code
21+
- Docker Compose setup with Python 3.11 + Redis 7
22+
- Pre-configured VS Code extensions (Python, Ruff, Black, MyPy, Pylance)
23+
- Automatic dependency installation on container creation
24+
25+
**CI/CD Enhancements**
26+
- Python 3.13 added to test matrix (now 3.10-3.13 × 3 OS = 12 jobs)
27+
- MyPy type checking in lint workflow (non-blocking)
28+
- Codecov coverage upload for test tracking
29+
- Documentation workflow for MkDocs build and deploy
30+
- PR labeler for automatic label assignment
31+
- Dependabot for automated dependency updates (pip, actions, docker)
32+
33+
**Async Pattern Detection**
34+
- Background pattern detection for Level 3 proactive interactions
35+
- Non-blocking pattern analysis during conversations
36+
- Sequential, preference, and conditional pattern types
37+
38+
**Workflow Tests**
39+
- PR Review workflow tests (32 tests)
40+
- Dependency Check workflow tests (29 tests)
41+
- Security Audit workflow tests
42+
- Base workflow tests
43+
44+
### Changed
45+
46+
**Documentation Restructured with Diátaxis**
47+
- Tutorials: Learning-oriented guides (installation, quickstart, examples)
48+
- How-to: Task-oriented guides (memory, agents, integration)
49+
- Explanation: Understanding-oriented content (philosophy, concepts)
50+
- Reference: Information-oriented docs (API, CLI, glossary)
51+
- Internal docs moved to `docs/internal/`
52+
53+
**Core Dependencies**
54+
- Added `rich>=13.0.0` for beautiful CLI output
55+
- Added `typer>=0.9.0` for modern CLI commands
56+
- Ruff auto-fix enabled (`fix = true`)
57+
58+
**Project Structure**
59+
- Root directory cleaned up (36 → 7 markdown files)
60+
- Planning docs moved to `docs/development-logs/`
61+
- Architecture docs organized in `docs/architecture/`
62+
- Marketing materials in `docs/marketing/`
63+
64+
### Fixed
65+
66+
- Fixed broken internal documentation links after Diátaxis reorganization
67+
- Lint fixes for unused variables in test files
68+
- Black formatting for workflow tests
69+
70+
---
71+
872
## [3.1.0] - 2025-12-23
973

1074
### Added

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "empathy-framework"
7-
version = "3.1.0"
7+
version = "3.2.0"
88
description = "AI collaboration framework with persistent memory, anticipatory intelligence, code inspection, and multi-agent orchestration"
99
readme = {file = "README.md", content-type = "text/markdown"}
1010
requires-python = ">=3.10"

tests/test_code_review_workflow.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ async def test_run_stage_classify(self):
116116
with patch.object(workflow, "_classify", new_callable=AsyncMock) as mock:
117117
mock.return_value = ({"change_type": "feature"}, 100, 50)
118118

119-
result = await workflow.run_stage("classify", ModelTier.CHEAP, {"diff": "..."})
119+
await workflow.run_stage("classify", ModelTier.CHEAP, {"diff": "..."})
120120

121121
mock.assert_called_once()
122122

@@ -128,7 +128,7 @@ async def test_run_stage_scan(self):
128128
with patch.object(workflow, "_scan", new_callable=AsyncMock) as mock:
129129
mock.return_value = ({"security_issues": []}, 200, 100)
130130

131-
result = await workflow.run_stage("scan", ModelTier.CAPABLE, {"diff": "..."})
131+
await workflow.run_stage("scan", ModelTier.CAPABLE, {"diff": "..."})
132132

133133
mock.assert_called_once()
134134

@@ -140,9 +140,7 @@ async def test_run_stage_architect_review(self):
140140
with patch.object(workflow, "_architect_review", new_callable=AsyncMock) as mock:
141141
mock.return_value = ({"recommendations": []}, 300, 200)
142142

143-
result = await workflow.run_stage(
144-
"architect_review", ModelTier.PREMIUM, {"diff": "..."}
145-
)
143+
await workflow.run_stage("architect_review", ModelTier.PREMIUM, {"diff": "..."})
146144

147145
mock.assert_called_once()
148146

@@ -154,9 +152,7 @@ async def test_run_stage_crew_review(self):
154152
with patch.object(workflow, "_crew_review", new_callable=AsyncMock) as mock:
155153
mock.return_value = ({"crew_analysis": {}}, 500, 300)
156154

157-
result = await workflow.run_stage(
158-
"crew_review", ModelTier.PREMIUM, {"diff": "..."}
159-
)
155+
await workflow.run_stage("crew_review", ModelTier.PREMIUM, {"diff": "..."})
160156

161157
mock.assert_called_once()
162158

tests/test_health_check_workflow.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import json
88
import os
99
import tempfile
10-
from datetime import datetime
1110
from unittest.mock import AsyncMock, MagicMock, patch
1211

1312
import pytest
@@ -267,7 +266,7 @@ async def test_run_stage_fix(self):
267266

268267
from src.empathy_os.workflows.base import ModelTier
269268

270-
result = await workflow.run_stage("fix", ModelTier.CAPABLE, {"path": "."})
269+
await workflow.run_stage("fix", ModelTier.CAPABLE, {"path": "."})
271270

272271
mock_fix.assert_called_once()
273272

tests/test_security_audit_workflow.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
"""
77

88
import json
9-
import os
109
import tempfile
1110
from pathlib import Path
1211
from unittest.mock import AsyncMock, MagicMock, patch
@@ -42,7 +41,7 @@ def test_pattern_structure(self):
4241
def test_severity_values(self):
4342
"""Test that severities are valid values."""
4443
valid_severities = {"critical", "high", "medium", "low"}
45-
for vuln_type, info in SECURITY_PATTERNS.items():
44+
for _vuln_type, info in SECURITY_PATTERNS.items():
4645
assert info["severity"] in valid_severities
4746

4847

@@ -203,7 +202,7 @@ async def test_run_stage_triage(self):
203202
with patch.object(workflow, "_triage", new_callable=AsyncMock) as mock:
204203
mock.return_value = ({"findings": []}, 100, 50)
205204

206-
result = await workflow.run_stage("triage", ModelTier.CHEAP, {"path": "."})
205+
await workflow.run_stage("triage", ModelTier.CHEAP, {"path": "."})
207206

208207
mock.assert_called_once()
209208

@@ -215,9 +214,7 @@ async def test_run_stage_analyze(self):
215214
with patch.object(workflow, "_analyze", new_callable=AsyncMock) as mock:
216215
mock.return_value = ({"analysis": {}}, 200, 100)
217216

218-
result = await workflow.run_stage(
219-
"analyze", ModelTier.CAPABLE, {"findings": []}
220-
)
217+
await workflow.run_stage("analyze", ModelTier.CAPABLE, {"findings": []})
221218

222219
mock.assert_called_once()
223220

@@ -229,7 +226,7 @@ async def test_run_stage_assess(self):
229226
with patch.object(workflow, "_assess", new_callable=AsyncMock) as mock:
230227
mock.return_value = ({"risk_score": 0}, 150, 75)
231228

232-
result = await workflow.run_stage("assess", ModelTier.CAPABLE, {})
229+
await workflow.run_stage("assess", ModelTier.CAPABLE, {})
233230

234231
mock.assert_called_once()
235232

@@ -241,7 +238,7 @@ async def test_run_stage_remediate(self):
241238
with patch.object(workflow, "_remediate", new_callable=AsyncMock) as mock:
242239
mock.return_value = ({"remediation_plan": []}, 300, 200)
243240

244-
result = await workflow.run_stage("remediate", ModelTier.PREMIUM, {})
241+
await workflow.run_stage("remediate", ModelTier.PREMIUM, {})
245242

246243
mock.assert_called_once()
247244

@@ -348,7 +345,7 @@ async def test_triage_skips_node_modules(self):
348345
with tempfile.TemporaryDirectory() as tmpdir:
349346
node_dir = Path(tmpdir) / "node_modules"
350347
node_dir.mkdir()
351-
(node_dir / "lib.js").write_text('eval(user_input)')
348+
(node_dir / "lib.js").write_text("eval(user_input)")
352349

353350
workflow = SecurityAuditWorkflow()
354351

@@ -463,9 +460,7 @@ def get_user(user_id: int) -> Optional[dict]:
463460
)
464461

465462
# Clean code should have minimal findings
466-
critical_findings = [
467-
f for f in result["findings"] if f["severity"] == "critical"
468-
]
463+
critical_findings = [f for f in result["findings"] if f["severity"] == "critical"]
469464
assert len(critical_findings) == 0
470465

471466
@pytest.mark.asyncio

tests/test_workflow_base.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66

77
from dataclasses import asdict
88
from datetime import datetime
9-
from unittest.mock import AsyncMock, MagicMock, patch
10-
11-
import pytest
129

1310
from src.empathy_os.workflows.base import (
1411
PROVIDER_MODELS,
@@ -104,8 +101,8 @@ def test_hybrid_models_exist(self):
104101

105102
def test_model_names_are_strings(self):
106103
"""Test all model names are strings."""
107-
for provider, models in PROVIDER_MODELS.items():
108-
for tier, model_name in models.items():
104+
for _provider, models in PROVIDER_MODELS.items():
105+
for _tier, model_name in models.items():
109106
assert isinstance(model_name, str)
110107
assert len(model_name) > 0
111108

0 commit comments

Comments
 (0)