STATUS board: per-branch STATUS.local.md with central aggregation via drone @prax status sync. Prax handler scans AIPASS_REGISTRY.json and builds collapsible STATUS.md at repo root (14 operational, 1 in-progress). Flow: migrated all 10 DPLAN handler files from Dev-Pass paths to Path(__file__)-based resolution. Fixed FPLAN template detection (is_template_content was deleting plans with real content). Prompts: breadcrumbs philosophy in global prompt, dev.local.md awareness, devpulse branch prompt revised (expertise table, working habits, git hygiene). ai_mail: sender identity fix propagated, email.py handler refactoring. Prax: status sync handler, dashboard command collision fix, central/reader.py. dev.local.md seeded across all 15 branches + spawn template. Gitignore updated (dev.local.md, STATUS.local.md, CLOSED_PLANS.local.json, backup_data). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
80 lines
2.2 KiB
Python
80 lines
2.2 KiB
Python
# =================== AIPass ====================
|
|
# Name: inbox_lock.py
|
|
# Description: Inbox File Lock Handler
|
|
# Version: 1.0.0
|
|
# Created: 2026-02-09
|
|
# Modified: 2026-02-09
|
|
# =============================================
|
|
|
|
"""
|
|
Inbox File Lock Handler
|
|
|
|
Provides exclusive file locking for inbox.json read-modify-write operations.
|
|
Uses fcntl.flock (POSIX advisory locks) to prevent concurrent write corruption.
|
|
|
|
Usage:
|
|
with inbox_lock(inbox_file):
|
|
data = json.load(open(inbox_file, encoding='utf-8'))
|
|
# ... modify data ...
|
|
json.dump(data, open(inbox_file, 'w', encoding='utf-8'))
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from contextlib import contextmanager
|
|
|
|
# fcntl is POSIX-only (Linux/macOS). On Windows, use msvcrt for locking.
|
|
if sys.platform == "win32":
|
|
import msvcrt
|
|
else:
|
|
import fcntl
|
|
|
|
|
|
|
|
@contextmanager
|
|
def inbox_lock(inbox_file: Path):
|
|
"""
|
|
Context manager that acquires an exclusive lock on an inbox.json file.
|
|
|
|
Uses a separate .inbox.lock file adjacent to inbox.json to hold the
|
|
fcntl.flock advisory lock. This avoids issues with truncating the
|
|
locked file itself during writes.
|
|
|
|
Args:
|
|
inbox_file: Path to the inbox.json file to lock
|
|
|
|
Yields:
|
|
None - lock is held for the duration of the with block
|
|
|
|
Raises:
|
|
OSError: If lock cannot be acquired
|
|
"""
|
|
lock_file = inbox_file.parent / ".inbox.lock"
|
|
lock_fd = None
|
|
|
|
try:
|
|
# Create/open lock file
|
|
lock_fd = open(lock_file, 'w', encoding='utf-8')
|
|
|
|
# Acquire exclusive lock (blocking - waits for other processes)
|
|
if sys.platform == "win32":
|
|
msvcrt.locking(lock_fd.fileno(), msvcrt.LK_LOCK, 1)
|
|
else:
|
|
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_EX)
|
|
yield
|
|
|
|
finally:
|
|
if lock_fd is not None:
|
|
try:
|
|
# Release lock
|
|
if sys.platform == "win32":
|
|
msvcrt.locking(lock_fd.fileno(), msvcrt.LK_UNLCK, 1)
|
|
else:
|
|
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_UN)
|
|
lock_fd.close()
|
|
except Exception:
|
|
try:
|
|
lock_fd.close()
|
|
except Exception:
|
|
pass # Best-effort close
|