anurag008w commited on
Commit
2b5c9d6
·
unverified ·
2 Parent(s): b91e0124e184ba

Merge pull request #14 from anurag162008/codex/investigate-changes-in-openclaw.json-backup

Browse files

Watch and settle openclaw.json before sync; preserve config patching; rotator logs to stderr; env/docs updates

Files changed (3) hide show
  1. .env.example +3 -0
  2. README.md +1 -0
  3. openclaw-sync.py +44 -4
.env.example CHANGED
@@ -288,6 +288,9 @@ SYNC_INTERVAL=180
288
  # Check openclaw.json for settings changes this often (seconds). Default: 1.
289
  OPENCLAW_CONFIG_WATCH_INTERVAL=1
290
 
 
 
 
291
  # Webhooks: Standard POST notifications for lifecycle events
292
  # WEBHOOK_URL=https://your-webhook-endpoint.com/log
293
 
 
288
  # Check openclaw.json for settings changes this often (seconds). Default: 1.
289
  OPENCLAW_CONFIG_WATCH_INTERVAL=1
290
 
291
+ # Wait for openclaw.json to stay valid and unchanged before syncing. Default: 3.
292
+ OPENCLAW_CONFIG_SETTLE_SECONDS=3
293
+
294
  # Webhooks: Standard POST notifications for lifecycle events
295
  # WEBHOOK_URL=https://your-webhook-endpoint.com/log
296
 
README.md CHANGED
@@ -164,6 +164,7 @@ HuggingClaw automatically syncs your workspace (chats, settings, sessions) to a
164
  | `HF_TOKEN` | — | HF token with **Write** access |
165
  | `SYNC_INTERVAL` | `180` | Full backup frequency in seconds |
166
  | `OPENCLAW_CONFIG_WATCH_INTERVAL` | `1` | How often to check `openclaw.json` for immediate settings sync |
 
167
 
168
  ## 📦 Ephemeral Package Re-install *(Optional)*
169
 
 
164
  | `HF_TOKEN` | — | HF token with **Write** access |
165
  | `SYNC_INTERVAL` | `180` | Full backup frequency in seconds |
166
  | `OPENCLAW_CONFIG_WATCH_INTERVAL` | `1` | How often to check `openclaw.json` for immediate settings sync |
167
+ | `OPENCLAW_CONFIG_SETTLE_SECONDS` | `3` | How long `openclaw.json` must stay valid and unchanged before syncing |
168
 
169
  ## 📦 Ephemeral Package Re-install *(Optional)*
170
 
openclaw-sync.py CHANGED
@@ -43,6 +43,10 @@ CONFIG_WATCH_INTERVAL = max(
43
  0.5,
44
  float(os.environ.get("OPENCLAW_CONFIG_WATCH_INTERVAL", "1")),
45
  )
 
 
 
 
46
  HF_TOKEN = os.environ.get("HF_TOKEN", "").strip()
47
  HF_USERNAME = os.environ.get("HF_USERNAME", "").strip()
48
  SPACE_AUTHOR_NAME = os.environ.get("SPACE_AUTHOR_NAME", "").strip()
@@ -440,13 +444,46 @@ def handle_signal(_sig, _frame) -> None:
440
  STOP_EVENT.set()
441
 
442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  def wait_for_sync_trigger(config_marker: tuple[int, int, int]) -> tuple[str, tuple[int, int, int]]:
444
  deadline = time.monotonic() + max(0, INTERVAL)
445
 
446
  while not STOP_EVENT.is_set():
447
  current_config_marker = file_marker(OPENCLAW_CONFIG_FILE)
448
  if current_config_marker != config_marker:
449
- return ("openclaw_config_changed", current_config_marker)
450
 
451
  remaining = deadline - time.monotonic()
452
  if remaining <= 0:
@@ -511,7 +548,10 @@ def loop() -> int:
511
  config_marker = file_marker(OPENCLAW_CONFIG_FILE)
512
 
513
  if config_marker != sync_started_config_marker:
514
- print("OpenClaw config changed during sync; syncing again immediately.")
 
 
 
515
  continue
516
  except Exception as exc:
517
  write_status("error", f"Sync failed: {exc}")
@@ -521,8 +561,8 @@ def loop() -> int:
521
  trigger, config_marker = wait_for_sync_trigger(config_marker)
522
  if trigger == "stopped":
523
  break
524
- if trigger == "openclaw_config_changed":
525
- print("OpenClaw config changed; syncing immediately.")
526
 
527
  return 0
528
 
 
43
  0.5,
44
  float(os.environ.get("OPENCLAW_CONFIG_WATCH_INTERVAL", "1")),
45
  )
46
+ CONFIG_SETTLE_SECONDS = max(
47
+ 0.0,
48
+ float(os.environ.get("OPENCLAW_CONFIG_SETTLE_SECONDS", "3")),
49
+ )
50
  HF_TOKEN = os.environ.get("HF_TOKEN", "").strip()
51
  HF_USERNAME = os.environ.get("HF_USERNAME", "").strip()
52
  SPACE_AUTHOR_NAME = os.environ.get("SPACE_AUTHOR_NAME", "").strip()
 
444
  STOP_EVENT.set()
445
 
446
 
447
+ def is_valid_json_file(path: Path) -> bool:
448
+ if not path.exists():
449
+ return True
450
+
451
+ try:
452
+ json.loads(path.read_text(encoding="utf-8"))
453
+ return True
454
+ except Exception:
455
+ return False
456
+
457
+
458
+ def wait_for_config_settle(config_marker: tuple[int, int, int]) -> tuple[str, tuple[int, int, int]]:
459
+ stable_since = time.monotonic()
460
+ current_marker = config_marker
461
+
462
+ while not STOP_EVENT.is_set():
463
+ latest_marker = file_marker(OPENCLAW_CONFIG_FILE)
464
+ if latest_marker != current_marker:
465
+ current_marker = latest_marker
466
+ stable_since = time.monotonic()
467
+
468
+ if (
469
+ time.monotonic() - stable_since >= CONFIG_SETTLE_SECONDS
470
+ and is_valid_json_file(OPENCLAW_CONFIG_FILE)
471
+ ):
472
+ return ("settled", current_marker)
473
+
474
+ if STOP_EVENT.wait(CONFIG_WATCH_INTERVAL):
475
+ return ("stopped", current_marker)
476
+
477
+ return ("stopped", current_marker)
478
+
479
+
480
  def wait_for_sync_trigger(config_marker: tuple[int, int, int]) -> tuple[str, tuple[int, int, int]]:
481
  deadline = time.monotonic() + max(0, INTERVAL)
482
 
483
  while not STOP_EVENT.is_set():
484
  current_config_marker = file_marker(OPENCLAW_CONFIG_FILE)
485
  if current_config_marker != config_marker:
486
+ return wait_for_config_settle(current_config_marker)
487
 
488
  remaining = deadline - time.monotonic()
489
  if remaining <= 0:
 
548
  config_marker = file_marker(OPENCLAW_CONFIG_FILE)
549
 
550
  if config_marker != sync_started_config_marker:
551
+ trigger, config_marker = wait_for_config_settle(config_marker)
552
+ if trigger == "stopped":
553
+ break
554
+ print("OpenClaw config changed during sync; syncing again after it settled.")
555
  continue
556
  except Exception as exc:
557
  write_status("error", f"Sync failed: {exc}")
 
561
  trigger, config_marker = wait_for_sync_trigger(config_marker)
562
  if trigger == "stopped":
563
  break
564
+ if trigger == "settled":
565
+ print("OpenClaw config changed and settled; syncing immediately.")
566
 
567
  return 0
568