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 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">🐾 ClawKeep</h1>
5
+ <h1 align="center">ClawKeep</h1>
6
6
 
7
7
  <p align="center">
8
- <strong>Time-travel backups for AI agents and everything else.</strong><br>
9
- <sub>Every change tracked. Every version recoverable. Set it and forget it.</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
- You're running an AI agent. It rewrites its own memory files, edits configs, updates state. One bad run and your agent's personality is gone. Its memory, corrupted. Its config, overwritten.
22
+ Your files are precious. Your AI agent's memory. Your dotfiles. Your configs. Your writing.
23
23
 
24
- You reach for a backup. All you have is a zip from three days ago.
24
+ One bad edit. One corrupted file. One accidental delete. Gone.
25
25
 
26
- **That's not enough.**
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 your files **full version history with encrypted backups**. Every change is tracked. Every state is recoverable. Back up to a local path, S3, or (soon) ClawKeep Cloud — all encrypted, all incremental. Built on git internally, but you never touch git.
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 tracking
34
- clawkeep watch → auto-backup on every change
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
- That's it. Three commands. Your files are protected forever.
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-project
71
+ cd ~/my-important-files
48
72
  clawkeep init
49
73
  ```
50
74
  ```
51
75
  ✔ ClawKeep initialized!
52
- 🐾 Directory is now version-controlled
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
- ## Commands
88
+ ## Encrypted Backup Targets
65
89
 
66
- | Command | What it does |
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, etc.)
96
+ # Back up to a local path (NAS, external drive, USB)
91
97
  clawkeep backup local /mnt/nas/backups
92
98
 
93
- # Sync (incremental — only new changes)
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
- All backups are **AES-256-GCM encrypted** and **incremental** only new changes are synced after the first backup.
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 | Encrypted chunks on any folder, NAS, or mounted drive |
108
- | **S3 / R2** | 🔜 Coming soon | Encrypted chunks on object storage |
109
- | **ClawKeep Cloud** | 🔜 Coming soon | Managed encrypted backup at clawkeep.com |
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 unsaved files, quick stats
122
- - **↻ History** — Full backup timeline with expandable diffs, compare any two backups side-by-side
123
- - **☁ Backup** — Configure backup targets, sync, test connections, download encrypted exports
124
- - **≡ Browse** — File browser with time-travel — view any file at any point in history
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 JS, Python, Go, Rust, JSON, YAML, CSS, HTML
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, runs as a background daemon
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. Background daemon that auto-backs-up on file changes:
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-push to remote after each backup
190
+ # Auto-sync to backup target after each change
189
191
  clawkeep watch --daemon --push
190
192
  ```
191
193
 
192
- Debounced writes, stability detection, smart ignore patterns. Your files are continuously versioned without any manual intervention.
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 in history — nothing is ever lost.
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** — ClawKeep checks out the old state and creates a new backup. Your full history is always intact.
211
+ Restores are **non-destructive** — your full history is always intact.
210
212
 
211
- ## Compare
213
+ ## Portable Encrypted Archives
212
214
 
213
- See exactly what changed between any two points in time:
215
+ Take your backups anywhere with encrypted exports:
214
216
 
215
- - **Dashboard:** Click "Compare" in History tab, select two backups
216
- - **CLI:** `clawkeep diff` shows changes since last backup
217
- - **API:** `GET /api/compare?from=abc123&to=def456`
217
+ ```bash
218
+ # Create encrypted archive
219
+ clawkeep export -p "your-password"
220
+ # → my-project.clawkeep.enc
218
221
 
219
- ## Encrypted by Default
222
+ # Restore on another machine
223
+ clawkeep import backup.clawkeep.enc -p "your-password"
224
+ ```
220
225
 
221
- All backups are AES-256-GCM encrypted with scrypt key derivation. Your data is opaque on the target — no file names, no git history, nothing readable. Just numbered `.enc` chunks.
226
+ One file. Fully encrypted. Restore anywhere.
222
227
 
223
- ```bash
224
- # One-off encrypted export (portable archive)
225
- clawkeep export -p "strong-password"
228
+ ## Built for AI Agents
226
229
 
227
- # Import from archive
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
- ## Programmatic API
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
- ```javascript
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
- const claw = new ClawGit('/path/to/project');
237
- await claw.init();
242
+ ## Works for Everything
238
243
 
239
- // Backup
240
- const snap = await claw.snap('pre-deploy checkpoint');
244
+ AI agents are the origin story, but ClawKeep protects anything:
241
245
 
242
- // History
243
- const history = await claw.log(10);
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
- // Diff between any two backups
246
- const changes = await claw.diffBetween('abc123', 'def456');
252
+ ## Smart Ignore
247
253
 
248
- // Restore
249
- await claw.restore('abc123');
254
+ Sensible defaults out of the box:
250
255
 
251
- // Time-travel file browsing
252
- const files = await claw.listFilesAtCommit('abc123', 'memory/');
253
- const content = await claw.showFileAtCommit('abc123', 'MEMORY.md');
256
+ ```bash
257
+ # .clawkeepignore (auto-generated)
258
+ node_modules/
259
+ __pycache__/
260
+ dist/
261
+ .env
262
+ *.log
254
263
  ```
255
264
 
256
- ## Built for AI Agents, Works for Everything
265
+ Add your own patterns. Large files and build artifacts stay out automatically.
257
266
 
258
- ClawKeep was built because AI agents break their own files. But it works for anything:
267
+ ## Programmatic API
259
268
 
260
- - **AI agent memory & config** — the original use case
261
- - **Dotfiles** version your shell config without thinking
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
- ## Why Not Just Git?
272
+ const claw = new ClawKeep('/path/to/project');
273
+ await claw.init();
267
274
 
268
- You *could* set up git, write a cron job, handle `.gitignore`, remember to commit, deal with merge conflicts, configure remotes...
275
+ // Create backup
276
+ const snap = await claw.snap('before risky changes');
269
277
 
270
- Or you could run `clawkeep watch --daemon` and never think about it again.
278
+ // Browse history
279
+ const history = await claw.log(10);
271
280
 
272
- | | Raw git | ClawKeep |
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
- ClawKeep *is* git underneath. You get all the power with none of the ceremony.
284
+ // Time-travel file access
285
+ const oldContent = await claw.showFileAtCommit('abc123', 'config.yaml');
286
+ ```
284
287
 
285
288
  ## Roadmap
286
289
 
287
- - [ ] `clawkeep.com` hosted dashboard & remote storage
288
- - [ ] S3/R2 backend support
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
- - [ ] Multi-directory sync
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.1.0",
4
- "description": "Git-backed memory persistence for AI agents. Your agent's memory deserves version control.",
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"
@@ -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 local targets
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 password = cfg.target === 'local' ? getPassword(opts) : null;
179
+ const needsPassword = cfg.target === 'local' || cfg.target === 's3' || cfg.target === 'cloud';
180
+ const password = needsPassword ? getPassword(opts) : null;
165
181
 
166
- if (cfg.target === 'local' && !password) {
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);