Skip to content

Commit 0207497

Browse files
committed
fix(serena): persist semantic sync acknowledgements
1 parent 2fd560f commit 0207497

3 files changed

Lines changed: 50 additions & 18 deletions

File tree

plugins/rldyour-serena-mcp/scripts/commit_serena_knowledge.sh

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,29 @@ fi
1111
ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
1212
cd "$ROOT"
1313
HEAD_FULL=$(git rev-parse HEAD 2>/dev/null || true)
14+
GIT_COMMON_DIR=$(git rev-parse --git-common-dir 2>/dev/null || true)
15+
if [ -n "$GIT_COMMON_DIR" ] && [[ "$GIT_COMMON_DIR" != /* ]]; then
16+
GIT_COMMON_DIR="$ROOT/$GIT_COMMON_DIR"
17+
fi
1418

1519
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
1620
STATE_SCRIPT="$SCRIPT_DIR/serena_memory_state.py"
1721

1822
KNOWLEDGE_PATTERN='^.. \.serena/(memories|plans|research)(/|$)'
1923
RUNTIME_PATTERN='^.. \.serena/(\.sync_marker|\.serena_sync_state\.json|\.auto_sync_head|\.active_workflow_intent\.json|\.dirty_stop_ack|\.flow_sync_marker|\.flow_post_task_state\.json|\.flow_blocker_ack\.json|\.stop_lifecycle_timeout_marker|\.bootstrap_overrides\.log)$'
2024

25+
write_sync_ack() {
26+
if [ -z "$HEAD_FULL" ]; then
27+
return 0
28+
fi
29+
mkdir -p .serena
30+
printf "%s\n" "$HEAD_FULL" > .serena/.auto_sync_head
31+
if [ -n "$GIT_COMMON_DIR" ]; then
32+
mkdir -p "$GIT_COMMON_DIR/rldyour"
33+
printf "%s\n" "$HEAD_FULL" > "$GIT_COMMON_DIR/rldyour/serena_auto_sync_head"
34+
fi
35+
}
36+
2137
STATUS=$(git status --porcelain -uall 2>/dev/null | grep -vE "$RUNTIME_PATTERN" || true)
2238
if [ -z "$STATUS" ]; then
2339
if [ ! -f "$STATE_SCRIPT" ]; then
@@ -32,10 +48,7 @@ if [ -z "$STATUS" ]; then
3248
MEMORY_CURRENT=$(printf "%s" "$STATE_JSON" | python3 -c 'import json,sys; data=json.load(sys.stdin); print("true" if (data.get("memory_matches_head") or data.get("memory_semantically_current")) else "false")' 2>/dev/null || echo "false")
3349
if [ "$MEMORY_CURRENT" = "true" ]; then
3450
rm -f .serena/.sync_marker .serena/.serena_sync_state.json
35-
if [ -n "$HEAD_FULL" ]; then
36-
mkdir -p .serena
37-
printf "%s\n" "$HEAD_FULL" > .serena/.auto_sync_head
38-
fi
51+
write_sync_ack
3952
echo "Serena knowledge is current; removed runtime sync markers"
4053
exit 0
4154
fi
@@ -86,10 +99,7 @@ if [ -z "$TRACKED_KNOWLEDGE" ]; then
8699
exit 1
87100
fi
88101
rm -f .serena/.sync_marker .serena/.serena_sync_state.json
89-
if [ -n "$HEAD_FULL" ]; then
90-
mkdir -p .serena
91-
printf "%s\n" "$HEAD_FULL" > .serena/.auto_sync_head
92-
fi
102+
write_sync_ack
93103
echo "Serena knowledge is fullrepo-managed; removed runtime sync markers without committing to the current branch"
94104
exit 0
95105
fi
@@ -103,6 +113,4 @@ fi
103113
git commit -m "chore(serena): sync project knowledge after ${HEAD_SHORT}"
104114
HEAD_FULL=$(git rev-parse HEAD 2>/dev/null || true)
105115
rm -f .serena/.sync_marker .serena/.serena_sync_state.json
106-
if [ -n "$HEAD_FULL" ]; then
107-
printf "%s\n" "$HEAD_FULL" > .serena/.auto_sync_head
108-
fi
116+
write_sync_ack

plugins/rldyour-serena-mcp/scripts/serena_memory_state.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
MEMORY_DIR = Path(".serena/memories")
1313
SYNC_STATE = Path(".serena/.serena_sync_state.json")
1414
AUTO_SYNC_HEAD = Path(".serena/.auto_sync_head")
15+
GIT_LOCAL_AUTO_SYNC_HEAD = Path("rldyour/serena_auto_sync_head")
1516
ANALYZE_SCRIPT = Path(__file__).resolve().parent / "analyze_sync_scope.py"
1617
SERENA_KNOWLEDGE_PREFIXES = (
1718
".serena/memories/",
@@ -42,6 +43,17 @@ def _stdout(*args: str) -> str:
4243
return _git(*args).stdout.strip()
4344

4445

46+
def _git_common_dir() -> Path | None:
47+
proc = _git("rev-parse", "--git-common-dir")
48+
if proc.returncode != 0:
49+
return None
50+
value = proc.stdout.strip()
51+
if not value:
52+
return None
53+
path = Path(value)
54+
return path if path.is_absolute() else Path.cwd() / path
55+
56+
4557
def _resolve_commit(ref: str) -> tuple[str, str] | None:
4658
proc = _git("rev-parse", f"{ref}^{{commit}}")
4759
if proc.returncode != 0:
@@ -169,13 +181,20 @@ def _load_sync_state() -> dict[str, Any]:
169181

170182

171183
def _acknowledged_head_matches(head_full: str, head_short: str) -> bool:
172-
if not AUTO_SYNC_HEAD.is_file():
173-
return False
174-
try:
175-
value = AUTO_SYNC_HEAD.read_text(encoding="utf-8").strip()
176-
except OSError:
177-
return False
178-
return bool(value) and value in {head_full, head_short}
184+
candidates = [AUTO_SYNC_HEAD]
185+
git_common_dir = _git_common_dir()
186+
if git_common_dir is not None:
187+
candidates.append(git_common_dir / GIT_LOCAL_AUTO_SYNC_HEAD)
188+
for path in candidates:
189+
if not path.is_file():
190+
continue
191+
try:
192+
value = path.read_text(encoding="utf-8").strip()
193+
except OSError:
194+
continue
195+
if value and value in {head_full, head_short}:
196+
return True
197+
return False
179198

180199

181200
def _memory_candidates(head_short: str) -> tuple[int, bool, list[tuple[str, str]]]:

scripts/smoke_serena_memory_taxonomy.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,13 @@ test "$BEFORE" = "$AFTER" || fail "commit_serena_knowledge created a commit in f
276276
test ! -e .serena/.sync_marker || fail "sync marker was not cleared"
277277
test ! -e .serena/.serena_sync_state.json || fail "sync state was not cleared"
278278
test -e .serena/.auto_sync_head || fail "auto sync acknowledgement was not written"
279+
GIT_COMMON_DIR=$(git rev-parse --git-common-dir)
280+
test -e "$GIT_COMMON_DIR/rldyour/serena_auto_sync_head" || fail "git-local auto sync acknowledgement was not written"
279281
ACK_CURRENT=$(python3 "$STATE_SCRIPT" | python3 -c 'import json,sys; print("true" if json.load(sys.stdin).get("is_current") else "false")')
280282
test "$ACK_CURRENT" = "true" || fail "semantic ancestor acknowledgement did not leave Serena state current"
283+
rm -f .serena/.auto_sync_head
284+
ACKLESS_CURRENT=$(python3 "$STATE_SCRIPT" | python3 -c 'import json,sys; print("true" if json.load(sys.stdin).get("is_current") else "false")')
285+
test "$ACKLESS_CURRENT" = "true" || fail "semantic ancestor state depended on worktree runtime acknowledgement marker"
281286

282287
STALE_REPO="$TMP_ROOT/stale"
283288
mkdir "$STALE_REPO"

0 commit comments

Comments
 (0)