somratpro commited on
Commit
2159e0f
Β·
1 Parent(s): f1b6f7f

refactor: generalize OpenClaw state persistence and add browser warm-up sequence

Browse files
Files changed (2) hide show
  1. start.sh +39 -36
  2. workspace-sync.py +59 -11
start.sh CHANGED
@@ -169,25 +169,19 @@ fi
169
 
170
  # ── Restore persisted OpenClaw state (if present) ──
171
  STATE_BACKUP_ROOT="/home/node/.openclaw/workspace/.huggingclaw-state/openclaw"
172
- restore_state_dir() {
173
- local name="$1"
174
- local source_dir="${STATE_BACKUP_ROOT}/${name}"
175
- local target_dir="/home/node/.openclaw/${name}"
176
-
177
- if [ ! -d "$source_dir" ]; then
178
- return
179
- fi
180
-
181
- echo "🧠 Restoring OpenClaw ${name} state..."
182
- rm -rf "$target_dir"
183
- mkdir -p "$(dirname "$target_dir")"
184
- cp -R "$source_dir" "$target_dir"
185
- echo " βœ… ${name} restored"
186
- }
187
-
188
- restore_state_dir "agents"
189
- restore_state_dir "memory"
190
- restore_state_dir "extensions"
191
 
192
  # ── Restore persisted WhatsApp credentials (if present) ──
193
  WA_BACKUP_DIR="/home/node/.openclaw/workspace/.huggingclaw-state/credentials/whatsapp/default"
@@ -414,23 +408,9 @@ graceful_shutdown() {
414
  echo "πŸ›‘ Shutting down gracefully..."
415
 
416
  if [ -f "/home/node/app/workspace-sync.py" ]; then
417
- echo "🧠 Snapshotting OpenClaw state before exit..."
418
- python3 /home/node/app/workspace-sync.py --snapshot-once 2>/dev/null || \
419
- echo " ⚠️ Could not snapshot OpenClaw state before shutdown"
420
- fi
421
-
422
- # Commit any unsaved workspace changes
423
- if [ -d "/home/node/.openclaw/workspace/.git" ]; then
424
- echo "πŸ’Ύ Saving workspace before exit..."
425
- cd /home/node/.openclaw/workspace
426
- git add -A 2>/dev/null
427
- if ! git diff --cached --quiet 2>/dev/null; then
428
- TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
429
- git commit -m "Shutdown sync ${TIMESTAMP}" 2>/dev/null
430
- git push origin main 2>/dev/null && echo " βœ… Workspace saved!" || echo " ⚠️ Push failed"
431
- else
432
- echo " βœ… No unsaved changes"
433
- fi
434
  fi
435
 
436
  # Kill background processes
@@ -440,6 +420,26 @@ graceful_shutdown() {
440
  }
441
  trap graceful_shutdown SIGTERM SIGINT
442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  # ── Start background services ──
444
  export LLM_MODEL="$LLM_MODEL"
445
  # 10. Start Health Server & Dashboard
@@ -476,6 +476,9 @@ if [ "$WHATSAPP_ENABLED_NORMALIZED" = "true" ]; then
476
  echo "πŸ›‘οΈ WhatsApp Guardian started (PID: $GUARDIAN_PID)"
477
  fi
478
 
 
 
 
479
  # 12. Start Workspace Sync after startup settles
480
  python3 -u /home/node/app/workspace-sync.py &
481
 
 
169
 
170
  # ── Restore persisted OpenClaw state (if present) ──
171
  STATE_BACKUP_ROOT="/home/node/.openclaw/workspace/.huggingclaw-state/openclaw"
172
+ if [ -d "$STATE_BACKUP_ROOT" ]; then
173
+ echo "🧠 Restoring OpenClaw state..."
174
+ for source_path in "$STATE_BACKUP_ROOT"/*; do
175
+ [ -e "$source_path" ] || continue
176
+ name="$(basename "$source_path")"
177
+ target_path="/home/node/.openclaw/${name}"
178
+
179
+ rm -rf "$target_path"
180
+ mkdir -p "$(dirname "$target_path")"
181
+ cp -R "$source_path" "$target_path"
182
+ done
183
+ echo " βœ… OpenClaw state restored"
184
+ fi
 
 
 
 
 
 
185
 
186
  # ── Restore persisted WhatsApp credentials (if present) ──
187
  WA_BACKUP_DIR="/home/node/.openclaw/workspace/.huggingclaw-state/credentials/whatsapp/default"
 
408
  echo "πŸ›‘ Shutting down gracefully..."
409
 
410
  if [ -f "/home/node/app/workspace-sync.py" ]; then
411
+ echo "πŸ’Ύ Saving OpenClaw state before exit..."
412
+ python3 /home/node/app/workspace-sync.py --sync-once || \
413
+ echo " ⚠️ Could not complete shutdown sync"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  fi
415
 
416
  # Kill background processes
 
420
  }
421
  trap graceful_shutdown SIGTERM SIGINT
422
 
423
+ warmup_browser() {
424
+ [ "$BROWSER_SHOULD_ENABLE" = "true" ] || return 0
425
+
426
+ (
427
+ sleep 5
428
+
429
+ local attempt
430
+ for attempt in 1 2 3 4 5; do
431
+ if openclaw browser --browser-profile openclaw start >/dev/null 2>&1; then
432
+ openclaw browser --browser-profile openclaw open about:blank >/dev/null 2>&1 || true
433
+ echo " βœ… Managed browser ready"
434
+ return 0
435
+ fi
436
+ sleep 2
437
+ done
438
+
439
+ echo " ⚠️ Managed browser warm-up did not complete; first browser action may need a retry"
440
+ ) &
441
+ }
442
+
443
  # ── Start background services ──
444
  export LLM_MODEL="$LLM_MODEL"
445
  # 10. Start Health Server & Dashboard
 
476
  echo "πŸ›‘οΈ WhatsApp Guardian started (PID: $GUARDIAN_PID)"
477
  fi
478
 
479
+ # 11.5 Warm up the managed browser so first browser actions have a live tab
480
+ warmup_browser
481
+
482
  # 12. Start Workspace Sync after startup settles
483
  python3 -u /home/node/app/workspace-sync.py &
484
 
workspace-sync.py CHANGED
@@ -19,10 +19,11 @@ OPENCLAW_HOME = Path("/home/node/.openclaw")
19
  WORKSPACE = OPENCLAW_HOME / "workspace"
20
  STATE_DIR = WORKSPACE / ".huggingclaw-state"
21
  OPENCLAW_STATE_BACKUP_DIR = STATE_DIR / "openclaw"
22
- PERSISTED_STATE_PATHS = {
23
- "agents": OPENCLAW_HOME / "agents",
24
- "memory": OPENCLAW_HOME / "memory",
25
- "extensions": OPENCLAW_HOME / "extensions",
 
26
  }
27
  WHATSAPP_CREDS_DIR = Path("/home/node/.openclaw/credentials/whatsapp/default")
28
  WHATSAPP_BACKUP_DIR = STATE_DIR / "credentials" / "whatsapp" / "default"
@@ -61,16 +62,19 @@ def snapshot_state_into_workspace() -> None:
61
  """
62
  try:
63
  STATE_DIR.mkdir(parents=True, exist_ok=True)
 
 
 
64
 
65
- for name, source_path in PERSISTED_STATE_PATHS.items():
66
- if not source_path.exists():
67
  continue
68
 
69
- backup_path = OPENCLAW_STATE_BACKUP_DIR / name
70
- backup_path.parent.mkdir(parents=True, exist_ok=True)
71
- if backup_path.exists():
72
- shutil.rmtree(backup_path, ignore_errors=True)
73
- shutil.copytree(source_path, backup_path)
74
  except Exception as e:
75
  print(f" ⚠️ Could not snapshot OpenClaw state: {e}")
76
 
@@ -211,6 +215,50 @@ def main():
211
  write_sync_status("configured", "State snapshot refreshed during shutdown.")
212
  return
213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  if not WORKSPACE.exists():
215
  print("πŸ“ Workspace sync: workspace not found, exiting.")
216
  return
 
19
  WORKSPACE = OPENCLAW_HOME / "workspace"
20
  STATE_DIR = WORKSPACE / ".huggingclaw-state"
21
  OPENCLAW_STATE_BACKUP_DIR = STATE_DIR / "openclaw"
22
+ EXCLUDED_STATE_NAMES = {
23
+ "workspace",
24
+ "openclaw-app",
25
+ "gateway.log",
26
+ "browser",
27
  }
28
  WHATSAPP_CREDS_DIR = Path("/home/node/.openclaw/credentials/whatsapp/default")
29
  WHATSAPP_BACKUP_DIR = STATE_DIR / "credentials" / "whatsapp" / "default"
 
62
  """
63
  try:
64
  STATE_DIR.mkdir(parents=True, exist_ok=True)
65
+ if OPENCLAW_STATE_BACKUP_DIR.exists():
66
+ shutil.rmtree(OPENCLAW_STATE_BACKUP_DIR, ignore_errors=True)
67
+ OPENCLAW_STATE_BACKUP_DIR.mkdir(parents=True, exist_ok=True)
68
 
69
+ for source_path in OPENCLAW_HOME.iterdir():
70
+ if source_path.name in EXCLUDED_STATE_NAMES:
71
  continue
72
 
73
+ backup_path = OPENCLAW_STATE_BACKUP_DIR / source_path.name
74
+ if source_path.is_dir():
75
+ shutil.copytree(source_path, backup_path)
76
+ elif source_path.is_file():
77
+ shutil.copy2(source_path, backup_path)
78
  except Exception as e:
79
  print(f" ⚠️ Could not snapshot OpenClaw state: {e}")
80
 
 
215
  write_sync_status("configured", "State snapshot refreshed during shutdown.")
216
  return
217
 
218
+ if "--sync-once" in sys.argv:
219
+ if not WORKSPACE.exists():
220
+ print("πŸ“ Workspace sync: workspace not found, exiting.")
221
+ return
222
+
223
+ use_hf_hub = bool(HF_TOKEN and HF_USERNAME)
224
+ git_dir = WORKSPACE / ".git"
225
+
226
+ if not use_hf_hub and not git_dir.exists():
227
+ print("πŸ“ Workspace sync: no git repo and no HF credentials, skipping.")
228
+ return
229
+
230
+ snapshot_state_into_workspace()
231
+
232
+ if not has_changes():
233
+ print("πŸ“ Workspace sync: no changes to persist.")
234
+ write_sync_status("configured", "No new state changes to sync.")
235
+ return
236
+
237
+ ts = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
238
+ write_sync_status("syncing", f"Shutdown sync started at {ts}")
239
+
240
+ if use_hf_hub:
241
+ if sync_with_hf_hub():
242
+ print(f"πŸ”„ Workspace sync (hf_hub): pushed changes ({ts})")
243
+ write_sync_status("success", "Shutdown sync pushed to HF Hub")
244
+ return
245
+ if sync_with_git():
246
+ print(f"πŸ”„ Workspace sync (git fallback): pushed changes ({ts})")
247
+ write_sync_status("success", "Shutdown sync pushed via git fallback")
248
+ return
249
+ write_sync_status("error", "Shutdown sync failed")
250
+ print("πŸ“ Workspace sync: shutdown sync failed.")
251
+ return
252
+
253
+ if sync_with_git():
254
+ print(f"πŸ”„ Workspace sync (git): pushed changes ({ts})")
255
+ write_sync_status("success", "Shutdown sync pushed via git")
256
+ return
257
+
258
+ write_sync_status("error", "Shutdown sync failed")
259
+ print("πŸ“ Workspace sync: shutdown sync failed.")
260
+ return
261
+
262
  if not WORKSPACE.exists():
263
  print("πŸ“ Workspace sync: workspace not found, exiting.")
264
  return