Skip to content

Commit 22edd88

Browse files
RMANOVclaude
andcommitted
feat(ui): add memory bridge GitHub sync to Refresh button
Refresh button in FullWindow now also runs git add/commit/push on ~/.claude/memory/bridge/ in a background thread. Uses pyqtSignal for thread-safe status bar updates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1077859 commit 22edd88

1 file changed

Lines changed: 54 additions & 3 deletions

File tree

task_tray.py

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
"""
66

77
import html as _html
8+
import os
89
import sqlite3
10+
import subprocess
11+
import threading
912
import uuid
1013
from datetime import datetime, timedelta, timezone
1114

@@ -214,7 +217,7 @@ def delete_task(self, task_id):
214217
QDialogButtonBox,
215218
)
216219
from PyQt6.QtGui import QIcon, QAction, QPixmap, QPainter, QColor, QFont
217-
from PyQt6.QtCore import QEvent, QSettings, Qt, QTimer, QPoint
220+
from PyQt6.QtCore import QEvent, QSettings, Qt, QTimer, QPoint, pyqtSignal
218221

219222

220223
def create_tray_icon_pixmap(overdue_count=0):
@@ -838,6 +841,8 @@ def _context_menu(self, pos):
838841
class FullWindow(QMainWindow):
839842
"""Full task manager window with tabs, search, sort, and suggested view."""
840843

844+
_bridge_done = pyqtSignal(str)
845+
841846
# Sort modes cycle: priority → due → created → priority ...
842847
_SORT_MODES = ("priority", "due", "created")
843848
_SORT_LABELS = {
@@ -915,8 +920,8 @@ def __init__(self, db, parent=None):
915920
add_action = QAction("+ Add Task", self)
916921
add_action.triggered.connect(self._add_task)
917922
toolbar.addAction(add_action)
918-
refresh_action = QAction("Refresh", self)
919-
refresh_action.triggered.connect(self.refresh)
923+
refresh_action = QAction("Refresh + Sync", self)
924+
refresh_action.triggered.connect(self._refresh_and_sync)
920925
toolbar.addAction(refresh_action)
921926
toolbar.addSeparator()
922927

@@ -940,6 +945,9 @@ def __init__(self, db, parent=None):
940945
self.status = QStatusBar()
941946
self.setStatusBar(self.status)
942947

948+
# Bridge sync signal (thread-safe → main thread)
949+
self._bridge_done.connect(lambda msg: self.status.showMessage(msg, 5000))
950+
943951
# Auto-refresh every 30s
944952
self._refresh_timer = QTimer(self)
945953
self._refresh_timer.timeout.connect(self.refresh)
@@ -955,6 +963,49 @@ def __init__(self, db, parent=None):
955963
def _run_purge(self):
956964
self._last_purged = self.db.purge_old_done(days=30)
957965

966+
# ── Bridge sync ────────────────────────────────────────────────────
967+
968+
_BRIDGE_DIR = os.path.expanduser("~/.claude/memory/bridge")
969+
970+
def _refresh_and_sync(self):
971+
"""Refresh task list then sync memory bridge to GitHub."""
972+
self.refresh()
973+
self._sync_bridge()
974+
975+
def _sync_bridge(self):
976+
"""Git add/commit/push the memory bridge in a background thread."""
977+
if not os.path.isdir(self._BRIDGE_DIR):
978+
self.status.showMessage("Bridge dir not found", 3000)
979+
return
980+
981+
self.status.showMessage("Syncing bridge to GitHub...")
982+
983+
def _do_sync():
984+
try:
985+
subprocess.run(
986+
["git", "add", "-A"],
987+
cwd=self._BRIDGE_DIR, capture_output=True, timeout=10,
988+
)
989+
result = subprocess.run(
990+
["git", "commit", "-m", "bridge: sync from task tray"],
991+
cwd=self._BRIDGE_DIR, capture_output=True, timeout=10,
992+
)
993+
if result.returncode == 0:
994+
subprocess.run(
995+
["git", "push"],
996+
cwd=self._BRIDGE_DIR, capture_output=True, timeout=30,
997+
)
998+
return "Bridge synced to GitHub"
999+
return "Bridge: nothing to sync"
1000+
except Exception as exc:
1001+
return f"Bridge sync error: {exc}"
1002+
1003+
def _run():
1004+
msg = _do_sync()
1005+
self._bridge_done.emit(msg)
1006+
1007+
threading.Thread(target=_run, daemon=True).start()
1008+
9581009
def _sort_tasks(self, tasks):
9591010
"""Sort tasks by current sort mode."""
9601011
mode = self._sort_mode

0 commit comments

Comments
 (0)