feat(client): Mac aider-watch client (B1-B4: scaffolding + api_client + buffer + aiderw)

This commit is contained in:
Your Name
2026-04-20 09:51:53 +08:00
parent e1539a813e
commit 36610e2744
19 changed files with 633 additions and 0 deletions

View File

@@ -0,0 +1 @@
# 2026-04-20 @ Asia/Taipei

View File

@@ -0,0 +1,23 @@
# 2026-04-20 @ Asia/Taipei
import hmac, hashlib
from aider_watch_client.api_client import sign_body
def test_sign_body_format():
body = b'{"events":[]}'
sig = sign_body(body, "secret")
assert sig.startswith("sha256=")
expected = "sha256=" + hmac.new(b"secret", body, hashlib.sha256).hexdigest()
assert sig == expected
def test_sign_body_deterministic():
assert sign_body(b"same", "secret") == sign_body(b"same", "secret")
def test_sign_body_different_secrets():
assert sign_body(b"body", "sec1") != sign_body(b"body", "sec2")
def test_sign_body_different_bodies():
assert sign_body(b"a", "s") != sign_body(b"b", "s")

View File

@@ -0,0 +1,53 @@
# 2026-04-20 @ Asia/Taipei
import json
from aider_watch_client import buffer
def test_write_reads_back(tmp_path, monkeypatch):
monkeypatch.setattr(buffer, "BUFFER_DIR", tmp_path)
ev = {"type":"session_start","session_id":"s1",
"ts":"2026-04-20T10:00:00+08:00","host":"ogt-mac","payload":{}}
buffer.write([ev])
files = list(tmp_path.glob("pending_*.jsonl"))
assert len(files) == 1
lines = [json.loads(l) for l in files[0].read_text().splitlines() if l.strip()]
assert lines[0]["session_id"] == "s1"
def test_flush_all_drained(tmp_path, monkeypatch):
monkeypatch.setattr(buffer, "BUFFER_DIR", tmp_path)
ev = {"type":"session_start","session_id":"s1",
"ts":"2026-04-20T10:00:00+08:00","host":"ogt-mac","payload":{}}
buffer.write([ev])
sent = []
def fake_post(evs): sent.extend(evs); return True
n = buffer.flush(post_fn=fake_post)
assert n == 1
assert len(sent) == 1
assert list(tmp_path.glob("pending_*.jsonl")) == []
def test_flush_keeps_on_fail(tmp_path, monkeypatch):
monkeypatch.setattr(buffer, "BUFFER_DIR", tmp_path)
ev = {"type":"session_start","session_id":"s1",
"ts":"2026-04-20T10:00:00+08:00","host":"ogt-mac","payload":{}}
buffer.write([ev])
n = buffer.flush(post_fn=lambda evs: False)
assert n == 0
assert len(list(tmp_path.glob("pending_*.jsonl"))) == 1
def test_flush_chunks_oversize(tmp_path, monkeypatch):
""">50 events → chunked."""
monkeypatch.setattr(buffer, "BUFFER_DIR", tmp_path)
events = [{"type":"raw","session_id":f"s{i}",
"ts":"2026-04-20T10:00:00+08:00","host":"m","payload":{}}
for i in range(120)]
buffer.write(events)
posted_sizes = []
def fake_post(evs):
posted_sizes.append(len(evs))
return True
n = buffer.flush(post_fn=fake_post)
assert n == 120
assert posted_sizes == [50, 50, 20] # 切成 3 批