clawkeep 0.1.0 → 0.2.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/README.md +160 -151
- package/bin/clawkeep.js +17 -0
- package/package.json +2 -2
- package/src/commands/backup.js +21 -5
- package/src/commands/cloud.js +292 -0
- package/src/commands/watch.js +1 -1
- package/src/core/backup.js +49 -13
- package/src/core/credentials.js +66 -0
- package/src/core/s3-client.js +234 -0
- package/src/core/transport.js +160 -3
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
<img src="assets/banner.jpg" alt="ClawKeep" width="100%" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<h1 align="center"
|
|
5
|
+
<h1 align="center">ClawKeep</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<strong>
|
|
9
|
-
<sub>
|
|
8
|
+
<strong>Private, encrypted backups that just work.</strong><br>
|
|
9
|
+
<sub>Zero-knowledge. Time-travel restore. Set it and forget it.</sub>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
@@ -19,23 +19,47 @@
|
|
|
19
19
|
|
|
20
20
|
## The Problem
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Your files are precious. Your AI agent's memory. Your dotfiles. Your configs. Your writing.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
One bad edit. One corrupted file. One accidental delete. Gone.
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Cloud backups? They can read your data. Time Machine? No encryption. Manual exports? You'll forget.
|
|
27
|
+
|
|
28
|
+
**You need backups that are automatic, encrypted, and private.**
|
|
27
29
|
|
|
28
30
|
## The Solution
|
|
29
31
|
|
|
30
|
-
ClawKeep gives
|
|
32
|
+
ClawKeep gives you **continuous, encrypted backups** with full version history. Every change is captured. Every version is recoverable. Everything is **AES-256 encrypted** before it leaves your machine.
|
|
31
33
|
|
|
32
34
|
```
|
|
33
|
-
clawkeep init → start
|
|
34
|
-
clawkeep watch → auto-backup
|
|
35
|
+
clawkeep init → start protecting a directory
|
|
36
|
+
clawkeep watch → auto-backup every change (encrypted)
|
|
35
37
|
clawkeep restore → go back to any point in time
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
Three commands. Your files are protected forever. **Nobody can read them but you.**
|
|
41
|
+
|
|
42
|
+
## 🔐 Privacy First
|
|
43
|
+
|
|
44
|
+
ClawKeep is built on a simple principle: **your data is yours**.
|
|
45
|
+
|
|
46
|
+
- **AES-256-GCM encryption** — Military-grade encryption for all backups
|
|
47
|
+
- **Zero-knowledge** — Your backup target only sees numbered `.enc` chunks
|
|
48
|
+
- **No file names leaked** — Directory structure, file names, everything encrypted
|
|
49
|
+
- **Local-first** — Works entirely offline, no account required
|
|
50
|
+
- **Open source** — Audit the code yourself
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
What your NAS/cloud sees: What's actually inside:
|
|
54
|
+
├── chunk-000001.enc ├── MEMORY.md
|
|
55
|
+
├── chunk-000002.enc ├── config/
|
|
56
|
+
├── manifest.enc │ ├── secrets.yaml
|
|
57
|
+
│ └── api-keys.json
|
|
58
|
+
└── notes/
|
|
59
|
+
└── journal.md
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Your backup target learns nothing.** Not file names, not sizes, not structure. Just opaque encrypted blobs.
|
|
39
63
|
|
|
40
64
|
## Quick Start
|
|
41
65
|
|
|
@@ -44,12 +68,12 @@ npm install -g clawkeep
|
|
|
44
68
|
```
|
|
45
69
|
|
|
46
70
|
```bash
|
|
47
|
-
cd ~/my-
|
|
71
|
+
cd ~/my-important-files
|
|
48
72
|
clawkeep init
|
|
49
73
|
```
|
|
50
74
|
```
|
|
51
75
|
✔ ClawKeep initialized!
|
|
52
|
-
🐾 Directory is now
|
|
76
|
+
🐾 Directory is now protected
|
|
53
77
|
Tracked 42 files
|
|
54
78
|
Backup a8f3c2d1
|
|
55
79
|
```
|
|
@@ -59,54 +83,74 @@ clawkeep init
|
|
|
59
83
|
clawkeep watch --daemon
|
|
60
84
|
```
|
|
61
85
|
|
|
62
|
-
Done. Every file change is now automatically versioned.
|
|
86
|
+
Done. Every file change is now automatically versioned and ready for encrypted backup.
|
|
63
87
|
|
|
64
|
-
##
|
|
88
|
+
## Encrypted Backup Targets
|
|
65
89
|
|
|
66
|
-
|
|
67
|
-
|---|---|
|
|
68
|
-
| `clawkeep init` | Start tracking a directory |
|
|
69
|
-
| `clawkeep watch` | Auto-backup on file changes. `--daemon` for background mode |
|
|
70
|
-
| `clawkeep snap` | Manual backup with optional `-m "message"` |
|
|
71
|
-
| `clawkeep log` | Browse your backup timeline |
|
|
72
|
-
| `clawkeep restore <ref>` | Time-travel to any backup |
|
|
73
|
-
| `clawkeep diff` | See what changed since last backup |
|
|
74
|
-
| `clawkeep backup` | Manage encrypted backup targets (local, S3, cloud) |
|
|
75
|
-
| `clawkeep backup sync` | Sync encrypted backup to target |
|
|
76
|
-
| `clawkeep backup restore` | Restore from encrypted backup |
|
|
77
|
-
| `clawkeep export` | AES-256 encrypted portable archive |
|
|
78
|
-
| `clawkeep import` | Restore from encrypted archive |
|
|
79
|
-
| `clawkeep status` | Show tracking stats |
|
|
80
|
-
| `clawkeep ui` | Launch the web dashboard |
|
|
81
|
-
|
|
82
|
-
## Backup Targets
|
|
83
|
-
|
|
84
|
-
Choose where your data goes. Configure once, sync automatically.
|
|
90
|
+
Send your encrypted backups anywhere. They can't read them anyway.
|
|
85
91
|
|
|
86
92
|
```bash
|
|
87
|
-
# Set encryption password (once)
|
|
93
|
+
# Set your encryption password (once)
|
|
88
94
|
clawkeep backup set-password
|
|
89
95
|
|
|
90
|
-
# Back up to a local path (NAS, external drive,
|
|
96
|
+
# Back up to a local path (NAS, external drive, USB)
|
|
91
97
|
clawkeep backup local /mnt/nas/backups
|
|
92
98
|
|
|
93
|
-
# Sync
|
|
99
|
+
# Sync — only new changes are uploaded
|
|
94
100
|
clawkeep backup sync
|
|
95
101
|
|
|
96
102
|
# Check backup status
|
|
97
103
|
clawkeep backup status
|
|
98
|
-
|
|
99
|
-
# Restore from backup
|
|
100
|
-
clawkeep backup restore /mnt/nas/backups/my-workspace/
|
|
101
104
|
```
|
|
102
105
|
|
|
103
|
-
|
|
106
|
+
Your backup target receives **encrypted chunks only**. No metadata. No history. Nothing useful without your password.
|
|
104
107
|
|
|
105
108
|
| Target | Status | Description |
|
|
106
109
|
|---|---|---|
|
|
107
|
-
| **Local path** | ✅ Available |
|
|
108
|
-
| **S3 / R2** |
|
|
109
|
-
| **ClawKeep Cloud** | 🔜 Coming soon | Managed
|
|
110
|
+
| **Local path** | ✅ Available | Any mounted folder — NAS, USB drive, network share |
|
|
111
|
+
| **S3 / R2** | ✅ Available | Object storage (Cloudflare R2, AWS S3, MinIO, Backblaze B2, Wasabi) |
|
|
112
|
+
| **ClawKeep Cloud** | 🔜 Coming soon | Managed zero-knowledge backup |
|
|
113
|
+
|
|
114
|
+
### S3 / R2 Setup
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Configure S3-compatible target
|
|
118
|
+
clawkeep backup s3 \
|
|
119
|
+
--endpoint https://your-account.r2.cloudflarestorage.com \
|
|
120
|
+
--bucket my-backups \
|
|
121
|
+
--access-key AKIAIOSFODNN7EXAMPLE \
|
|
122
|
+
--secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \
|
|
123
|
+
--region auto \
|
|
124
|
+
--prefix clawkeep/
|
|
125
|
+
|
|
126
|
+
# Or use environment variables for credentials
|
|
127
|
+
export CLAWKEEP_S3_ACCESS_KEY=your-access-key
|
|
128
|
+
export CLAWKEEP_S3_SECRET_KEY=your-secret-key
|
|
129
|
+
clawkeep backup s3 --endpoint https://... --bucket my-backups
|
|
130
|
+
|
|
131
|
+
# Sync encrypted chunks to S3
|
|
132
|
+
clawkeep backup sync
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Works with any S3-compatible service: **Cloudflare R2** (zero egress fees), **AWS S3**, **Backblaze B2**, **MinIO**, **Wasabi**, and more.
|
|
136
|
+
|
|
137
|
+
## Commands
|
|
138
|
+
|
|
139
|
+
| Command | What it does |
|
|
140
|
+
|---|---|
|
|
141
|
+
| `clawkeep init` | Start protecting a directory |
|
|
142
|
+
| `clawkeep watch` | Auto-backup on file changes. `--daemon` for background |
|
|
143
|
+
| `clawkeep snap` | Manual backup with optional `-m "message"` |
|
|
144
|
+
| `clawkeep log` | Browse your backup timeline |
|
|
145
|
+
| `clawkeep restore <ref>` | Time-travel to any backup |
|
|
146
|
+
| `clawkeep diff` | See what changed since last backup |
|
|
147
|
+
| `clawkeep backup` | Manage encrypted backup targets |
|
|
148
|
+
| `clawkeep backup sync` | Push encrypted backup to target |
|
|
149
|
+
| `clawkeep backup restore` | Restore from encrypted backup |
|
|
150
|
+
| `clawkeep export` | Portable encrypted archive |
|
|
151
|
+
| `clawkeep import` | Restore from encrypted archive |
|
|
152
|
+
| `clawkeep status` | Show protection stats |
|
|
153
|
+
| `clawkeep ui` | Launch the web dashboard |
|
|
110
154
|
|
|
111
155
|
## Web Dashboard
|
|
112
156
|
|
|
@@ -118,62 +162,20 @@ clawkeep ui --daemon --port 3333
|
|
|
118
162
|
|
|
119
163
|
**Four tabs, everything you need:**
|
|
120
164
|
|
|
121
|
-
- **◉ Dashboard** — Protection status, recent changes, pending
|
|
122
|
-
- **↻ History** — Full
|
|
123
|
-
- **☁ Backup** — Configure
|
|
124
|
-
- **≡ Browse** — File browser with time-travel — view any file at any point
|
|
165
|
+
- **◉ Dashboard** — Protection status, recent changes, pending files
|
|
166
|
+
- **↻ History** — Full timeline with diffs, compare any two points
|
|
167
|
+
- **☁ Backup** — Configure targets, sync, download encrypted exports
|
|
168
|
+
- **≡ Browse** — File browser with time-travel — view any file at any point
|
|
125
169
|
|
|
126
170
|
**Also includes:**
|
|
127
|
-
- 🎨 Syntax highlighting for
|
|
171
|
+
- 🎨 Syntax highlighting for code files
|
|
128
172
|
- ✏️ Named backups from the UI
|
|
129
173
|
- ⏪ One-click restore to any backup
|
|
130
|
-
- 🔐 Token-based auth
|
|
131
|
-
|
|
132
|
-
## Framework Integrations
|
|
133
|
-
|
|
134
|
-
ClawKeep works with any directory, but it's especially useful for AI agent frameworks that maintain persistent state:
|
|
135
|
-
|
|
136
|
-
| Framework | What to track | How to integrate |
|
|
137
|
-
|---|---|---|
|
|
138
|
-
| **[Clawdbot](https://github.com/clawdbot/clawdbot)** | `MEMORY.md`, `SOUL.md`, `IDENTITY.md`, config, daily notes | Heartbeat task or watch daemon. See [SKILL.md](SKILL.md) |
|
|
139
|
-
| **[OpenClaw](https://github.com/openclaw)** | `.openclaw/` memory, agent state, tool configs | `clawkeep init && clawkeep watch --daemon` in agent dir |
|
|
140
|
-
| **[Nanobot](https://github.com/nicholasgriffintn/nanobot)** | `nanobot.yml`, conversation history, plugins | Watch daemon on nanobot workspace |
|
|
141
|
-
| **[Claude Code](https://claude.ai/code)** | `CLAUDE.md`, project context, session artifacts | `clawkeep watch --daemon` in project root |
|
|
142
|
-
| **[Codex CLI](https://github.com/openai/codex)** | `codex.md`, workspace files | Watch daemon on workspace |
|
|
143
|
-
| **[CrewAI](https://github.com/joaomdmoura/crewAI)** | Agent memory, task outputs, crew configs | Watch daemon on crew workspace |
|
|
144
|
-
| **[AutoGPT](https://github.com/Significant-Gravitas/AutoGPT)** | Agent state, auto_gpt_workspace, memory | Watch daemon on workspace root |
|
|
145
|
-
| **Generic** | Any directory with files that change | `clawkeep init && clawkeep watch --daemon` |
|
|
146
|
-
|
|
147
|
-
### Agent Skill
|
|
148
|
-
|
|
149
|
-
ClawKeep ships with a [SKILL.md](SKILL.md) that any AI agent can read and follow. Drop it into your agent's skills directory and it will know how to:
|
|
150
|
-
|
|
151
|
-
- Initialize ClawKeep on its own workspace
|
|
152
|
-
- Run watch mode or periodic backups via heartbeat
|
|
153
|
-
- Restore to previous versions when something goes wrong
|
|
154
|
-
- Take named backups before risky operations
|
|
155
|
-
- Configure backup targets for offsite protection
|
|
156
|
-
|
|
157
|
-
See [SKILL.md](SKILL.md) for the full agent-readable integration guide.
|
|
158
|
-
|
|
159
|
-
## Smart Ignore
|
|
160
|
-
|
|
161
|
-
ClawKeep ships with sensible defaults. Your `node_modules`, build artifacts, and caches are never tracked:
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
# .clawkeepignore (auto-generated)
|
|
165
|
-
node_modules/
|
|
166
|
-
__pycache__/
|
|
167
|
-
dist/
|
|
168
|
-
.env
|
|
169
|
-
*.log
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
Add your own patterns. They're automatically synced to `.gitignore` — you never think about it.
|
|
174
|
+
- 🔐 Token-based auth
|
|
173
175
|
|
|
174
176
|
## Watch Mode
|
|
175
177
|
|
|
176
|
-
The killer feature.
|
|
178
|
+
The killer feature. Continuous protection without thinking about it:
|
|
177
179
|
|
|
178
180
|
```bash
|
|
179
181
|
# Foreground (see live output)
|
|
@@ -185,15 +187,15 @@ clawkeep watch --daemon
|
|
|
185
187
|
# Stop the daemon
|
|
186
188
|
clawkeep watch --stop
|
|
187
189
|
|
|
188
|
-
# Auto-
|
|
190
|
+
# Auto-sync to backup target after each change
|
|
189
191
|
clawkeep watch --daemon --push
|
|
190
192
|
```
|
|
191
193
|
|
|
192
|
-
|
|
194
|
+
Smart debouncing, stability detection, configurable ignore patterns. Your files are continuously protected.
|
|
193
195
|
|
|
194
|
-
## Restore
|
|
196
|
+
## Time-Travel Restore
|
|
195
197
|
|
|
196
|
-
Go back to any point in time. Your current state is preserved
|
|
198
|
+
Go back to any point in time. Your current state is preserved — nothing is ever lost.
|
|
197
199
|
|
|
198
200
|
```bash
|
|
199
201
|
# See the timeline
|
|
@@ -206,90 +208,97 @@ clawkeep restore abc123f
|
|
|
206
208
|
clawkeep restore HEAD~3
|
|
207
209
|
```
|
|
208
210
|
|
|
209
|
-
Restores are **non-destructive** —
|
|
211
|
+
Restores are **non-destructive** — your full history is always intact.
|
|
210
212
|
|
|
211
|
-
##
|
|
213
|
+
## Portable Encrypted Archives
|
|
212
214
|
|
|
213
|
-
|
|
215
|
+
Take your backups anywhere with encrypted exports:
|
|
214
216
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
```bash
|
|
218
|
+
# Create encrypted archive
|
|
219
|
+
clawkeep export -p "your-password"
|
|
220
|
+
# → my-project.clawkeep.enc
|
|
218
221
|
|
|
219
|
-
|
|
222
|
+
# Restore on another machine
|
|
223
|
+
clawkeep import backup.clawkeep.enc -p "your-password"
|
|
224
|
+
```
|
|
220
225
|
|
|
221
|
-
|
|
226
|
+
One file. Fully encrypted. Restore anywhere.
|
|
222
227
|
|
|
223
|
-
|
|
224
|
-
# One-off encrypted export (portable archive)
|
|
225
|
-
clawkeep export -p "strong-password"
|
|
228
|
+
## Built for AI Agents
|
|
226
229
|
|
|
227
|
-
|
|
228
|
-
clawkeep import backup.clawkeep.enc -p "strong-password"
|
|
229
|
-
```
|
|
230
|
+
ClawKeep was originally built to protect AI agent workspaces — memory files, personality configs, conversation history. One bad inference and your agent's identity is gone.
|
|
230
231
|
|
|
231
|
-
|
|
232
|
+
| Framework | What to protect |
|
|
233
|
+
|---|---|
|
|
234
|
+
| **[Clawdbot](https://github.com/clawdbot/clawdbot)** | `MEMORY.md`, `SOUL.md`, `IDENTITY.md`, daily notes |
|
|
235
|
+
| **[Claude Code](https://claude.ai/code)** | `CLAUDE.md`, project context, artifacts |
|
|
236
|
+
| **[CrewAI](https://github.com/joaomdmoura/crewAI)** | Agent memory, task outputs, crew configs |
|
|
237
|
+
| **[AutoGPT](https://github.com/Significant-Gravitas/AutoGPT)** | Agent state, workspace, memory |
|
|
238
|
+
| **Any agent** | Memory, config, state files |
|
|
232
239
|
|
|
233
|
-
|
|
234
|
-
const { ClawGit } = require('clawkeep');
|
|
240
|
+
ClawKeep ships with a [SKILL.md](SKILL.md) that AI agents can read and follow autonomously.
|
|
235
241
|
|
|
236
|
-
|
|
237
|
-
await claw.init();
|
|
242
|
+
## Works for Everything
|
|
238
243
|
|
|
239
|
-
|
|
240
|
-
const snap = await claw.snap('pre-deploy checkpoint');
|
|
244
|
+
AI agents are the origin story, but ClawKeep protects anything:
|
|
241
245
|
|
|
242
|
-
|
|
243
|
-
|
|
246
|
+
- **Dotfiles** — `~/.config`, shell rc files, SSH configs
|
|
247
|
+
- **Writing** — Manuscripts, notes, journals
|
|
248
|
+
- **Configs** — Server configs, infrastructure as code
|
|
249
|
+
- **Development** — Project files, local databases
|
|
250
|
+
- **Any directory** — If it changes, ClawKeep can protect it
|
|
244
251
|
|
|
245
|
-
|
|
246
|
-
const changes = await claw.diffBetween('abc123', 'def456');
|
|
252
|
+
## Smart Ignore
|
|
247
253
|
|
|
248
|
-
|
|
249
|
-
await claw.restore('abc123');
|
|
254
|
+
Sensible defaults out of the box:
|
|
250
255
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
256
|
+
```bash
|
|
257
|
+
# .clawkeepignore (auto-generated)
|
|
258
|
+
node_modules/
|
|
259
|
+
__pycache__/
|
|
260
|
+
dist/
|
|
261
|
+
.env
|
|
262
|
+
*.log
|
|
254
263
|
```
|
|
255
264
|
|
|
256
|
-
|
|
265
|
+
Add your own patterns. Large files and build artifacts stay out automatically.
|
|
257
266
|
|
|
258
|
-
|
|
267
|
+
## Programmatic API
|
|
259
268
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
- **Writing projects** — every draft saved, every version recoverable
|
|
263
|
-
- **Config management** — track infrastructure config changes over time
|
|
264
|
-
- **Any directory** — if files change, ClawKeep can track them
|
|
269
|
+
```javascript
|
|
270
|
+
const { ClawKeep } = require('clawkeep');
|
|
265
271
|
|
|
266
|
-
|
|
272
|
+
const claw = new ClawKeep('/path/to/project');
|
|
273
|
+
await claw.init();
|
|
267
274
|
|
|
268
|
-
|
|
275
|
+
// Create backup
|
|
276
|
+
const snap = await claw.snap('before risky changes');
|
|
269
277
|
|
|
270
|
-
|
|
278
|
+
// Browse history
|
|
279
|
+
const history = await claw.log(10);
|
|
271
280
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
| Setup | Multiple commands | `clawkeep init` |
|
|
275
|
-
| Auto-backup | DIY cron/hooks | `clawkeep watch --daemon` |
|
|
276
|
-
| Ignore patterns | Manual `.gitignore` | Auto-managed `.clawkeepignore` |
|
|
277
|
-
| Time travel | `git checkout` / `git stash` | `clawkeep restore` |
|
|
278
|
-
| Visual history | External GUI needed | Built-in web dashboard |
|
|
279
|
-
| Backup targets | Manual remote config | `clawkeep backup local /path` (encrypted) |
|
|
280
|
-
| Encrypted export | Not built-in | `clawkeep export` |
|
|
281
|
-
| Learning curve | Steep | Three commands |
|
|
281
|
+
// Restore
|
|
282
|
+
await claw.restore('abc123');
|
|
282
283
|
|
|
283
|
-
|
|
284
|
+
// Time-travel file access
|
|
285
|
+
const oldContent = await claw.showFileAtCommit('abc123', 'config.yaml');
|
|
286
|
+
```
|
|
284
287
|
|
|
285
288
|
## Roadmap
|
|
286
289
|
|
|
287
|
-
- [
|
|
288
|
-
- [ ]
|
|
290
|
+
- [x] S3 / R2 / MinIO backend
|
|
291
|
+
- [ ] `clawkeep.com` — zero-knowledge cloud backup
|
|
292
|
+
- [ ] End-to-end encrypted team sharing
|
|
289
293
|
- [ ] Webhooks on file changes
|
|
290
|
-
- [ ]
|
|
291
|
-
- [ ] Team sharing & access control
|
|
294
|
+
- [ ] Mobile app for backup status
|
|
292
295
|
|
|
293
296
|
## License
|
|
294
297
|
|
|
295
298
|
MIT — [ClawKeep](https://clawkeep.com) 🐾
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
<p align="center">
|
|
303
|
+
<strong>Your files. Your encryption keys. Your privacy.</strong>
|
|
304
|
+
</p>
|
package/bin/clawkeep.js
CHANGED
|
@@ -89,12 +89,29 @@ program
|
|
|
89
89
|
.description('Manage backup target (local, cloud, s3, git)')
|
|
90
90
|
.option('-d, --dir <path>', 'Target directory', '.')
|
|
91
91
|
.option('-p, --password <pass>', 'Encryption password (or CLAWKEEP_PASSWORD env)')
|
|
92
|
+
.option('--endpoint <url>', 'S3 endpoint URL')
|
|
93
|
+
.option('--bucket <name>', 'S3 bucket name')
|
|
94
|
+
.option('--access-key <key>', 'S3 access key ID')
|
|
95
|
+
.option('--secret-key <key>', 'S3 secret access key')
|
|
96
|
+
.option('--region <region>', 'S3 region (default: auto)')
|
|
97
|
+
.option('--prefix <prefix>', 'S3 key prefix')
|
|
92
98
|
.action((subcommand, targetPath, opts) => {
|
|
93
99
|
opts.args = targetPath ? [targetPath] : [];
|
|
94
100
|
opts.path = targetPath;
|
|
95
101
|
require('../src/commands/backup')(subcommand, opts.args, opts);
|
|
96
102
|
});
|
|
97
103
|
|
|
104
|
+
// cloud
|
|
105
|
+
program
|
|
106
|
+
.command('cloud [subcommand]')
|
|
107
|
+
.description('Connect to ClawKeep Cloud')
|
|
108
|
+
.option('-d, --dir <path>', 'Target directory', '.')
|
|
109
|
+
.option('--api-key <key>', 'API key (headless)')
|
|
110
|
+
.option('--workspace <id>', 'Workspace ID (headless)')
|
|
111
|
+
.option('--endpoint <url>', 'API endpoint')
|
|
112
|
+
.option('-p, --password <pass>', 'Encryption password')
|
|
113
|
+
.action((sub, opts) => require('../src/commands/cloud')(sub, opts));
|
|
114
|
+
|
|
98
115
|
// watch
|
|
99
116
|
program
|
|
100
117
|
.command('watch')
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawkeep",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Private, encrypted backups with time-travel restore. Zero-knowledge protection for AI agents, configs, and everything you care about.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"clawkeep": "./bin/clawkeep.js"
|
package/src/commands/backup.js
CHANGED
|
@@ -69,7 +69,7 @@ async function showStatus(bm) {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
// Encryption status
|
|
72
|
-
if (cfg.target === 'local') {
|
|
72
|
+
if (cfg.target === 'local' || cfg.target === 's3' || cfg.target === 'cloud') {
|
|
73
73
|
console.log(` Encrypted: ${cfg.passwordSet ? chalk.green('\u2713 yes') : chalk.yellow('\u26a0 password not set')}`);
|
|
74
74
|
if (cfg.chunkCount > 0) {
|
|
75
75
|
console.log(` Chunks: ${cfg.chunkCount}`);
|
|
@@ -106,6 +106,21 @@ async function setTarget(bm, typeOrArgs, opts) {
|
|
|
106
106
|
process.exit(1);
|
|
107
107
|
}
|
|
108
108
|
options.url = url;
|
|
109
|
+
} else if (type === 's3') {
|
|
110
|
+
const endpoint = opts.endpoint || process.env.CLAWKEEP_S3_ENDPOINT;
|
|
111
|
+
const bucket = opts.bucket || process.env.CLAWKEEP_S3_BUCKET;
|
|
112
|
+
const accessKey = opts.accessKey || process.env.CLAWKEEP_S3_ACCESS_KEY;
|
|
113
|
+
const secretKey = opts.secretKey || process.env.CLAWKEEP_S3_SECRET_KEY;
|
|
114
|
+
const region = opts.region || process.env.CLAWKEEP_S3_REGION || 'auto';
|
|
115
|
+
const prefix = opts.prefix || process.env.CLAWKEEP_S3_PREFIX || '';
|
|
116
|
+
|
|
117
|
+
if (!endpoint || !bucket || !accessKey || !secretKey) {
|
|
118
|
+
console.error(chalk.red(' Missing S3 config. Required: --endpoint, --bucket, --access-key, --secret-key'));
|
|
119
|
+
console.error(chalk.dim(' Or use env vars: CLAWKEEP_S3_ENDPOINT, CLAWKEEP_S3_BUCKET, CLAWKEEP_S3_ACCESS_KEY, CLAWKEEP_S3_SECRET_KEY'));
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
options = { endpoint, bucket, accessKey, secretKey, region, prefix };
|
|
109
124
|
}
|
|
110
125
|
|
|
111
126
|
const spinner = ora('Setting up backup target...').start();
|
|
@@ -123,8 +138,8 @@ async function setTarget(bm, typeOrArgs, opts) {
|
|
|
123
138
|
console.log(` ${chalk.yellow('\u26a0')} ${test.message}`);
|
|
124
139
|
}
|
|
125
140
|
|
|
126
|
-
// Remind about password for
|
|
127
|
-
if (type === 'local' && !bm.hasPassword()) {
|
|
141
|
+
// Remind about password for encrypted targets
|
|
142
|
+
if ((type === 'local' || type === 's3' || type === 'cloud') && !bm.hasPassword()) {
|
|
128
143
|
console.log('');
|
|
129
144
|
console.log(chalk.yellow(' \u26a0 Set a password before syncing:'));
|
|
130
145
|
console.log(chalk.dim(' $ clawkeep backup set-password'));
|
|
@@ -161,9 +176,10 @@ async function doSetPassword(bm, opts) {
|
|
|
161
176
|
|
|
162
177
|
async function doSync(bm, opts) {
|
|
163
178
|
const cfg = bm.getConfig();
|
|
164
|
-
const
|
|
179
|
+
const needsPassword = cfg.target === 'local' || cfg.target === 's3' || cfg.target === 'cloud';
|
|
180
|
+
const password = needsPassword ? getPassword(opts) : null;
|
|
165
181
|
|
|
166
|
-
if (
|
|
182
|
+
if (needsPassword && !password) {
|
|
167
183
|
console.error(chalk.red(' Password required for encrypted sync.'));
|
|
168
184
|
console.error(chalk.dim(' Use: CLAWKEEP_PASSWORD=xxx clawkeep backup sync'));
|
|
169
185
|
process.exit(1);
|