chat-memory-sync 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Cross-platform sync runner: git pull -> export all harnesses -> commit -> push.
4
+ Works on mac / windows / linux (only needs `git` + `python3`). Scheduled by the
5
+ platform background job; also safe to run manually: python3 run.py
6
+ """
7
+ import os, sys, subprocess, datetime
8
+ from . import cmlib
9
+
10
+ REPO = cmlib.data_dir()
11
+ LOG = os.path.join(cmlib.state_dir(), "sync.log")
12
+
13
+
14
+ def log(msg):
15
+ line = f"{datetime.datetime.now():%Y-%m-%d %H:%M:%S} {msg}"
16
+ print(line)
17
+ try:
18
+ with open(LOG, "a") as f:
19
+ f.write(line + "\n")
20
+ except Exception:
21
+ pass
22
+
23
+
24
+ def git(*args, check=False):
25
+ r = subprocess.run(["git", *args], cwd=REPO, capture_output=True, text=True)
26
+ if check and r.returncode != 0:
27
+ log(f"git {' '.join(args)} failed: {r.stderr.strip()}")
28
+ return r
29
+
30
+
31
+ def ensure_identity():
32
+ """Commit as the user's own git identity. Only set a neutral fallback if the
33
+ machine has no identity configured at all (so a fresh box doesn't error)."""
34
+ if git("config", "user.email").stdout.strip():
35
+ return
36
+ git("config", "user.name", "chat-memory-sync")
37
+ git("config", "user.email", "chat-memory-sync@users.noreply.github.com")
38
+
39
+
40
+ def main():
41
+ global REPO, LOG
42
+ REPO = cmlib.data_dir()
43
+ LOG = os.path.join(cmlib.state_dir(), "sync.log")
44
+ log("===== sync start =====")
45
+
46
+ if not os.path.isdir(os.path.join(REPO, ".git")):
47
+ git("init")
48
+ ensure_identity()
49
+ git("add", "-A")
50
+ git("commit", "-m", "Initial export")
51
+ ensure_identity()
52
+
53
+ has_origin = git("remote", "get-url", "origin").returncode == 0
54
+ branch = (git("rev-parse", "--abbrev-ref", "HEAD").stdout.strip() or "main")
55
+
56
+ if has_origin:
57
+ r = git("pull", "--rebase", "--autostash", "origin", branch)
58
+ log("pulled from origin" if r.returncode == 0 else "pull failed (continuing)")
59
+
60
+ # export
61
+ from . import sync as exporter
62
+ exporter.main()
63
+
64
+ # warm the recall full-text index so first query after a sync is instant
65
+ try:
66
+ from . import recall
67
+ recall.ensure_index(force=True)
68
+ log("recall index rebuilt")
69
+ except Exception as e:
70
+ log(f"recall index skipped: {e}")
71
+
72
+ if git("status", "--porcelain").stdout.strip():
73
+ host = subprocess.run(["hostname"], capture_output=True, text=True).stdout.strip() or "machine"
74
+ git("add", "-A")
75
+ git("commit", "-m", f"Sync chat memory ({host}) {datetime.datetime.now():%Y-%m-%d %H:%M}")
76
+ log("committed changes")
77
+ if has_origin:
78
+ if git("push", "origin", branch).returncode != 0:
79
+ log("push rejected, rebasing and retrying")
80
+ git("pull", "--rebase", "--autostash", "origin", branch)
81
+ r = git("push", "origin", branch)
82
+ log("pushed after retry" if r.returncode == 0 else "push failed")
83
+ else:
84
+ log("pushed to origin")
85
+ else:
86
+ log("no changes")
87
+
88
+ log("===== sync done =====")
89
+
90
+
91
+ if __name__ == "__main__":
92
+ main()