feat: major architectural refactor

- Refactor memory system (episodic/STM/LTM with components)
- Implement complete subtitle domain (scanner, matcher, placer)
- Add YAML workflow infrastructure
- Externalize knowledge base (patterns, release groups)
- Add comprehensive testing suite
- Create manual testing CLIs
This commit is contained in:
2026-05-11 21:33:37 +02:00
parent 62b5d0b998
commit 249c5de76a
103 changed files with 8559 additions and 1346 deletions
+16 -16
View File
@@ -24,7 +24,7 @@ class TestSetPathForFolder:
fs_tools.set_path_for_folder("download", str(real_folder["downloads"]))
mem = get_memory()
assert mem.ltm.get_config("download_folder") == str(real_folder["downloads"])
assert mem.ltm.download_folder == str(real_folder["downloads"])
def test_all_folder_types(self, memory, real_folder):
"""Should accept all valid folder types."""
@@ -73,7 +73,7 @@ class TestListFolder:
def test_success(self, memory, real_folder):
"""Should list folder contents."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download")
@@ -84,7 +84,7 @@ class TestListFolder:
def test_subfolder(self, memory, real_folder):
"""Should list subfolder contents."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "test_series")
@@ -105,7 +105,7 @@ class TestListFolder:
def test_path_traversal_dotdot(self, memory, real_folder):
"""Should block path traversal with .."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "../")
@@ -113,7 +113,7 @@ class TestListFolder:
def test_path_traversal_absolute(self, memory, real_folder):
"""Should block absolute paths."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "/etc/passwd")
@@ -121,7 +121,7 @@ class TestListFolder:
def test_path_traversal_encoded(self, memory, real_folder):
"""Should block encoded traversal attempts."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "..%2F..%2Fetc")
@@ -130,7 +130,7 @@ class TestListFolder:
def test_path_not_exists(self, memory, real_folder):
"""Should return error for non-existent path."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "nonexistent_folder")
@@ -138,7 +138,7 @@ class TestListFolder:
def test_path_is_file(self, memory, real_folder):
"""Should return error if path is a file."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "test_movie.mkv")
@@ -148,7 +148,7 @@ class TestListFolder:
"""Should handle empty folder."""
empty_dir = real_folder["downloads"] / "empty"
empty_dir.mkdir()
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "empty")
@@ -161,7 +161,7 @@ class TestListFolder:
# Create files with different names
(real_folder["downloads"] / "zebra.txt").touch()
(real_folder["downloads"] / "alpha.txt").touch()
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download")
@@ -176,7 +176,7 @@ class TestFileManagerSecurity:
def test_null_byte_injection(self, memory, real_folder):
"""Should block null byte injection."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "test\x00.txt")
@@ -184,7 +184,7 @@ class TestFileManagerSecurity:
def test_path_outside_root(self, memory, real_folder):
"""Should block paths that escape root."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
# Try to access parent directory
result = fs_tools.list_folder("download", "test_series/../../")
@@ -200,7 +200,7 @@ class TestFileManagerSecurity:
except OSError:
pytest.skip("Cannot create symlinks")
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "escape_link")
@@ -212,7 +212,7 @@ class TestFileManagerSecurity:
"""Should handle special characters in path."""
special_dir = real_folder["downloads"] / "special !@#$%"
special_dir.mkdir()
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "special !@#$%")
@@ -222,7 +222,7 @@ class TestFileManagerSecurity:
"""Should handle unicode in path."""
unicode_dir = real_folder["downloads"] / "日本語フォルダ"
unicode_dir.mkdir()
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
result = fs_tools.list_folder("download", "日本語フォルダ")
@@ -230,7 +230,7 @@ class TestFileManagerSecurity:
def test_very_long_path(self, memory, real_folder):
"""Should handle very long paths gracefully."""
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
memory.ltm.download_folder = str(real_folder["downloads"])
long_path = "a" * 1000