Skip to content

sync-now 알고리즘

🚧 설계 단계 — 아직 구현 안 됨

이 페이지는 ainote 의 향후 기능을 미리 문서화한 것입니다. 현재 @ainote/mcp v1.1.x 에는 vault / sync 도구가 포함돼 있지 않습니다. 도구 호출 시 Tool not found 에러를 받게 됩니다.

~/.claude/ainote-sync/tools/sync-now.sh 의 의사코드.

한 사이클

python
def sync_now(dry_run=False):
    manifest = load("manifest.yml")
    state = load("state.json")
    log = open("log/{YYYY-MM}.jsonl", "a")

    # 1. 로컬 스캔
    local_files = expand(manifest.sync)   # glob 풀어서 (source, target) pair 리스트

    # 2. 원격 list
    remote_files = mcp_call("sync_list", {})  # hub 에서 manifest 매칭 파일들

    # 3. 양쪽 sha256 + mtime + hlc 수집
    pairs = match_pairs(local_files, remote_files)

    # 4. 각 페어별 케이스 결정
    actions = []
    for p in pairs:
        case = decide_case(p, threshold_minutes=5)
        actions.append((p, case))

    # 5. Safety guard
    delete_count = sum(1 for _, c in actions if c == "delete")
    if delete_count / len(actions) > manifest.safety.max_delete_pct / 100:
        abort("max_delete_pct exceeded")

    # 6. dry-run 모드
    if dry_run:
        print_actions(actions)
        return

    # 7. 실행
    for p, case in actions:
        match case:
            case "no-op":  pass
            case "push":   push_to_hub(p)
            case "pull":   pull_from_hub(p)
            case "conflict_save_both":
                save_conflict_files(p)
                ABORT_PROMPT(f"수동 해결: {p.target}")
            case "lww_remote_wins":
                pull_from_hub(p)
            case "lww_local_wins":
                push_to_hub(p)
            case "delete_local":
                delete_local(p)
            case "delete_remote":
                delete_remote(p)

        log.write(json.dumps({
            "ts": now_iso(),
            "device": DEVICE_ID,
            "path": p.target,
            "action": case,
            "local_sha": p.local_sha,
            "remote_sha": p.remote_sha,
            "hlc": p.new_hlc,
        }) + "\n")

        update_state(state, p, case)

    save(state)

decide_case

python
def decide_case(pair, threshold_minutes):
    local_changed = (pair.local_sha != state[pair.target].local_sha)
    remote_changed = (pair.remote_hlc > state[pair.target].hlc)

    if not local_changed and not remote_changed:
        return "no-op"

    if local_changed and not remote_changed:
        if not pair.local_exists:
            return "delete_remote"
        return "push"

    if not local_changed and remote_changed:
        if not pair.remote_exists:
            return "delete_local"
        return "pull"

    # 양쪽 변경
    time_diff = abs(pair.local_mtime - pair.remote_mtime)
    if time_diff <= timedelta(minutes=threshold_minutes):
        return "conflict_save_both"

    if pair.local_hlc > pair.remote_hlc:
        return "lww_local_wins"
    return "lww_remote_wins"

sub-procedures

push_to_hub

python
def push_to_hub(p):
    new_hlc = compute_hlc(now(), state[p.target].hlc, DEVICE_ID)
    mcp_call("sync_push", {
        "path": p.target,
        "content": read_file(p.source),
        "sha256": p.local_sha,
        "hlc": new_hlc,
        "device_id": DEVICE_ID,
    })
    p.new_hlc = new_hlc

pull_from_hub

python
def pull_from_hub(p):
    res = mcp_call("sync_pull", {"path": p.target})
    write_file(p.source, res.content)
    set_mtime(p.source, res.remote_mtime)
    p.new_hlc = res.hlc

save_conflict_files

python
def save_conflict_files(p):
    ts = now().strftime("%Y-%m-%dT%H-%M-%S")
    safe_path = p.target.replace("/", "__")
    out = f"~/.claude/ainote-sync/conflicts/{ts}__{safe_path}.diff"
    write(out, format_diff(
        local=read_file(p.source),
        local_hlc=p.local_hlc,
        remote=mcp_call("sync_pull", {"path": p.target}).content,
        remote_hlc=p.remote_hlc,
    ))

트리거

수동

bash
~/.claude/ainote-sync/tools/sync-now.sh
~/.claude/ainote-sync/tools/sync-now.sh --dry-run

Cron (15분마다)

bash
*/15 * * * * /Users/seunghan/.claude/ainote-sync/tools/sync-now.sh >> /tmp/ainote-sync.log 2>&1

launchd (macOS, 더 안정적)

vault_sync 와 동일 패턴.plistStartInterval: 900.

File watcher (실시간)

bash
fswatch ~/CLAUDE.md ~/.claude/projects/ | xargs -I{} sync-now.sh

audit (주간)

bash
~/.claude/ainote-sync/tools/audit.sh

체크:

  • manifest 의 source 가 모두 존재
  • state.json 과 hub 의 file 목록 차이
  • conflicts/ 의 미해결 파일
  • 최근 7일 변경 통계 (디바이스별)

다음

MIT License · ainote.dev