forked from Rockachopa/Timmy-time-dashboard
refactor: Phase 2b — consolidate 28 modules into 14 packages
Complete the module consolidation planned in REFACTORING_PLAN.md: Modules merged: - work_orders/ + task_queue/ → swarm/ (subpackages) - self_modify/ + self_tdd/ + upgrades/ → self_coding/ (subpackages) - tools/ → creative/tools/ - chat_bridge/ + telegram_bot/ + shortcuts/ + voice/ → integrations/ (new) - ws_manager/ + notifications/ + events/ + router/ → infrastructure/ (new) - agents/ + agent_core/ + memory/ → timmy/ (subpackages) Updated across codebase: - 66 source files: import statements rewritten - 13 test files: import + patch() target strings rewritten - pyproject.toml: wheel includes (28→14), entry points updated - CLAUDE.md: singleton paths, module map, entry points table - AGENTS.md: file convention updates - REFACTORING_PLAN.md: execution status, success metrics Extras: - Module-level CLAUDE.md added to 6 key packages (Phase 6.2) - Zero test regressions: 1462 tests passing https://claude.ai/code/session_01JNjWfHqusjT3aiN4vvYgUk
This commit is contained in:
@@ -7,7 +7,7 @@ working tree.
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
from tools.git_tools import (
|
||||
from creative.tools.git_tools import (
|
||||
git_init,
|
||||
git_status,
|
||||
git_add,
|
||||
|
||||
@@ -274,7 +274,7 @@ class TestWebSocketResilience:
|
||||
|
||||
def test_websocket_manager_handles_no_connections(self):
|
||||
"""WebSocket manager handles zero connected clients."""
|
||||
from ws_manager.handler import ws_manager
|
||||
from infrastructure.ws_manager.handler import ws_manager
|
||||
|
||||
# Should not crash when broadcasting with no connections
|
||||
try:
|
||||
@@ -297,7 +297,7 @@ class TestVoiceNLUEdgeCases:
|
||||
|
||||
def test_nlu_empty_string(self):
|
||||
"""Empty string doesn't crash NLU."""
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
result = detect_intent("")
|
||||
assert result is not None
|
||||
@@ -306,14 +306,14 @@ class TestVoiceNLUEdgeCases:
|
||||
|
||||
def test_nlu_all_punctuation(self):
|
||||
"""String of only punctuation is handled."""
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
result = detect_intent("...!!!???")
|
||||
assert result is not None
|
||||
|
||||
def test_nlu_very_long_input(self):
|
||||
"""10k character input doesn't crash or hang."""
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
long_input = "word " * 2000 # ~10k chars
|
||||
|
||||
@@ -327,7 +327,7 @@ class TestVoiceNLUEdgeCases:
|
||||
|
||||
def test_nlu_non_english_text(self):
|
||||
"""Non-English Unicode text is handled."""
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
# Test various Unicode scripts
|
||||
test_inputs = [
|
||||
@@ -343,7 +343,7 @@ class TestVoiceNLUEdgeCases:
|
||||
|
||||
def test_nlu_special_characters(self):
|
||||
"""Special characters don't break parsing."""
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
special_inputs = [
|
||||
"<script>alert('xss')</script>",
|
||||
|
||||
@@ -11,7 +11,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tools.self_edit import (
|
||||
from creative.tools.self_edit import (
|
||||
MAX_FILES_PER_COMMIT,
|
||||
MAX_RETRIES,
|
||||
PROTECTED_FILES,
|
||||
@@ -81,7 +81,7 @@ def test_hello():
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_settings():
|
||||
"""Mock settings to enable self-modification."""
|
||||
with patch('tools.self_edit.settings') as mock_settings:
|
||||
with patch('creative.tools.self_edit.settings') as mock_settings:
|
||||
mock_settings.self_modify_enabled = True
|
||||
yield mock_settings
|
||||
|
||||
@@ -343,7 +343,7 @@ class TestSelfEditGlobalTool:
|
||||
|
||||
async def test_self_edit_tool_singleton(self, temp_repo):
|
||||
"""Should use singleton pattern."""
|
||||
from tools import self_edit as self_edit_module
|
||||
from creative.tools import self_edit as self_edit_module
|
||||
|
||||
# Reset singleton
|
||||
self_edit_module._self_edit_tool = None
|
||||
|
||||
@@ -8,7 +8,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from self_modify.loop import SelfModifyLoop, ModifyRequest, ModifyResult
|
||||
from self_coding.self_modify.loop import SelfModifyLoop, ModifyRequest, ModifyResult
|
||||
|
||||
|
||||
# ── Dataclass tests ───────────────────────────────────────────────────────────
|
||||
@@ -75,7 +75,7 @@ class TestSelfModifyLoop:
|
||||
assert loop._autonomous is True
|
||||
assert loop._max_autonomous_cycles == 5
|
||||
|
||||
@patch("self_modify.loop.settings")
|
||||
@patch("self_coding.self_modify.loop.settings")
|
||||
def test_run_disabled(self, mock_settings):
|
||||
mock_settings.self_modify_enabled = False
|
||||
loop = SelfModifyLoop()
|
||||
@@ -83,8 +83,8 @@ class TestSelfModifyLoop:
|
||||
assert not result.success
|
||||
assert "disabled" in result.error.lower()
|
||||
|
||||
@patch("self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_modify.loop.settings")
|
||||
@patch("self_coding.self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_coding.self_modify.loop.settings")
|
||||
def test_run_no_target_files(self, mock_settings):
|
||||
mock_settings.self_modify_enabled = True
|
||||
mock_settings.self_modify_max_retries = 0
|
||||
@@ -96,8 +96,8 @@ class TestSelfModifyLoop:
|
||||
assert not result.success
|
||||
assert "no target files" in result.error.lower()
|
||||
|
||||
@patch("self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_modify.loop.settings")
|
||||
@patch("self_coding.self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_coding.self_modify.loop.settings")
|
||||
def test_run_success_path(self, mock_settings):
|
||||
mock_settings.self_modify_enabled = True
|
||||
mock_settings.self_modify_max_retries = 2
|
||||
@@ -125,8 +125,8 @@ class TestSelfModifyLoop:
|
||||
loop._run_tests.assert_called_once()
|
||||
loop._git_commit.assert_called_once()
|
||||
|
||||
@patch("self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_modify.loop.settings")
|
||||
@patch("self_coding.self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_coding.self_modify.loop.settings")
|
||||
def test_run_test_failure_reverts(self, mock_settings):
|
||||
mock_settings.self_modify_enabled = True
|
||||
mock_settings.self_modify_max_retries = 0
|
||||
@@ -151,8 +151,8 @@ class TestSelfModifyLoop:
|
||||
assert not result.test_passed
|
||||
loop._revert_files.assert_called()
|
||||
|
||||
@patch("self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_modify.loop.settings")
|
||||
@patch("self_coding.self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_coding.self_modify.loop.settings")
|
||||
def test_dry_run(self, mock_settings):
|
||||
mock_settings.self_modify_enabled = True
|
||||
mock_settings.self_modify_max_retries = 2
|
||||
@@ -207,8 +207,8 @@ class TestSyntaxValidation:
|
||||
errors = loop._validate_syntax({"README.md": "this is not python {{{}"})
|
||||
assert errors == {}
|
||||
|
||||
@patch("self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_modify.loop.settings")
|
||||
@patch("self_coding.self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_coding.self_modify.loop.settings")
|
||||
def test_syntax_error_skips_write(self, mock_settings):
|
||||
"""When LLM produces invalid syntax, we skip writing and retry."""
|
||||
mock_settings.self_modify_enabled = True
|
||||
@@ -264,8 +264,8 @@ class TestBackendResolution:
|
||||
|
||||
|
||||
class TestAutonomousLoop:
|
||||
@patch("self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_modify.loop.settings")
|
||||
@patch("self_coding.self_modify.loop.os.environ", {"SELF_MODIFY_SKIP_BRANCH": "1"})
|
||||
@patch("self_coding.self_modify.loop.settings")
|
||||
def test_autonomous_retries_after_failure(self, mock_settings):
|
||||
mock_settings.self_modify_enabled = True
|
||||
mock_settings.self_modify_max_retries = 0
|
||||
@@ -371,43 +371,43 @@ class TestFileInference:
|
||||
|
||||
class TestCodeIntent:
|
||||
def test_detects_modify_code(self):
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
intent = detect_intent("modify the code in config.py")
|
||||
assert intent.name == "code"
|
||||
|
||||
def test_detects_self_modify(self):
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
intent = detect_intent("self-modify to add a new endpoint")
|
||||
assert intent.name == "code"
|
||||
|
||||
def test_detects_edit_source(self):
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
intent = detect_intent("edit the source to fix the bug")
|
||||
assert intent.name == "code"
|
||||
|
||||
def test_detects_update_your_code(self):
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
intent = detect_intent("update your code to handle errors")
|
||||
assert intent.name == "code"
|
||||
|
||||
def test_detects_fix_function(self):
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
intent = detect_intent("fix the function that calculates totals")
|
||||
assert intent.name == "code"
|
||||
|
||||
def test_does_not_match_general_chat(self):
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
intent = detect_intent("tell me about the weather today")
|
||||
assert intent.name == "chat"
|
||||
|
||||
def test_extracts_target_file_entity(self):
|
||||
from voice.nlu import detect_intent
|
||||
from integrations.voice.nlu import detect_intent
|
||||
|
||||
intent = detect_intent("modify file src/config.py to add debug flag")
|
||||
assert intent.entities.get("target_file") == "src/config.py"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from self_tdd.watchdog import _run_tests
|
||||
from self_coding.self_tdd.watchdog import _run_tests
|
||||
|
||||
|
||||
def _mock_result(returncode: int, stdout: str = "", stderr: str = "") -> MagicMock:
|
||||
@@ -12,26 +12,26 @@ def _mock_result(returncode: int, stdout: str = "", stderr: str = "") -> MagicMo
|
||||
|
||||
|
||||
def test_run_tests_returns_true_when_suite_passes():
|
||||
with patch("self_tdd.watchdog.subprocess.run", return_value=_mock_result(0, "5 passed")):
|
||||
with patch("self_coding.self_tdd.watchdog.subprocess.run", return_value=_mock_result(0, "5 passed")):
|
||||
passed, _ = _run_tests()
|
||||
assert passed is True
|
||||
|
||||
|
||||
def test_run_tests_returns_false_when_suite_fails():
|
||||
with patch("self_tdd.watchdog.subprocess.run", return_value=_mock_result(1, "1 failed")):
|
||||
with patch("self_coding.self_tdd.watchdog.subprocess.run", return_value=_mock_result(1, "1 failed")):
|
||||
passed, _ = _run_tests()
|
||||
assert passed is False
|
||||
|
||||
|
||||
def test_run_tests_output_includes_stdout():
|
||||
with patch("self_tdd.watchdog.subprocess.run", return_value=_mock_result(0, stdout="5 passed")):
|
||||
with patch("self_coding.self_tdd.watchdog.subprocess.run", return_value=_mock_result(0, stdout="5 passed")):
|
||||
_, output = _run_tests()
|
||||
assert "5 passed" in output
|
||||
|
||||
|
||||
def test_run_tests_output_combines_stdout_and_stderr():
|
||||
with patch(
|
||||
"self_tdd.watchdog.subprocess.run",
|
||||
"self_coding.self_tdd.watchdog.subprocess.run",
|
||||
return_value=_mock_result(1, stdout="FAILED test_foo", stderr="ImportError: no module named bar"),
|
||||
):
|
||||
_, output = _run_tests()
|
||||
@@ -40,7 +40,7 @@ def test_run_tests_output_combines_stdout_and_stderr():
|
||||
|
||||
|
||||
def test_run_tests_invokes_pytest_with_correct_flags():
|
||||
with patch("self_tdd.watchdog.subprocess.run", return_value=_mock_result(0)) as mock_run:
|
||||
with patch("self_coding.self_tdd.watchdog.subprocess.run", return_value=_mock_result(0)) as mock_run:
|
||||
_run_tests()
|
||||
cmd = mock_run.call_args[0][0]
|
||||
assert "pytest" in cmd
|
||||
@@ -49,6 +49,6 @@ def test_run_tests_invokes_pytest_with_correct_flags():
|
||||
|
||||
|
||||
def test_run_tests_uses_60s_timeout():
|
||||
with patch("self_tdd.watchdog.subprocess.run", return_value=_mock_result(0)) as mock_run:
|
||||
with patch("self_coding.self_tdd.watchdog.subprocess.run", return_value=_mock_result(0)) as mock_run:
|
||||
_run_tests()
|
||||
assert mock_run.call_args.kwargs["timeout"] == 60
|
||||
|
||||
@@ -7,11 +7,11 @@ from unittest.mock import patch, MagicMock, call
|
||||
|
||||
import pytest
|
||||
|
||||
from self_tdd.watchdog import _run_tests, watch
|
||||
from self_coding.self_tdd.watchdog import _run_tests, watch
|
||||
|
||||
|
||||
class TestRunTests:
|
||||
@patch("self_tdd.watchdog.subprocess.run")
|
||||
@patch("self_coding.self_tdd.watchdog.subprocess.run")
|
||||
def test_run_tests_passing(self, mock_run):
|
||||
mock_run.return_value = MagicMock(
|
||||
returncode=0,
|
||||
@@ -22,7 +22,7 @@ class TestRunTests:
|
||||
assert passed is True
|
||||
assert "5 passed" in output
|
||||
|
||||
@patch("self_tdd.watchdog.subprocess.run")
|
||||
@patch("self_coding.self_tdd.watchdog.subprocess.run")
|
||||
def test_run_tests_failing(self, mock_run):
|
||||
mock_run.return_value = MagicMock(
|
||||
returncode=1,
|
||||
@@ -34,7 +34,7 @@ class TestRunTests:
|
||||
assert "2 failed" in output
|
||||
assert "ERRORS" in output
|
||||
|
||||
@patch("self_tdd.watchdog.subprocess.run")
|
||||
@patch("self_coding.self_tdd.watchdog.subprocess.run")
|
||||
def test_run_tests_command_format(self, mock_run):
|
||||
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
||||
_run_tests()
|
||||
@@ -48,9 +48,9 @@ class TestRunTests:
|
||||
|
||||
|
||||
class TestWatch:
|
||||
@patch("self_tdd.watchdog.time.sleep")
|
||||
@patch("self_tdd.watchdog._run_tests")
|
||||
@patch("self_tdd.watchdog.typer")
|
||||
@patch("self_coding.self_tdd.watchdog.time.sleep")
|
||||
@patch("self_coding.self_tdd.watchdog._run_tests")
|
||||
@patch("self_coding.self_tdd.watchdog.typer")
|
||||
def test_watch_first_pass(self, mock_typer, mock_tests, mock_sleep):
|
||||
"""First iteration: None→passing → should print green message."""
|
||||
call_count = 0
|
||||
@@ -67,9 +67,9 @@ class TestWatch:
|
||||
# Should have printed green "All tests passing" message
|
||||
mock_typer.secho.assert_called()
|
||||
|
||||
@patch("self_tdd.watchdog.time.sleep")
|
||||
@patch("self_tdd.watchdog._run_tests")
|
||||
@patch("self_tdd.watchdog.typer")
|
||||
@patch("self_coding.self_tdd.watchdog.time.sleep")
|
||||
@patch("self_coding.self_tdd.watchdog._run_tests")
|
||||
@patch("self_coding.self_tdd.watchdog.typer")
|
||||
def test_watch_regression(self, mock_typer, mock_tests, mock_sleep):
|
||||
"""Regression: passing→failing → should print red message + output."""
|
||||
results = [(True, "ok"), (False, "FAILED: test_foo"), KeyboardInterrupt]
|
||||
@@ -91,9 +91,9 @@ class TestWatch:
|
||||
secho_calls = [str(c) for c in mock_typer.secho.call_args_list]
|
||||
assert any("Regression" in c for c in secho_calls) or any("RED" in c for c in secho_calls)
|
||||
|
||||
@patch("self_tdd.watchdog.time.sleep")
|
||||
@patch("self_tdd.watchdog._run_tests")
|
||||
@patch("self_tdd.watchdog.typer")
|
||||
@patch("self_coding.self_tdd.watchdog.time.sleep")
|
||||
@patch("self_coding.self_tdd.watchdog._run_tests")
|
||||
@patch("self_coding.self_tdd.watchdog.typer")
|
||||
def test_watch_keyboard_interrupt(self, mock_typer, mock_tests, mock_sleep):
|
||||
mock_tests.side_effect = KeyboardInterrupt
|
||||
watch(interval=60)
|
||||
|
||||
Reference in New Issue
Block a user