openclaw-config-guardian 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 OpenClaw Config Guardian Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,198 @@
1
+ <div align="center">
2
+
3
+ <img width="120" src="https://img.shields.io/badge/🛡️-Config_Guardian-blue?style=for-the-badge" alt="Config Guardian" />
4
+
5
+ # OpenClaw Config Guardian
6
+
7
+ **Auto backup & one-click rollback for OpenClaw configuration.**
8
+
9
+ [![npm version](https://img.shields.io/npm/v/@openclaw/config-guardian.svg)](https://www.npmjs.com/package/@openclaw/config-guardian)
10
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
11
+ [![Node.js](https://img.shields.io/badge/Node.js->=18-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
12
+
13
+ </div>
14
+
15
+ ---
16
+
17
+ ## ✨ Features
18
+
19
+ | Feature | Description |
20
+ |---------|-------------|
21
+ | 🔄 **Auto Backup** | Automatic daily backups at 2:00 AM (only when OpenClaw is healthy) |
22
+ | 🌐 **Web UI** | Beautiful web interface to manage backups |
23
+ | ⚡ **One-Click Rollback** | Restore to any backup point instantly |
24
+ | 🏥 **Health Check** | Verifies OpenClaw status before backup |
25
+ | 🧹 **Auto Cleanup** | Keeps only the latest N backups automatically |
26
+ | 🖥️ **CLI Support** | Full command-line interface |
27
+
28
+ ---
29
+
30
+ ## 🚀 Quick Start
31
+
32
+ ### Option 1: npx (No Installation)
33
+
34
+ ```bash
35
+ # Check status
36
+ npx @openclaw/config-guardian status
37
+
38
+ # Create backup
39
+ npx @openclaw/config-guardian backup
40
+
41
+ # Start Web UI
42
+ npx @openclaw/config-guardian webui
43
+ ```
44
+
45
+ ### Option 2: Global Install
46
+
47
+ ```bash
48
+ # Install globally
49
+ npm install -g @openclaw/config-guardian
50
+
51
+ # Use shorthand
52
+ ocg status
53
+ ocg backup
54
+ ocg webui
55
+ ```
56
+
57
+ ### Option 3: One-Line Install Script
58
+
59
+ ```bash
60
+ curl -fsSL https://raw.githubusercontent.com/openclaw/config-guardian/main/scripts/install.sh | bash
61
+ ```
62
+
63
+ ---
64
+
65
+ ## 📖 Usage
66
+
67
+ ### CLI Commands
68
+
69
+ ```bash
70
+ # View status
71
+ openclaw-config-guardian status
72
+
73
+ # Create backup immediately
74
+ openclaw-config-guardian backup
75
+
76
+ # List all backups
77
+ openclaw-config-guardian list
78
+
79
+ # Restore to specific backup
80
+ openclaw-config-guardian restore backup-2024-01-01T00-00-00-000Z
81
+
82
+ # Delete a backup
83
+ openclaw-config-guardian delete backup-2024-01-01T00-00-00-000Z
84
+
85
+ # Start Web UI
86
+ openclaw-config-guardian webui
87
+
88
+ # Show help
89
+ openclaw-config-guardian help
90
+ ```
91
+
92
+ ### Web UI
93
+
94
+ Start the Web UI and open http://localhost:3456:
95
+
96
+ ```bash
97
+ openclaw-config-guardian webui
98
+ ```
99
+
100
+ Features:
101
+ - Toggle auto backup on/off
102
+ - View system status
103
+ - Create backups with one click
104
+ - Restore to any backup point
105
+ - Delete old backups
106
+
107
+ ---
108
+
109
+ ## ⚙️ Configuration
110
+
111
+ Edit `~/.openclaw/extensions/openclaw-config-guardian/config.json`:
112
+
113
+ ```json
114
+ {
115
+ "autoBackup": true,
116
+ "maxBackups": 10,
117
+ "webUIPort": 3456,
118
+ "backupItems": [
119
+ "config.json",
120
+ "gateway.json",
121
+ "agents.json",
122
+ "skills.json",
123
+ "memory",
124
+ "workspace"
125
+ ]
126
+ }
127
+ ```
128
+
129
+ | Option | Description | Default |
130
+ |--------|-------------|---------|
131
+ | `autoBackup` | Enable automatic daily backups | `true` |
132
+ | `maxBackups` | Maximum backups to keep | `10` |
133
+ | `webUIPort` | Port for Web UI | `3456` |
134
+ | `backupItems` | Files/directories to backup | See above |
135
+
136
+ ---
137
+
138
+ ## 📦 What's Backed Up
139
+
140
+ By default, the following are backed up:
141
+
142
+ - `config.json` - Main configuration
143
+ - `gateway.json` - Gateway configuration
144
+ - `agents.json` - Agents configuration
145
+ - `skills.json` - Skills configuration
146
+ - `memory/` - Memory files
147
+ - `workspace/` - Workspace files
148
+
149
+ ---
150
+
151
+ ## 🔒 Safety Features
152
+
153
+ - **Emergency Backup**: Before rollback, current config is backed up
154
+ - **Health Check**: Only backs up when OpenClaw is running normally
155
+ - **Auto Cleanup**: Old backups are automatically deleted
156
+ - **Safe Restore**: Stops Gateway before restore, restarts after
157
+
158
+ ---
159
+
160
+ ## 🛠️ Development
161
+
162
+ ```bash
163
+ # Clone the repo
164
+ git clone https://github.com/openclaw/config-guardian.git
165
+ cd config-guardian
166
+
167
+ # Install dependencies
168
+ npm install
169
+
170
+ # Build
171
+ npm run build
172
+
173
+ # Local install
174
+ npm install -g .
175
+
176
+ # Or use local script
177
+ bash scripts/install.sh --local
178
+ ```
179
+
180
+ ---
181
+
182
+ ## 🤝 Contributing
183
+
184
+ Contributions are welcome! Please feel free to submit a Pull Request.
185
+
186
+ ---
187
+
188
+ ## 📄 License
189
+
190
+ MIT License - see [LICENSE](LICENSE) file for details.
191
+
192
+ ---
193
+
194
+ <div align="center">
195
+
196
+ Made with ❤️ for the OpenClaw community
197
+
198
+ </div>
package/bin/cli.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import('../dist/cli.js');
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,136 @@
1
+ import { getConfig, createBackup, listBackups, restoreBackup, deleteBackup, checkOpenClawHealth } from './core.js';
2
+ function printUsage() {
3
+ console.log(`
4
+ 🛡️ OpenClaw Config Guardian
5
+ =============================
6
+
7
+ Usage: openclaw-config-guardian <command> [options]
8
+
9
+ Commands:
10
+ install Install the plugin
11
+ uninstall Uninstall the plugin
12
+ status Show current status
13
+ backup Create a backup immediately
14
+ restore <backup-id> Restore to a specific backup
15
+ delete <backup-id> Delete a specific backup
16
+ list List all backups
17
+ webui [port] Start Web UI (default port: 3456)
18
+ config Show current configuration
19
+ help Show this help message
20
+
21
+ Examples:
22
+ openclaw-config-guardian backup
23
+ openclaw-config-guardian restore backup-2024-01-01T00-00-00-000Z
24
+ openclaw-config-guardian webui 8080
25
+ `);
26
+ }
27
+ function showStatus() {
28
+ const config = getConfig();
29
+ const backups = listBackups();
30
+ console.log('\n📊 Config Guardian 状态');
31
+ console.log('======================');
32
+ console.log('自动备份:', config.autoBackup ? '✅ 开启' : '❌ 关闭');
33
+ console.log('最大备份数:', config.maxBackups);
34
+ console.log('Web UI 端口:', config.webUIPort);
35
+ console.log('上次备份:', config.lastBackup || '无');
36
+ console.log('备份数量:', backups.length);
37
+ console.log('OpenClaw 状态:', checkOpenClawHealth() ? '🟢 运行中' : '🔴 未运行');
38
+ if (backups.length > 0) {
39
+ console.log('\n最近备份:');
40
+ backups.slice(0, 5).forEach(b => {
41
+ console.log(` • ${b.id} (${new Date(b.timestamp).toLocaleString()})`);
42
+ });
43
+ }
44
+ console.log();
45
+ }
46
+ function showConfig() {
47
+ const config = getConfig();
48
+ console.log('\n⚙️ 当前配置');
49
+ console.log('=============');
50
+ console.log(JSON.stringify(config, null, 2));
51
+ console.log();
52
+ }
53
+ function showList() {
54
+ const backups = listBackups();
55
+ if (backups.length === 0) {
56
+ console.log('\n📭 暂无备份\n');
57
+ return;
58
+ }
59
+ console.log('\n📦 备份列表');
60
+ console.log('===========');
61
+ backups.forEach((b, i) => {
62
+ console.log(`${i + 1}. ${b.id}`);
63
+ console.log(` 时间: ${new Date(b.timestamp).toLocaleString()}`);
64
+ console.log(` 项目: ${b.items.join(', ')}`);
65
+ console.log();
66
+ });
67
+ }
68
+ async function main() {
69
+ const args = process.argv.slice(2);
70
+ const command = args[0];
71
+ switch (command) {
72
+ case 'install':
73
+ console.log('✅ 插件已安装!');
74
+ console.log('🌐 启动 Web UI: openclaw-config-guardian webui');
75
+ console.log('📊 查看状态: openclaw-config-guardian status');
76
+ break;
77
+ case 'uninstall':
78
+ console.log('🗑️ 插件已卸载');
79
+ break;
80
+ case 'status':
81
+ showStatus();
82
+ break;
83
+ case 'config':
84
+ showConfig();
85
+ break;
86
+ case 'backup':
87
+ console.log('💾 执行手动备份...');
88
+ const result = createBackup();
89
+ if (!result.success) {
90
+ process.exit(1);
91
+ }
92
+ break;
93
+ case 'restore':
94
+ const backupId = args[1];
95
+ if (!backupId) {
96
+ console.error('❌ 请指定备份 ID');
97
+ console.log('用法: openclaw-config-guardian restore <backup-id>');
98
+ showList();
99
+ process.exit(1);
100
+ }
101
+ restoreBackup(backupId);
102
+ break;
103
+ case 'delete':
104
+ const deleteId = args[1];
105
+ if (!deleteId) {
106
+ console.error('❌ 请指定备份 ID');
107
+ console.log('用法: openclaw-config-guardian delete <backup-id>');
108
+ process.exit(1);
109
+ }
110
+ const deleteResult = deleteBackup(deleteId);
111
+ if (!deleteResult.success) {
112
+ console.error('❌ 删除失败:', deleteResult.error);
113
+ process.exit(1);
114
+ }
115
+ break;
116
+ case 'list':
117
+ showList();
118
+ break;
119
+ case 'webui':
120
+ const port = args[1] ? parseInt(args[1]) : undefined;
121
+ const { startWebUI } = await import('./webui.js');
122
+ startWebUI(port);
123
+ break;
124
+ case 'help':
125
+ case '--help':
126
+ case '-h':
127
+ default:
128
+ printUsage();
129
+ break;
130
+ }
131
+ }
132
+ main().catch(err => {
133
+ console.error('❌ 错误:', err);
134
+ process.exit(1);
135
+ });
136
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/core.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ export interface BackupConfig {
2
+ autoBackup: boolean;
3
+ maxBackups: number;
4
+ webUIPort: number;
5
+ backupItems: string[];
6
+ lastBackup?: string;
7
+ }
8
+ export interface BackupMeta {
9
+ timestamp: string;
10
+ version: string;
11
+ items: string[];
12
+ }
13
+ export interface BackupInfo {
14
+ id: string;
15
+ timestamp: string;
16
+ items: string[];
17
+ }
18
+ export declare function getConfig(): BackupConfig;
19
+ export declare function saveConfig(config: BackupConfig): void;
20
+ export declare function checkOpenClawHealth(): boolean;
21
+ export declare function createBackup(): {
22
+ success: boolean;
23
+ backupId?: string;
24
+ error?: string;
25
+ };
26
+ export declare function cleanupOldBackups(maxBackups?: number): void;
27
+ export declare function listBackups(): BackupInfo[];
28
+ export declare function restoreBackup(backupId: string): {
29
+ success: boolean;
30
+ error?: string;
31
+ };
32
+ export declare function deleteBackup(backupId: string): {
33
+ success: boolean;
34
+ error?: string;
35
+ };
36
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,SAAS,IAAI,YAAY,CAYxC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAGrD;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAO7C;AAED,wBAAgB,YAAY,IAAI;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAgEtF;AAED,wBAAgB,iBAAiB,CAAC,UAAU,GAAE,MAAW,GAAG,IAAI,CAkB/D;AAED,wBAAgB,WAAW,IAAI,UAAU,EAAE,CAoB1C;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA6EpF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAenF"}
package/dist/core.js ADDED
@@ -0,0 +1,228 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { execSync } from 'child_process';
4
+ import { fileURLToPath } from 'url';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ const PLUGIN_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '', '.openclaw', 'extensions', 'openclaw-config-guardian');
8
+ const CONFIG_FILE = path.join(PLUGIN_DIR, 'config.json');
9
+ const BACKUPS_DIR = path.join(PLUGIN_DIR, 'backups');
10
+ const OPENCLAW_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '', '.openclaw');
11
+ // 默认配置
12
+ const DEFAULT_BACKUP_ITEMS = [
13
+ 'config.json',
14
+ 'gateway.json',
15
+ 'agents.json',
16
+ 'skills.json',
17
+ 'memory',
18
+ 'workspace'
19
+ ];
20
+ export function getConfig() {
21
+ if (!fs.existsSync(CONFIG_FILE)) {
22
+ const defaultConfig = {
23
+ autoBackup: true,
24
+ maxBackups: 10,
25
+ webUIPort: 3456,
26
+ backupItems: DEFAULT_BACKUP_ITEMS
27
+ };
28
+ saveConfig(defaultConfig);
29
+ return defaultConfig;
30
+ }
31
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
32
+ }
33
+ export function saveConfig(config) {
34
+ fs.mkdirSync(PLUGIN_DIR, { recursive: true });
35
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
36
+ }
37
+ export function checkOpenClawHealth() {
38
+ try {
39
+ const result = execSync('openclaw gateway status', { encoding: 'utf8', timeout: 10000 });
40
+ return result.includes('running') || result.includes('active');
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ }
46
+ export function createBackup() {
47
+ const config = getConfig();
48
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
49
+ const backupId = `backup-${timestamp}`;
50
+ const backupDir = path.join(BACKUPS_DIR, backupId);
51
+ console.log(`[${new Date().toLocaleString()}] 开始备份...`);
52
+ // 检查 OpenClaw 健康状态
53
+ if (!checkOpenClawHealth()) {
54
+ console.log('⚠️ OpenClaw 状态异常,跳过本次备份');
55
+ return { success: false, error: 'OpenClaw is not running' };
56
+ }
57
+ try {
58
+ fs.mkdirSync(backupDir, { recursive: true });
59
+ // 备份元数据
60
+ const meta = {
61
+ timestamp: new Date().toISOString(),
62
+ version: '1.0.0',
63
+ items: []
64
+ };
65
+ // 备份各项
66
+ for (const item of config.backupItems) {
67
+ const sourcePath = path.join(OPENCLAW_DIR, item);
68
+ const destPath = path.join(backupDir, item);
69
+ if (fs.existsSync(sourcePath)) {
70
+ const stat = fs.statSync(sourcePath);
71
+ if (stat.isDirectory()) {
72
+ fs.cpSync(sourcePath, destPath, { recursive: true });
73
+ }
74
+ else {
75
+ fs.copyFileSync(sourcePath, destPath);
76
+ }
77
+ meta.items.push(item);
78
+ console.log(` ✓ ${item}`);
79
+ }
80
+ else {
81
+ console.log(` ⚠ ${item} (不存在)`);
82
+ }
83
+ }
84
+ // 保存元数据
85
+ fs.writeFileSync(path.join(backupDir, 'meta.json'), JSON.stringify(meta, null, 2));
86
+ // 更新配置
87
+ config.lastBackup = timestamp;
88
+ saveConfig(config);
89
+ // 清理旧备份
90
+ cleanupOldBackups(config.maxBackups);
91
+ console.log(`✅ 备份完成: ${backupId}`);
92
+ return { success: true, backupId };
93
+ }
94
+ catch (err) {
95
+ const error = err instanceof Error ? err.message : String(err);
96
+ console.error('❌ 备份失败:', error);
97
+ // 清理失败的备份
98
+ if (fs.existsSync(backupDir)) {
99
+ fs.rmSync(backupDir, { recursive: true });
100
+ }
101
+ return { success: false, error };
102
+ }
103
+ }
104
+ export function cleanupOldBackups(maxBackups = 10) {
105
+ if (!fs.existsSync(BACKUPS_DIR))
106
+ return;
107
+ const backups = fs.readdirSync(BACKUPS_DIR)
108
+ .filter(d => d.startsWith('backup-'))
109
+ .map(d => ({
110
+ name: d,
111
+ path: path.join(BACKUPS_DIR, d),
112
+ time: fs.statSync(path.join(BACKUPS_DIR, d)).mtime.getTime()
113
+ }))
114
+ .sort((a, b) => b.time - a.time);
115
+ // 保留最近 N 个
116
+ const toDelete = backups.slice(maxBackups);
117
+ for (const backup of toDelete) {
118
+ fs.rmSync(backup.path, { recursive: true });
119
+ console.log(`🗑️ 清理旧备份: ${backup.name}`);
120
+ }
121
+ }
122
+ export function listBackups() {
123
+ if (!fs.existsSync(BACKUPS_DIR)) {
124
+ return [];
125
+ }
126
+ return fs.readdirSync(BACKUPS_DIR)
127
+ .filter(d => d.startsWith('backup-'))
128
+ .map(d => {
129
+ const metaPath = path.join(BACKUPS_DIR, d, 'meta.json');
130
+ let meta = {};
131
+ if (fs.existsSync(metaPath)) {
132
+ meta = JSON.parse(fs.readFileSync(metaPath, 'utf8'));
133
+ }
134
+ return {
135
+ id: d,
136
+ timestamp: meta.timestamp || d.replace('backup-', ''),
137
+ items: meta.items || []
138
+ };
139
+ })
140
+ .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
141
+ }
142
+ export function restoreBackup(backupId) {
143
+ const backupDir = path.join(BACKUPS_DIR, backupId);
144
+ if (!fs.existsSync(backupDir)) {
145
+ console.error(`❌ 备份不存在: ${backupId}`);
146
+ return { success: false, error: `Backup not found: ${backupId}` };
147
+ }
148
+ console.log(`🔄 准备回滚到: ${backupId}`);
149
+ console.log('⚠️ 这将覆盖当前配置,请确认...');
150
+ try {
151
+ // 先创建当前配置的紧急备份
152
+ const emergencyBackup = path.join(BACKUPS_DIR, `emergency-${Date.now()}`);
153
+ fs.mkdirSync(emergencyBackup, { recursive: true });
154
+ const items = ['config.json', 'gateway.json', 'agents.json', 'skills.json'];
155
+ for (const item of items) {
156
+ const sourcePath = path.join(OPENCLAW_DIR, item);
157
+ if (fs.existsSync(sourcePath)) {
158
+ fs.copyFileSync(sourcePath, path.join(emergencyBackup, item));
159
+ }
160
+ }
161
+ console.log(`📦 已创建紧急备份: ${path.basename(emergencyBackup)}`);
162
+ // 停止 gateway
163
+ console.log('🛑 停止 OpenClaw Gateway...');
164
+ try {
165
+ execSync('openclaw gateway stop', { timeout: 30000 });
166
+ }
167
+ catch {
168
+ console.log(' ⚠️ gateway 可能未运行');
169
+ }
170
+ // 恢复备份
171
+ console.log('📂 恢复配置文件中...');
172
+ const metaPath = path.join(backupDir, 'meta.json');
173
+ const meta = fs.existsSync(metaPath)
174
+ ? JSON.parse(fs.readFileSync(metaPath, 'utf8'))
175
+ : { items: [], timestamp: '', version: '' };
176
+ for (const item of meta.items || []) {
177
+ const sourcePath = path.join(backupDir, item);
178
+ const destPath = path.join(OPENCLAW_DIR, item);
179
+ if (fs.existsSync(sourcePath)) {
180
+ // 删除现有文件/目录
181
+ if (fs.existsSync(destPath)) {
182
+ fs.rmSync(destPath, { recursive: true });
183
+ }
184
+ // 复制备份
185
+ const stat = fs.statSync(sourcePath);
186
+ if (stat.isDirectory()) {
187
+ fs.cpSync(sourcePath, destPath, { recursive: true });
188
+ }
189
+ else {
190
+ fs.copyFileSync(sourcePath, destPath);
191
+ }
192
+ console.log(` ✓ ${item}`);
193
+ }
194
+ }
195
+ // 启动 gateway
196
+ console.log('🚀 启动 OpenClaw Gateway...');
197
+ try {
198
+ execSync('openclaw gateway start', { timeout: 30000 });
199
+ console.log('✅ Gateway 已启动');
200
+ }
201
+ catch {
202
+ console.error('❌ 启动失败,请手动检查');
203
+ }
204
+ console.log('✅ 回滚完成!');
205
+ return { success: true };
206
+ }
207
+ catch (err) {
208
+ const error = err instanceof Error ? err.message : String(err);
209
+ console.error('❌ 回滚失败:', error);
210
+ return { success: false, error };
211
+ }
212
+ }
213
+ export function deleteBackup(backupId) {
214
+ const backupDir = path.join(BACKUPS_DIR, backupId);
215
+ if (!fs.existsSync(backupDir)) {
216
+ return { success: false, error: `Backup not found: ${backupId}` };
217
+ }
218
+ try {
219
+ fs.rmSync(backupDir, { recursive: true });
220
+ console.log(`🗑️ 已删除备份: ${backupId}`);
221
+ return { success: true };
222
+ }
223
+ catch (err) {
224
+ const error = err instanceof Error ? err.message : String(err);
225
+ return { success: false, error };
226
+ }
227
+ }
228
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function startAutoBackup(): void;
2
+ export declare function stopAutoBackup(): void;
3
+ export declare function init(): void;
4
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAOA,wBAAgB,eAAe,IAAI,IAAI,CAYtC;AAED,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAED,wBAAgB,IAAI,IAAI,IAAI,CAmB3B"}
package/dist/daemon.js ADDED
@@ -0,0 +1,42 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import cron from 'node-cron';
4
+ import { getConfig, createBackup } from './core.js';
5
+ let backupJob = null;
6
+ export function startAutoBackup() {
7
+ if (backupJob) {
8
+ backupJob.stop();
9
+ }
10
+ // 每24小时执行一次(每天凌晨2点)
11
+ backupJob = cron.schedule('0 2 * * *', () => {
12
+ console.log('[定时任务] 执行自动备份...');
13
+ createBackup();
14
+ });
15
+ console.log('✅ 自动备份已启用(每天凌晨2点)');
16
+ }
17
+ export function stopAutoBackup() {
18
+ if (backupJob) {
19
+ backupJob.stop();
20
+ backupJob = null;
21
+ }
22
+ console.log('⏹️ 自动备份已停止');
23
+ }
24
+ export function init() {
25
+ const config = getConfig();
26
+ if (config.autoBackup) {
27
+ startAutoBackup();
28
+ }
29
+ // 监听配置变化
30
+ const PLUGIN_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '', '.openclaw', 'extensions', 'openclaw-config-guardian');
31
+ const CONFIG_FILE = path.join(PLUGIN_DIR, 'config.json');
32
+ fs.watchFile(CONFIG_FILE, () => {
33
+ const newConfig = getConfig();
34
+ if (newConfig.autoBackup && !backupJob) {
35
+ startAutoBackup();
36
+ }
37
+ else if (!newConfig.autoBackup && backupJob) {
38
+ stopAutoBackup();
39
+ }
40
+ });
41
+ }
42
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAc,YAAY,EAAE,MAAM,WAAW,CAAC;AAEhE,IAAI,SAAS,GAA8B,IAAI,CAAC;AAEhD,MAAM,UAAU,eAAe;IAC7B,IAAI,SAAS,EAAE,CAAC;QACd,SAAS,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;IAED,oBAAoB;IACpB,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QAC1C,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChC,YAAY,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,IAAI,SAAS,EAAE,CAAC;QACd,SAAS,CAAC,IAAI,EAAE,CAAC;QACjB,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,eAAe,EAAE,CAAC;IACpB,CAAC;IAED,SAAS;IACT,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,0BAA0B,CAAC,CAAC;IACvI,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAEzD,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,GAAG,EAAE;QAC7B,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC;QAC9B,IAAI,SAAS,CAAC,UAAU,IAAI,CAAC,SAAS,EAAE,CAAC;YACvC,eAAe,EAAE,CAAC;QACpB,CAAC;aAAM,IAAI,CAAC,SAAS,CAAC,UAAU,IAAI,SAAS,EAAE,CAAC;YAC9C,cAAc,EAAE,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { init } from './daemon.js';
2
+ export * from './core.js';
3
+ export * from './webui.js';
4
+ export * from './daemon.js';
5
+ declare const _default: {
6
+ init: typeof init;
7
+ };
8
+ export default _default;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGnC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;;;;AAG5B,wBAAwB"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import { init } from './daemon.js';
2
+ // 导出主要功能
3
+ export * from './core.js';
4
+ export * from './webui.js';
5
+ export * from './daemon.js';
6
+ // 默认导出
7
+ export default { init };
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,SAAS;AACT,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAE5B,OAAO;AACP,eAAe,EAAE,IAAI,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function startWebUI(port?: number): void;
2
+ //# sourceMappingURL=webui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webui.d.ts","sourceRoot":"","sources":["../src/webui.ts"],"names":[],"mappings":"AA2EA,wBAAgB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ9C"}
package/dist/webui.js ADDED
@@ -0,0 +1,77 @@
1
+ import express from 'express';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { getConfig, saveConfig, createBackup, listBackups, restoreBackup, deleteBackup, checkOpenClawHealth } from './core.js';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ const app = express();
8
+ app.use(express.json());
9
+ // 静态文件服务
10
+ const webuiPath = path.join(__dirname, '..', 'webui');
11
+ app.use(express.static(webuiPath));
12
+ // API 路由
13
+ // 获取配置
14
+ app.get('/api/config', (req, res) => {
15
+ res.json(getConfig());
16
+ });
17
+ // 更新配置
18
+ app.post('/api/config', (req, res) => {
19
+ const config = getConfig();
20
+ if (req.body.autoBackup !== undefined) {
21
+ config.autoBackup = req.body.autoBackup;
22
+ }
23
+ if (req.body.maxBackups !== undefined) {
24
+ config.maxBackups = req.body.maxBackups;
25
+ }
26
+ if (req.body.webUIPort !== undefined) {
27
+ config.webUIPort = req.body.webUIPort;
28
+ }
29
+ if (req.body.backupItems !== undefined) {
30
+ config.backupItems = req.body.backupItems;
31
+ }
32
+ saveConfig(config);
33
+ res.json({ success: true, config });
34
+ });
35
+ // 获取备份列表
36
+ app.get('/api/backups', (req, res) => {
37
+ res.json(listBackups());
38
+ });
39
+ // 立即备份
40
+ app.post('/api/backup', async (req, res) => {
41
+ const result = createBackup();
42
+ res.json(result);
43
+ });
44
+ // 回滚备份
45
+ app.post('/api/restore/:id', (req, res) => {
46
+ const backupId = req.params.id;
47
+ const result = restoreBackup(backupId);
48
+ res.json(result);
49
+ });
50
+ // 删除备份
51
+ app.delete('/api/backups/:id', (req, res) => {
52
+ const backupId = req.params.id;
53
+ const result = deleteBackup(backupId);
54
+ res.json(result);
55
+ });
56
+ // 获取 OpenClaw 状态
57
+ app.get('/api/status', (req, res) => {
58
+ res.json({
59
+ gateway: checkOpenClawHealth() ? 'running' : 'stopped',
60
+ config: getConfig()
61
+ });
62
+ });
63
+ // 启动服务器
64
+ export function startWebUI(port) {
65
+ const config = getConfig();
66
+ const actualPort = port || config.webUIPort || 3456;
67
+ app.listen(actualPort, () => {
68
+ console.log(`🌐 Config Guardian Web UI 已启动`);
69
+ console.log(`📍 访问地址: http://localhost:${actualPort}`);
70
+ });
71
+ }
72
+ // 如果是直接运行
73
+ if (import.meta.url === `file://${process.argv[1]}`) {
74
+ const port = process.argv[2] ? parseInt(process.argv[2]) : undefined;
75
+ startWebUI(port);
76
+ }
77
+ //# sourceMappingURL=webui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webui.js","sourceRoot":"","sources":["../src/webui.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ {
2
+ "id": "openclaw-config-guardian",
3
+ "name": "OpenClaw Config Guardian",
4
+ "description": "Auto backup & one-click rollback for OpenClaw configuration. Protect your configs with scheduled backups and easy restore via Web UI or CLI.",
5
+ "channels": [],
6
+ "extensions": [],
7
+ "skills": ["skills/config-guardian"],
8
+ "capabilities": {
9
+ "proactiveMessaging": false,
10
+ "cronJobs": true
11
+ },
12
+ "configSchema": {
13
+ "type": "object",
14
+ "additionalProperties": false,
15
+ "properties": {
16
+ "autoBackup": {
17
+ "type": "boolean",
18
+ "default": true,
19
+ "description": "Enable automatic daily backups at 2:00 AM"
20
+ },
21
+ "maxBackups": {
22
+ "type": "number",
23
+ "default": 10,
24
+ "description": "Maximum number of backups to keep (old ones auto-deleted)"
25
+ },
26
+ "webUIPort": {
27
+ "type": "number",
28
+ "default": 3456,
29
+ "description": "Port for the Web UI"
30
+ },
31
+ "backupItems": {
32
+ "type": "array",
33
+ "items": { "type": "string" },
34
+ "default": ["config.json", "gateway.json", "agents.json", "skills.json", "memory", "workspace"],
35
+ "description": "Files and directories to backup"
36
+ }
37
+ }
38
+ }
39
+ }
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "openclaw-config-guardian",
3
+ "version": "1.0.0",
4
+ "description": "OpenClaw Config Guardian - Auto backup & one-click rollback for OpenClaw configuration",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "openclaw-config-guardian": "bin/cli.js",
10
+ "ocg": "bin/cli.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "bin",
15
+ "scripts",
16
+ "skills",
17
+ "openclaw.plugin.json",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "openclaw": {
22
+ "id": "openclaw-config-guardian",
23
+ "extensions": [],
24
+ "skills": [
25
+ "skills/config-guardian"
26
+ ]
27
+ },
28
+ "scripts": {
29
+ "build": "tsc",
30
+ "dev": "tsc --watch",
31
+ "prepack": "npm run build",
32
+ "postinstall": "node scripts/postinstall.js",
33
+ "test": "echo \"No tests yet\""
34
+ },
35
+ "keywords": [
36
+ "openclaw",
37
+ "openclaw-plugin",
38
+ "backup",
39
+ "config",
40
+ "guardian",
41
+ "rollback",
42
+ "restore"
43
+ ],
44
+ "author": "dingclaw",
45
+ "license": "MIT",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/openclaw/config-guardian.git"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/openclaw/config-guardian/issues"
52
+ },
53
+ "homepage": "https://github.com/openclaw/config-guardian#readme",
54
+ "engines": {
55
+ "node": ">=18.0.0"
56
+ },
57
+ "dependencies": {
58
+ "express": "^4.18.2",
59
+ "node-cron": "^3.0.3"
60
+ },
61
+ "devDependencies": {
62
+ "@types/express": "^4.17.21",
63
+ "@types/node": "^20.0.0",
64
+ "@types/node-cron": "^3.0.11",
65
+ "typescript": "^5.9.3"
66
+ },
67
+ "peerDependencies": {
68
+ "openclaw": ">=1.0.0"
69
+ }
70
+ }
@@ -0,0 +1,89 @@
1
+ #!/bin/bash
2
+
3
+ # OpenClaw Config Guardian 一键安装脚本
4
+ # 支持: npm install, npx, curl | bash
5
+
6
+ set -e
7
+
8
+ echo "🛡️ OpenClaw Config Guardian 安装器"
9
+ echo "======================================"
10
+
11
+ # 颜色定义
12
+ RED='\033[0;31m'
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ NC='\033[0m' # No Color
16
+
17
+ # 检查 Node.js
18
+ if ! command -v node &> /dev/null; then
19
+ echo -e "${RED}❌ 未检测到 Node.js,请先安装 Node.js 18+${NC}"
20
+ echo " 访问: https://nodejs.org/"
21
+ exit 1
22
+ fi
23
+
24
+ NODE_VERSION=$(node --version | cut -d'v' -f2 | cut -d'.' -f1)
25
+ if [ "$NODE_VERSION" -lt 18 ]; then
26
+ echo -e "${RED}❌ Node.js 版本过低,需要 18+,当前: $(node --version)${NC}"
27
+ exit 1
28
+ fi
29
+
30
+ echo -e "${GREEN}✓ Node.js $(node --version)${NC}"
31
+
32
+ # 检查 npm
33
+ if ! command -v npm &> /dev/null; then
34
+ echo -e "${RED}❌ 未检测到 npm${NC}"
35
+ exit 1
36
+ fi
37
+
38
+ echo -e "${GREEN}✓ npm $(npm --version)${NC}"
39
+
40
+ # 检查 OpenClaw
41
+ if ! command -v openclaw &> /dev/null; then
42
+ echo -e "${YELLOW}⚠️ 未检测到 OpenClaw CLI${NC}"
43
+ echo " 插件仍可安装,但部分功能需要 OpenClaw"
44
+ else
45
+ echo -e "${GREEN}✓ OpenClaw 已安装${NC}"
46
+ fi
47
+
48
+ echo ""
49
+ echo "📦 正在安装 @openclaw/config-guardian..."
50
+ echo ""
51
+
52
+ # 安装方式选择
53
+ if [ "$1" == "--local" ] || [ "$1" == "-l" ]; then
54
+ # 本地开发安装
55
+ echo "🔧 本地开发模式"
56
+ npm install -g .
57
+ else
58
+ # 从 npm 安装
59
+ npm install -g @openclaw/config-guardian@latest
60
+ fi
61
+
62
+ echo ""
63
+ echo -e "${GREEN}✅ 安装完成!${NC}"
64
+ echo ""
65
+ echo "使用方法:"
66
+ echo ""
67
+ echo " 命令行:"
68
+ echo " ocg status - 查看状态"
69
+ echo " ocg backup - 立即备份"
70
+ echo " ocg restore <id> - 回滚到指定备份"
71
+ echo " ocg list - 列出所有备份"
72
+ echo " ocg webui - 启动 Web UI"
73
+ echo " ocg help - 显示帮助"
74
+ echo ""
75
+ echo " npx 方式 (无需全局安装):"
76
+ echo " npx @openclaw/config-guardian status"
77
+ echo " npx @openclaw/config-guardian webui"
78
+ echo ""
79
+ echo "🌐 Web UI 默认地址: http://localhost:3456"
80
+ echo ""
81
+ echo "配置文件: ~/.openclaw/extensions/openclaw-config-guardian/config.json"
82
+ echo ""
83
+
84
+ # 提示启动 Web UI
85
+ read -p "是否立即启动 Web UI? (y/N): " -n 1 -r
86
+ echo
87
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
88
+ ocg webui
89
+ fi
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { execSync } from 'child_process';
6
+ import { fileURLToPath } from 'url';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ const PLUGIN_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '', '.openclaw', 'extensions', 'openclaw-config-guardian');
12
+
13
+ console.log('🛡️ OpenClaw Config Guardian 安装后配置...');
14
+
15
+ try {
16
+ // 创建插件目录
17
+ fs.mkdirSync(PLUGIN_DIR, { recursive: true });
18
+
19
+ // 创建备份目录
20
+ fs.mkdirSync(path.join(PLUGIN_DIR, 'backups'), { recursive: true });
21
+
22
+ // 创建默认配置
23
+ const configPath = path.join(PLUGIN_DIR, 'config.json');
24
+ if (!fs.existsSync(configPath)) {
25
+ const defaultConfig = {
26
+ autoBackup: true,
27
+ maxBackups: 10,
28
+ webUIPort: 3456,
29
+ backupItems: [
30
+ 'config.json',
31
+ 'gateway.json',
32
+ 'agents.json',
33
+ 'skills.json',
34
+ 'memory',
35
+ 'workspace'
36
+ ]
37
+ };
38
+ fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
39
+ console.log('✅ 默认配置已创建');
40
+ }
41
+
42
+ console.log('');
43
+ console.log('🎉 安装完成!');
44
+ console.log('');
45
+ console.log('快速开始:');
46
+ console.log(' npx openclaw-config-guardian status - 查看状态');
47
+ console.log(' npx openclaw-config-guardian backup - 立即备份');
48
+ console.log(' npx openclaw-config-guardian webui - 启动 Web UI');
49
+ console.log('');
50
+ console.log('或使用简写:');
51
+ console.log(' ocg status');
52
+ console.log(' ocg backup');
53
+ console.log(' ocg webui');
54
+ console.log('');
55
+ console.log('🌐 Web UI 地址: http://localhost:3456');
56
+ console.log('');
57
+ } catch (err) {
58
+ console.error('❌ 配置失败:', err.message);
59
+ process.exit(1);
60
+ }
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: config-guardian
3
+ description: OpenClaw 配置守护者 - 自动备份与一键回滚。支持定时备份、Web UI 管理、命令行操作。
4
+ metadata: {"openclaw":{"emoji":"🛡️","requires":{"config":["config-guardian"]}}}
5
+ ---
6
+
7
+ # Config Guardian 技能
8
+
9
+ ## 功能
10
+
11
+ - 🔄 **自动备份**: 每天凌晨 2 点自动备份配置
12
+ - 🌐 **Web UI**: 图形界面管理备份
13
+ - ⚡ **一键回滚**: 快速恢复到任意备份点
14
+ - 🏥 **健康检测**: 备份前自动检查 OpenClaw 状态
15
+ - 🧹 **自动清理**: 保留最近 N 个备份,自动删除旧备份
16
+
17
+ ## 使用方式
18
+
19
+ ### 1. Web UI(推荐)
20
+
21
+ ```bash
22
+ openclaw config-guardian webui
23
+ ```
24
+
25
+ 访问 http://localhost:3456
26
+
27
+ ### 2. 命令行
28
+
29
+ ```bash
30
+ # 查看状态
31
+ openclaw config-guardian status
32
+
33
+ # 立即备份
34
+ openclaw config-guardian backup
35
+
36
+ # 回滚到指定备份
37
+ openclaw config-guardian restore <backup-id>
38
+
39
+ # 列出所有备份
40
+ openclaw config-guardian list
41
+ ```
42
+
43
+ ### 3. 配置
44
+
45
+ 编辑 `~/.openclaw/config.json`:
46
+
47
+ ```json
48
+ {
49
+ "config-guardian": {
50
+ "autoBackup": true,
51
+ "maxBackups": 10,
52
+ "webUIPort": 3456,
53
+ "backupItems": [
54
+ "config.json",
55
+ "gateway.json",
56
+ "agents.json",
57
+ "skills.json",
58
+ "memory",
59
+ "workspace"
60
+ ]
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## 备份内容
66
+
67
+ 默认备份以下文件和目录:
68
+ - `config.json` - 主配置
69
+ - `gateway.json` - 网关配置
70
+ - `agents.json` - 代理配置
71
+ - `skills.json` - 技能配置
72
+ - `memory/` - 记忆文件
73
+ - `workspace/` - 工作空间
74
+
75
+ ## API 接口
76
+
77
+ Web UI 提供以下 REST API:
78
+
79
+ | 接口 | 方法 | 说明 |
80
+ |------|------|------|
81
+ | `/api/config` | GET/POST | 获取/更新配置 |
82
+ | `/api/backups` | GET | 获取备份列表 |
83
+ | `/api/backup` | POST | 立即执行备份 |
84
+ | `/api/restore/:id` | POST | 回滚到指定备份 |
85
+ | `/api/status` | GET | 获取 OpenClaw 状态 |
86
+
87
+ ## 安全说明
88
+
89
+ - 回滚前会自动创建紧急备份
90
+ - 仅在 OpenClaw 运行正常时执行备份
91
+ - 备份文件存储在本地,不会上传云端