feat(system): S90: drone JSON fix + cli AIPASS_HOME auto-detect + mailbox + prax monitor refactor + test isolation

Co-Authored-By: @devpulse <devpulse@aipass>
This commit is contained in:
AIOSAI
2026-04-11 18:00:43 -07:00
co-authored by @devpulse
parent 35928fc911
commit e7950e76f9
8 changed files with 313 additions and 156 deletions
+149 -5
View File
@@ -91,6 +91,7 @@ def test_init_project_creates_all_expected_files(tmp_path):
target / "STATUS.local.md",
target / ".gitignore",
target / ".claude" / "settings.json",
target / ".ai_mail.local" / "inbox.json",
]
for f in expected_files:
assert f.exists(), f"Expected file not created: {f}"
@@ -105,8 +106,8 @@ def test_init_project_creates_all_expected_files(tmp_path):
# No local prompt at project level (belongs in agent dirs only)
assert not (target / ".aipass" / "aipass_local_prompt.md").exists()
# 9 files + 2 directories = 11 created_files entries
assert len(result["created_files"]) == 11
# 10 files + 2 directories = 12 created_files entries
assert len(result["created_files"]) == 12
def test_init_project_return_dict_structure(tmp_path):
@@ -122,6 +123,7 @@ def test_init_project_return_dict_structure(tmp_path):
"project_name",
"target",
"created_files",
"aipass_home",
}
assert result["project_name"] == "ALPHA"
assert result["registry_file"] == "ALPHA_REGISTRY.json"
@@ -312,7 +314,7 @@ def test_init_project_auto_creates_target_dir(tmp_path):
assert target.is_dir()
assert result["project_name"] == "NESTED"
assert len(result["created_files"]) == 11
assert len(result["created_files"]) == 12
def test_init_project_defaults_name_from_directory(tmp_path):
@@ -367,6 +369,10 @@ def test_init_project_skips_existing_optional_files(tmp_path):
src_dir = target / "src"
src_dir.mkdir()
mail_dir = target / ".ai_mail.local"
mail_dir.mkdir()
(mail_dir / "inbox.json").write_text("{}\n", encoding="utf-8")
result = init_project(target, project_name="eta")
# Only registry should be in created_files (everything else pre-existed)
@@ -445,6 +451,7 @@ def test_update_project_return_dict_structure(tmp_path):
"updated_files",
"already_current",
"skipped_files",
"aipass_home",
}
assert result["project_name"] == "UPD"
assert result["target"] == str(target.resolve())
@@ -546,11 +553,148 @@ def test_update_project_creates_missing_managed_dirs(tmp_path):
def test_update_project_skipped_files_count(tmp_path):
"""update_project always skips exactly 4 user-owned files."""
"""update_project skips 4 user-owned files + existing mailbox = 5 total."""
target = tmp_path / "proj"
target.mkdir()
init_project(target, project_name="count")
result = update_project(target)
assert len(result["skipped_files"]) == 4
# 4 user-owned (registry, README, STATUS, .gitignore) + inbox.json = 5
assert len(result["skipped_files"]) == 5
# ---------------------------------------------------------------------------
# DPLAN-0121: AIPASS_HOME + mailbox tests
# ---------------------------------------------------------------------------
def test_init_project_creates_mailbox(tmp_path):
"""init_project creates .ai_mail.local/inbox.json."""
target = tmp_path / "proj"
target.mkdir()
init_project(target, project_name="mail")
assert (target / ".ai_mail.local" / "inbox.json").exists()
def test_init_project_mailbox_json_contents(tmp_path):
"""inbox.json has valid empty mailbox structure."""
target = tmp_path / "proj"
target.mkdir()
init_project(target, project_name="mail")
data = json.loads((target / ".ai_mail.local" / "inbox.json").read_text(encoding="utf-8"))
assert data["mailbox"] == "inbox"
assert data["total_messages"] == 0
assert data["unread_count"] == 0
assert data["messages"] == []
def test_init_project_mailbox_not_overwritten_on_rerun(tmp_path):
"""Re-running init skips existing inbox.json."""
target = tmp_path / "proj"
target.mkdir()
init_project(target, project_name="mail")
inbox = target / ".ai_mail.local" / "inbox.json"
inbox.write_text('{"custom": true}\n', encoding="utf-8")
init_project(target, project_name="mail")
assert json.loads(inbox.read_text(encoding="utf-8")) == {"custom": True}
def test_init_project_returns_aipass_home(tmp_path):
"""init_project return dict includes aipass_home key."""
target = tmp_path / "proj"
target.mkdir()
result = init_project(target, project_name="home")
assert "aipass_home" in result
assert result["aipass_home"] is None or isinstance(result["aipass_home"], str)
def test_init_project_settings_has_aipass_home_when_detected(tmp_path):
"""When AIPASS_HOME is detected, settings.json includes env.AIPASS_HOME."""
target = tmp_path / "proj"
target.mkdir()
result = init_project(target, project_name="env")
if result["aipass_home"] is None:
pytest.skip("AIPASS_HOME not detectable in this environment")
settings = json.loads((target / ".claude" / "settings.json").read_text(encoding="utf-8"))
assert "env" in settings
assert settings["env"]["AIPASS_HOME"] == result["aipass_home"]
def test_update_project_creates_mailbox_if_missing(tmp_path):
"""update_project creates inbox.json if it does not exist."""
import shutil
target = tmp_path / "proj"
target.mkdir()
init_project(target, project_name="newmail")
# Remove the entire mailbox directory to simulate missing mailbox
shutil.rmtree(target / ".ai_mail.local")
result = update_project(target)
inbox = target / ".ai_mail.local" / "inbox.json"
assert inbox.exists()
assert str(inbox) in result["updated_files"]
def test_update_project_skips_existing_mailbox(tmp_path):
"""update_project never overwrites an existing inbox.json."""
target = tmp_path / "proj"
target.mkdir()
init_project(target, project_name="keepmail")
inbox = target / ".ai_mail.local" / "inbox.json"
inbox.write_text(
'{"mailbox":"inbox","total_messages":5,"unread_count":2,"messages":["x"]}\n',
encoding="utf-8",
)
result = update_project(target)
assert str(inbox) in result["skipped_files"]
assert json.loads(inbox.read_text(encoding="utf-8"))["total_messages"] == 5
def test_update_project_returns_aipass_home(tmp_path):
"""update_project return dict includes aipass_home key."""
target = tmp_path / "proj"
target.mkdir()
init_project(target, project_name="uhome")
result = update_project(target)
assert "aipass_home" in result
assert result["aipass_home"] is None or isinstance(result["aipass_home"], str)
def test_update_project_adds_aipass_home_if_missing(tmp_path):
"""update_project injects AIPASS_HOME into settings.json if env section is absent."""
target = tmp_path / "proj"
target.mkdir()
init_project(target, project_name="addenv")
settings_path = target / ".claude" / "settings.json"
data = json.loads(settings_path.read_text(encoding="utf-8"))
data.pop("env", None)
settings_path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
result = update_project(target)
if result["aipass_home"] is not None:
new_data = json.loads(settings_path.read_text(encoding="utf-8"))
assert new_data.get("env", {}).get("AIPASS_HOME") == result["aipass_home"]
assert str(settings_path) in result["updated_files"]