clawkeep 0.2.2 → 0.2.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawkeep",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
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": {
@@ -140,10 +140,11 @@ class BackupManager {
140
140
  if (!target) throw new Error('No backup target configured');
141
141
 
142
142
  let result;
143
+ let transport;
143
144
  if (target === 'local' || target === 's3' || target === 'cloud') {
144
145
  // Encrypted incremental sync (local, S3, or cloud)
145
146
  if (!password) throw new Error('Password required for encrypted sync');
146
- const transport = createTransport(backup, this.claw);
147
+ transport = createTransport(backup, this.claw);
147
148
  const sm = new SyncManager(this.claw, transport, password);
148
149
  result = await sm.sync();
149
150
  } else if (target === 'git') {
@@ -156,6 +157,13 @@ class BackupManager {
156
157
  freshConfig.backup.lastSync = new Date().toISOString();
157
158
  this.claw.saveConfig(freshConfig);
158
159
 
160
+ // Report sync stats to cloud API (fire-and-forget)
161
+ if (target === 'cloud' && transport.reportSync) {
162
+ const chunkCount = freshConfig.backup.chunkCount || result.chunkCount || 0;
163
+ const totalSize = result.totalSize || 0;
164
+ transport.reportSync({ chunkCount, totalSize }).catch(() => {});
165
+ }
166
+
159
167
  return { ...result, lastSync: freshConfig.backup.lastSync };
160
168
  }
161
169
 
@@ -181,6 +181,36 @@ class CloudTransport extends BackupTransport {
181
181
  : now + 3600000;
182
182
  }
183
183
 
184
+ /**
185
+ * Report sync stats to the cloud API (fire-and-forget).
186
+ */
187
+ async reportSync({ chunkCount, totalSize }) {
188
+ const url = `${this.endpoint}/api/workspaces/${this.workspace}/sync-report`;
189
+ const body = JSON.stringify({ chunk_count: chunkCount, storage_bytes: totalSize });
190
+ try {
191
+ await new Promise((resolve, reject) => {
192
+ const parsed = new URL(url);
193
+ const mod = parsed.protocol === 'https:' ? https : http;
194
+ const req = mod.request(url, {
195
+ method: 'POST',
196
+ headers: {
197
+ 'Authorization': 'Bearer ' + this.apiKey,
198
+ 'Content-Type': 'application/json',
199
+ 'Accept': 'application/json',
200
+ },
201
+ }, (res) => {
202
+ res.resume(); // drain response
203
+ res.on('end', resolve);
204
+ });
205
+ req.on('error', reject);
206
+ req.setTimeout(15000, () => req.destroy(new Error('Sync report timeout')));
207
+ req.end(body);
208
+ });
209
+ } catch {
210
+ // Fire-and-forget: don't fail the sync if report fails
211
+ }
212
+ }
213
+
184
214
  async writeFile(remotePath, buffer) {
185
215
  await this._ensureCredentials();
186
216
  return this._inner.writeFile(remotePath, buffer);