repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | import type { Sandbox } from '@cloudflare/sandbox'; |
| #2 | import type { MoltbotEnv } from '../types'; |
| #3 | import { R2_MOUNT_PATH } from '../config'; |
| #4 | import { mountR2Storage } from './r2'; |
| #5 | import { waitForProcess } from './utils'; |
| #6 | |
| #7 | export interface SyncResult { |
| #8 | success: boolean; |
| #9 | lastSync?: string; |
| #10 | error?: string; |
| #11 | details?: string; |
| #12 | } |
| #13 | |
| #14 | /** |
| #15 | * Sync moltbot config from container to R2 for persistence. |
| #16 | * |
| #17 | * This function: |
| #18 | * 1. Mounts R2 if not already mounted |
| #19 | * 2. Verifies source has critical files (prevents overwriting good backup with empty data) |
| #20 | * 3. Runs rsync to copy config to R2 |
| #21 | * 4. Writes a timestamp file for tracking |
| #22 | * |
| #23 | * @param sandbox - The sandbox instance |
| #24 | * @param env - Worker environment bindings |
| #25 | * @returns SyncResult with success status and optional error details |
| #26 | */ |
| #27 | export async function syncToR2(sandbox: Sandbox, env: MoltbotEnv): Promise<SyncResult> { |
| #28 | // Check if R2 is configured |
| #29 | if (!env.R2_ACCESS_KEY_ID || !env.R2_SECRET_ACCESS_KEY || !env.CF_ACCOUNT_ID) { |
| #30 | return { success: false, error: 'R2 storage is not configured' }; |
| #31 | } |
| #32 | |
| #33 | // Mount R2 if not already mounted |
| #34 | const mounted = await mountR2Storage(sandbox, env); |
| #35 | if (!mounted) { |
| #36 | return { success: false, error: 'Failed to mount R2 storage' }; |
| #37 | } |
| #38 | |
| #39 | // Sanity check: verify source has critical files before syncing |
| #40 | // This prevents accidentally overwriting a good backup with empty/corrupted data |
| #41 | try { |
| #42 | const checkProc = await sandbox.startProcess('test -f /root/.clawdbot/clawdbot.json && echo "ok"'); |
| #43 | await waitForProcess(checkProc, 5000); |
| #44 | const checkLogs = await checkProc.getLogs(); |
| #45 | if (!checkLogs.stdout?.includes('ok')) { |
| #46 | return { |
| #47 | success: false, |
| #48 | error: 'Sync aborted: source missing clawdbot.json', |
| #49 | details: 'The local config directory is missing critical files. This could indicate corruption or an incomplete setup.', |
| #50 | }; |
| #51 | } |
| #52 | } catch (err) { |
| #53 | return { |
| #54 | success: false, |
| #55 | error: 'Failed to verify source files', |
| #56 | details: err instanceof Error ? err.message : 'Unknown error', |
| #57 | }; |
| #58 | } |
| #59 | |
| #60 | // Run rsync to backup config to R2 |
| #61 | // Note: Use --no-times because s3fs doesn't support setting timestamps |
| #62 | const syncCmd = `rsync -r --no-times --delete --exclude='*.lock' --exclude='*.log' --exclude='*.tmp' /root/.clawdbot/ ${R2_MOUNT_PATH}/clawdbot/ && rsync -r --no-times --delete /root/clawd/skills/ ${R2_MOUNT_PATH}/skills/ && date -Iseconds > ${R2_MOUNT_PATH}/.last-sync`; |
| #63 | |
| #64 | try { |
| #65 | const proc = await sandbox.startProcess(syncCmd); |
| #66 | await waitForProcess(proc, 30000); // 30 second timeout for sync |
| #67 | |
| #68 | // Check for success by reading the timestamp file |
| #69 | // (process status may not update reliably in sandbox API) |
| #70 | // Note: backup structure is ${R2_MOUNT_PATH}/clawdbot/ and ${R2_MOUNT_PATH}/skills/ |
| #71 | const timestampProc = await sandbox.startProcess(`cat ${R2_MOUNT_PATH}/.last-sync`); |
| #72 | await waitForProcess(timestampProc, 5000); |
| #73 | const timestampLogs = await timestampProc.getLogs(); |
| #74 | const lastSync = timestampLogs.stdout?.trim(); |
| #75 | |
| #76 | if (lastSync && lastSync.match(/^\d{4}-\d{2}-\d{2}/)) { |
| #77 | return { success: true, lastSync }; |
| #78 | } else { |
| #79 | const logs = await proc.getLogs(); |
| #80 | return { |
| #81 | success: false, |
| #82 | error: 'Sync failed', |
| #83 | details: logs.stderr || logs.stdout || 'No timestamp file created', |
| #84 | }; |
| #85 | } |
| #86 | } catch (err) { |
| #87 | return { |
| #88 | success: false, |
| #89 | error: 'Sync error', |
| #90 | details: err instanceof Error ? err.message : 'Unknown error', |
| #91 | }; |
| #92 | } |
| #93 | } |
| #94 |