crewly 1.11.4 → 1.11.6
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/dist/backend/backend/src/constants.d.ts +22 -1
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +22 -1
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/services/backup/backup-archive.service.d.ts +90 -0
- package/dist/backend/backend/src/services/backup/backup-archive.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/backup/backup-archive.service.js +309 -0
- package/dist/backend/backend/src/services/backup/backup-archive.service.js.map +1 -0
- package/dist/backend/backend/src/services/backup/backup-cloud.client.d.ts +75 -0
- package/dist/backend/backend/src/services/backup/backup-cloud.client.d.ts.map +1 -0
- package/dist/backend/backend/src/services/backup/backup-cloud.client.js +134 -0
- package/dist/backend/backend/src/services/backup/backup-cloud.client.js.map +1 -0
- package/dist/backend/backend/src/services/backup/backup-restore.service.d.ts +78 -0
- package/dist/backend/backend/src/services/backup/backup-restore.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/backup/backup-restore.service.js +358 -0
- package/dist/backend/backend/src/services/backup/backup-restore.service.js.map +1 -0
- package/dist/backend/backend/src/services/backup/backup.types.d.ts +163 -0
- package/dist/backend/backend/src/services/backup/backup.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/backup/backup.types.js +13 -0
- package/dist/backend/backend/src/services/backup/backup.types.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-sync.service.d.ts +29 -2
- package/dist/backend/backend/src/services/cloud/cloud-sync.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.service.js +97 -13
- package/dist/backend/backend/src/services/cloud/cloud-sync.service.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +22 -1
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +22 -1
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/controllers/cloud/cloud-google-auth.controller.d.ts +70 -0
- package/dist/cli/backend/src/controllers/cloud/cloud-google-auth.controller.d.ts.map +1 -0
- package/dist/cli/backend/src/controllers/cloud/cloud-google-auth.controller.js +427 -0
- package/dist/cli/backend/src/controllers/cloud/cloud-google-auth.controller.js.map +1 -0
- package/dist/cli/backend/src/services/backup/backup-archive.service.d.ts +90 -0
- package/dist/cli/backend/src/services/backup/backup-archive.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/backup/backup-archive.service.js +309 -0
- package/dist/cli/backend/src/services/backup/backup-archive.service.js.map +1 -0
- package/dist/cli/backend/src/services/backup/backup-cloud.client.d.ts +75 -0
- package/dist/cli/backend/src/services/backup/backup-cloud.client.d.ts.map +1 -0
- package/dist/cli/backend/src/services/backup/backup-cloud.client.js +134 -0
- package/dist/cli/backend/src/services/backup/backup-cloud.client.js.map +1 -0
- package/dist/cli/backend/src/services/backup/backup-restore.service.d.ts +78 -0
- package/dist/cli/backend/src/services/backup/backup-restore.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/backup/backup-restore.service.js +358 -0
- package/dist/cli/backend/src/services/backup/backup-restore.service.js.map +1 -0
- package/dist/cli/backend/src/services/backup/backup.types.d.ts +163 -0
- package/dist/cli/backend/src/services/backup/backup.types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/backup/backup.types.js +13 -0
- package/dist/cli/backend/src/services/backup/backup.types.js.map +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts +410 -0
- package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-client.service.js +863 -0
- package/dist/cli/backend/src/services/cloud/cloud-client.service.js.map +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.service.d.ts +292 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.service.js +1093 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.service.js.map +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts +328 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js +171 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js.map +1 -0
- package/dist/cli/backend/src/services/cloud/device-identity.service.d.ts +89 -0
- package/dist/cli/backend/src/services/cloud/device-identity.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/cloud/device-identity.service.js +148 -0
- package/dist/cli/backend/src/services/cloud/device-identity.service.js.map +1 -0
- package/dist/cli/backend/src/services/user/user-identity.service.d.ts +86 -0
- package/dist/cli/backend/src/services/user/user-identity.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/user/user-identity.service.js +190 -0
- package/dist/cli/backend/src/services/user/user-identity.service.js.map +1 -0
- package/dist/cli/cli/src/commands/backup.d.ts +31 -0
- package/dist/cli/cli/src/commands/backup.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/backup.js +280 -0
- package/dist/cli/cli/src/commands/backup.js.map +1 -0
- package/dist/cli/cli/src/index.js +10 -0
- package/dist/cli/cli/src/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup Archive Service (P0)
|
|
3
|
+
*
|
|
4
|
+
* Builds a portable workspace backup: a single `.tar.gz` containing a
|
|
5
|
+
* top-level `manifest.json`, the captured `CREWLY_HOME` globals (under
|
|
6
|
+
* `home/`), each project's `.crewly/` tree (under `projects/<id>/`), and
|
|
7
|
+
* optionally `chat.db`.
|
|
8
|
+
*
|
|
9
|
+
* Runs locally with no Cloud dependency — `crewly backup create`. The Cloud
|
|
10
|
+
* upload/park step (Pro-gated) is a later phase and consumes the archive this
|
|
11
|
+
* service produces. See specs/2026-06-07-workspace-backup.md.
|
|
12
|
+
*
|
|
13
|
+
* @module services/backup/backup-archive.service
|
|
14
|
+
*/
|
|
15
|
+
import { createHash } from 'node:crypto';
|
|
16
|
+
import { createReadStream } from 'node:fs';
|
|
17
|
+
import * as fs from 'node:fs/promises';
|
|
18
|
+
import * as os from 'node:os';
|
|
19
|
+
import * as path from 'node:path';
|
|
20
|
+
import { execFile } from 'node:child_process';
|
|
21
|
+
import { promisify } from 'node:util';
|
|
22
|
+
import { create as tarCreate } from 'tar';
|
|
23
|
+
import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
|
|
24
|
+
import { safeReadJson } from '../../utils/file-io.utils.js';
|
|
25
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
26
|
+
import { BACKUP_SCHEMA_VERSION, } from './backup.types.js';
|
|
27
|
+
const execFileAsync = promisify(execFile);
|
|
28
|
+
/**
|
|
29
|
+
* Top-level CREWLY_HOME entries that are MACHINE-SPECIFIC, secret, runtime, or
|
|
30
|
+
* would cause recursion — never captured. chat.db is handled separately via
|
|
31
|
+
* the SQLite online backup API, so it's excluded from the generic file walk.
|
|
32
|
+
*/
|
|
33
|
+
const GLOBAL_EXCLUDE_TOPLEVEL = new Set([
|
|
34
|
+
'device.json',
|
|
35
|
+
'cloud',
|
|
36
|
+
'credentials',
|
|
37
|
+
'telegram-credentials.json',
|
|
38
|
+
'runtime.json',
|
|
39
|
+
'.orchestrator-state',
|
|
40
|
+
'session-state.json',
|
|
41
|
+
'logs',
|
|
42
|
+
'teams-backup.json',
|
|
43
|
+
'teams-backup-history',
|
|
44
|
+
'backups', // our own output dir
|
|
45
|
+
'chat.db',
|
|
46
|
+
'chat.db-wal',
|
|
47
|
+
'chat.db-shm',
|
|
48
|
+
]);
|
|
49
|
+
/** Directory names excluded at ANY depth (runtime/session/log noise). */
|
|
50
|
+
const EXCLUDE_DIR_ANYWHERE = new Set(['sessions', 'logs', '.orchestrator-state']);
|
|
51
|
+
/** True for files excluded at any depth (ephemeral session logs). */
|
|
52
|
+
function isExcludedFile(name) {
|
|
53
|
+
return name.endsWith('.jsonl');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Service that builds workspace backup archives.
|
|
57
|
+
*/
|
|
58
|
+
export class BackupArchiveService {
|
|
59
|
+
logger;
|
|
60
|
+
constructor(logger) {
|
|
61
|
+
this.logger = logger ?? LoggerService.getInstance().createComponentLogger('BackupArchive');
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Build a workspace backup archive.
|
|
65
|
+
*
|
|
66
|
+
* Captures CREWLY_HOME globals (exclude-based, so new data domains are
|
|
67
|
+
* picked up automatically), each project's `.crewly/` tree (walked from
|
|
68
|
+
* projects.json) with git provenance, and chat.db (unless excluded). Stages
|
|
69
|
+
* everything into a temp dir, writes the manifest, and tars it to `outPath`.
|
|
70
|
+
*
|
|
71
|
+
* @param options - Build options (createdAt is required — no clock in lib code)
|
|
72
|
+
* @returns The archive path, manifest, and total captured bytes
|
|
73
|
+
* @throws If CREWLY_HOME does not exist or the tar write fails
|
|
74
|
+
*/
|
|
75
|
+
async createArchive(options) {
|
|
76
|
+
const home = options.homePath ?? getCrewlyHomePath();
|
|
77
|
+
const homeStat = await fs.stat(home).catch(() => null);
|
|
78
|
+
if (!homeStat?.isDirectory()) {
|
|
79
|
+
throw new Error(`CREWLY_HOME not found or not a directory: ${home}`);
|
|
80
|
+
}
|
|
81
|
+
const outPath = options.outPath ??
|
|
82
|
+
path.join(home, 'backups', `workspace-${options.createdAt.replace(/[:.]/g, '-')}.tar.gz`);
|
|
83
|
+
const staging = await fs.mkdtemp(path.join(os.tmpdir(), 'crewly-backup-'));
|
|
84
|
+
try {
|
|
85
|
+
let totalBytes = 0;
|
|
86
|
+
// 1) Global CREWLY_HOME files → staging/home/<rel>
|
|
87
|
+
const global = [];
|
|
88
|
+
for (const rel of await this.collectGlobalFiles(home)) {
|
|
89
|
+
const entry = await this.stageFile(home, rel, staging, path.join('home', rel));
|
|
90
|
+
global.push(entry);
|
|
91
|
+
totalBytes += entry.bytes;
|
|
92
|
+
}
|
|
93
|
+
// 2) Per-project .crewly trees → staging/projects/<id>/<rel>
|
|
94
|
+
const projects = await this.collectProjects(home, staging);
|
|
95
|
+
for (const p of projects)
|
|
96
|
+
for (const f of p.files)
|
|
97
|
+
totalBytes += f.bytes;
|
|
98
|
+
// 3) chat.db via SQLite online backup → staging/chat.db
|
|
99
|
+
const chatDb = options.excludeChatDb
|
|
100
|
+
? { included: false, skippedReason: 'excluded by option' }
|
|
101
|
+
: await this.captureChatDb(home, staging);
|
|
102
|
+
if (chatDb.bytes)
|
|
103
|
+
totalBytes += chatDb.bytes;
|
|
104
|
+
// 4) Manifest
|
|
105
|
+
const manifest = {
|
|
106
|
+
schemaVersion: BACKUP_SCHEMA_VERSION,
|
|
107
|
+
crewlyVersion: this.readCrewlyVersion(),
|
|
108
|
+
createdAt: options.createdAt,
|
|
109
|
+
sourceDeviceId: options.sourceDeviceId ?? null,
|
|
110
|
+
sourceDeviceName: options.sourceDeviceName ?? null,
|
|
111
|
+
sourceHomePath: home,
|
|
112
|
+
ownerSub: options.ownerSub ?? null,
|
|
113
|
+
global,
|
|
114
|
+
projects,
|
|
115
|
+
chatDb,
|
|
116
|
+
crypto: { mode: 'none' },
|
|
117
|
+
};
|
|
118
|
+
await fs.writeFile(path.join(staging, 'manifest.json'), JSON.stringify(manifest, null, 2), 'utf8');
|
|
119
|
+
// 5) tar.gz the staging dir
|
|
120
|
+
await fs.mkdir(path.dirname(outPath), { recursive: true });
|
|
121
|
+
await tarCreate({ gzip: true, file: outPath, cwd: staging }, ['.']);
|
|
122
|
+
this.logger.info('Workspace backup created', {
|
|
123
|
+
outPath,
|
|
124
|
+
globalFiles: global.length,
|
|
125
|
+
projects: projects.length,
|
|
126
|
+
chatDb: chatDb.included,
|
|
127
|
+
totalBytes,
|
|
128
|
+
});
|
|
129
|
+
return { archivePath: outPath, manifest, totalBytes };
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
await fs.rm(staging, { recursive: true, force: true }).catch(() => undefined);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Recursively collect capturable global files under CREWLY_HOME (relative
|
|
137
|
+
* paths). Exclude-based so new data domains are captured automatically.
|
|
138
|
+
*
|
|
139
|
+
* @param home - CREWLY_HOME absolute path
|
|
140
|
+
* @returns Relative file paths (POSIX-style) to capture
|
|
141
|
+
*/
|
|
142
|
+
async collectGlobalFiles(home) {
|
|
143
|
+
const out = [];
|
|
144
|
+
const walk = async (absDir, rel, isTop) => {
|
|
145
|
+
const entries = await fs.readdir(absDir, { withFileTypes: true }).catch(() => []);
|
|
146
|
+
for (const e of entries) {
|
|
147
|
+
if (isTop && GLOBAL_EXCLUDE_TOPLEVEL.has(e.name))
|
|
148
|
+
continue;
|
|
149
|
+
if (e.isDirectory() && EXCLUDE_DIR_ANYWHERE.has(e.name))
|
|
150
|
+
continue;
|
|
151
|
+
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
152
|
+
if (e.isDirectory()) {
|
|
153
|
+
await walk(path.join(absDir, e.name), childRel, false);
|
|
154
|
+
}
|
|
155
|
+
else if (e.isFile() && !isExcludedFile(e.name)) {
|
|
156
|
+
out.push(childRel);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
await walk(home, '', true);
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Walk projects.json and capture each project's `.crewly/` tree + git
|
|
165
|
+
* provenance into staging/projects/<id>/.
|
|
166
|
+
*
|
|
167
|
+
* @param home - CREWLY_HOME absolute path
|
|
168
|
+
* @param staging - staging dir root
|
|
169
|
+
* @returns Project entries for the manifest
|
|
170
|
+
*/
|
|
171
|
+
async collectProjects(home, staging) {
|
|
172
|
+
const projects = await safeReadJson(path.join(home, 'projects.json'), []);
|
|
173
|
+
const result = [];
|
|
174
|
+
for (const proj of projects) {
|
|
175
|
+
const crewlyDir = path.join(proj.path, '.crewly');
|
|
176
|
+
const dirStat = await fs.stat(crewlyDir).catch(() => null);
|
|
177
|
+
if (!dirStat?.isDirectory())
|
|
178
|
+
continue; // project gone / never initialized
|
|
179
|
+
const files = [];
|
|
180
|
+
const walk = async (absDir, rel) => {
|
|
181
|
+
const entries = await fs.readdir(absDir, { withFileTypes: true }).catch(() => []);
|
|
182
|
+
for (const e of entries) {
|
|
183
|
+
if (e.isDirectory() && EXCLUDE_DIR_ANYWHERE.has(e.name))
|
|
184
|
+
continue;
|
|
185
|
+
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
186
|
+
if (e.isDirectory())
|
|
187
|
+
await walk(path.join(absDir, e.name), childRel);
|
|
188
|
+
else if (e.isFile() && !isExcludedFile(e.name)) {
|
|
189
|
+
const archivePath = `projects/${proj.id}/.crewly/${childRel}`;
|
|
190
|
+
files.push(await this.stageFile(crewlyDir, childRel, staging, archivePath));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
await walk(crewlyDir, '');
|
|
195
|
+
result.push({
|
|
196
|
+
id: proj.id,
|
|
197
|
+
name: proj.name,
|
|
198
|
+
sourcePath: proj.path,
|
|
199
|
+
git: await this.readGitProvenance(proj.path),
|
|
200
|
+
files,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Read `origin` remote + HEAD commit for a project dir (best-effort).
|
|
207
|
+
*
|
|
208
|
+
* @param projectPath - Absolute project path
|
|
209
|
+
* @returns Git provenance (nulls when not a repo / unavailable)
|
|
210
|
+
*/
|
|
211
|
+
async readGitProvenance(projectPath) {
|
|
212
|
+
const run = async (args) => {
|
|
213
|
+
try {
|
|
214
|
+
const { stdout } = await execFileAsync('git', ['-C', projectPath, ...args], { timeout: 5000 });
|
|
215
|
+
const v = stdout.trim();
|
|
216
|
+
return v.length > 0 ? v : null;
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
return {
|
|
223
|
+
remote: await run(['remote', 'get-url', 'origin']),
|
|
224
|
+
commit: await run(['rev-parse', 'HEAD']),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Capture chat.db via the SQLite online backup API (consistent snapshot of a
|
|
229
|
+
* possibly-live DB). Degrades gracefully when chat.db is absent or the native
|
|
230
|
+
* module can't load — the backup just omits it with a recorded reason.
|
|
231
|
+
*
|
|
232
|
+
* @param home - CREWLY_HOME absolute path
|
|
233
|
+
* @param staging - staging dir root
|
|
234
|
+
* @returns chat.db manifest record
|
|
235
|
+
*/
|
|
236
|
+
async captureChatDb(home, staging) {
|
|
237
|
+
const dbPath = path.join(home, 'chat.db');
|
|
238
|
+
if (!(await fs.stat(dbPath).catch(() => null))?.isFile()) {
|
|
239
|
+
return { included: false, skippedReason: 'chat.db not present' };
|
|
240
|
+
}
|
|
241
|
+
const dest = path.join(staging, 'chat.db');
|
|
242
|
+
try {
|
|
243
|
+
const mod = (await import('better-sqlite3'));
|
|
244
|
+
const Database = mod.default;
|
|
245
|
+
const db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
246
|
+
try {
|
|
247
|
+
await db.backup(dest);
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
db.close();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
255
|
+
this.logger.warn('chat.db capture skipped', { reason });
|
|
256
|
+
return { included: false, skippedReason: `sqlite backup failed: ${reason}` };
|
|
257
|
+
}
|
|
258
|
+
const { sha256, bytes } = await hashAndSize(dest);
|
|
259
|
+
return { included: true, sha256, bytes };
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Copy a source file into the staging archive layout, returning its manifest
|
|
263
|
+
* entry (archive-relative path + sha256 + size).
|
|
264
|
+
*
|
|
265
|
+
* @param srcRoot - Root the relative path is resolved against
|
|
266
|
+
* @param rel - Source path relative to srcRoot (POSIX-style)
|
|
267
|
+
* @param staging - staging dir root
|
|
268
|
+
* @param archivePath - Destination path inside the archive
|
|
269
|
+
* @returns Manifest file entry
|
|
270
|
+
*/
|
|
271
|
+
async stageFile(srcRoot, rel, staging, archivePath) {
|
|
272
|
+
const src = path.join(srcRoot, ...rel.split('/'));
|
|
273
|
+
const dest = path.join(staging, ...archivePath.split('/'));
|
|
274
|
+
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
275
|
+
await fs.copyFile(src, dest);
|
|
276
|
+
const { sha256, bytes } = await hashAndSize(dest);
|
|
277
|
+
return { path: archivePath, sha256, bytes };
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Read the running Crewly version (best-effort). Uses npm_package_version —
|
|
281
|
+
* the same source as tracing.service.ts — which works under both the ESM
|
|
282
|
+
* runtime and the CJS test runner (no import.meta / __dirname).
|
|
283
|
+
*
|
|
284
|
+
* @returns Version string or 'unknown'
|
|
285
|
+
*/
|
|
286
|
+
readCrewlyVersion() {
|
|
287
|
+
return process.env.npm_package_version ?? 'unknown';
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Stream a file through SHA-256 and return the hex digest + byte size.
|
|
292
|
+
*
|
|
293
|
+
* @param filePath - File to hash
|
|
294
|
+
* @returns sha256 (hex) and byte size
|
|
295
|
+
*/
|
|
296
|
+
async function hashAndSize(filePath) {
|
|
297
|
+
return new Promise((resolve, reject) => {
|
|
298
|
+
const hash = createHash('sha256');
|
|
299
|
+
let bytes = 0;
|
|
300
|
+
const stream = createReadStream(filePath);
|
|
301
|
+
stream.on('data', (chunk) => {
|
|
302
|
+
bytes += chunk.length;
|
|
303
|
+
hash.update(chunk);
|
|
304
|
+
});
|
|
305
|
+
stream.on('error', reject);
|
|
306
|
+
stream.on('end', () => resolve({ sha256: hash.digest('hex'), bytes }));
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=backup-archive.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup-archive.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/backup/backup-archive.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup Cloud Client (P3)
|
|
3
|
+
*
|
|
4
|
+
* OSS-side HTTP client for the Pro-gated cloud backup service
|
|
5
|
+
* (`/api/cloud/backup`). Used by `crewly backup push/pull/list` to park an
|
|
6
|
+
* archive in the cloud and pull it back on another machine.
|
|
7
|
+
*
|
|
8
|
+
* Transport-only: it streams files to/from the cloud and surfaces a friendly
|
|
9
|
+
* upgrade error on 402. Auth (access token) + base URL come from
|
|
10
|
+
* CloudClientService; both are injected so this is testable without the cloud.
|
|
11
|
+
*
|
|
12
|
+
* @module services/backup/backup-cloud.client
|
|
13
|
+
*/
|
|
14
|
+
/** Thrown when the account isn't Pro (HTTP 402). */
|
|
15
|
+
export declare class BackupNotProError extends Error {
|
|
16
|
+
readonly code = "upgrade_required";
|
|
17
|
+
constructor(message?: string);
|
|
18
|
+
}
|
|
19
|
+
/** Thrown on any other cloud backup HTTP failure. */
|
|
20
|
+
export declare class BackupCloudError extends Error {
|
|
21
|
+
readonly status?: number | undefined;
|
|
22
|
+
constructor(message: string, status?: number | undefined);
|
|
23
|
+
}
|
|
24
|
+
/** A cloud snapshot as returned by the service (client-facing view). */
|
|
25
|
+
export interface CloudBackupItem {
|
|
26
|
+
backupId: string;
|
|
27
|
+
deviceName: string | null;
|
|
28
|
+
deviceId: string | null;
|
|
29
|
+
sizeBytes: number;
|
|
30
|
+
sha256: string | null;
|
|
31
|
+
cryptoMode: 'sse' | 'none';
|
|
32
|
+
createdAt: string;
|
|
33
|
+
}
|
|
34
|
+
/** Metadata sent with an upload. */
|
|
35
|
+
export interface PushMeta {
|
|
36
|
+
backupId?: string;
|
|
37
|
+
deviceName?: string | null;
|
|
38
|
+
deviceId?: string | null;
|
|
39
|
+
sha256?: string | null;
|
|
40
|
+
}
|
|
41
|
+
/** HTTP client for the cloud backup endpoints. */
|
|
42
|
+
export declare class BackupCloudClient {
|
|
43
|
+
private readonly opts;
|
|
44
|
+
private readonly fetchImpl;
|
|
45
|
+
constructor(opts: {
|
|
46
|
+
baseUrl: string;
|
|
47
|
+
token: string;
|
|
48
|
+
fetchImpl?: typeof fetch;
|
|
49
|
+
});
|
|
50
|
+
private url;
|
|
51
|
+
private authHeaders;
|
|
52
|
+
/** List this account's cloud snapshots (newest first). */
|
|
53
|
+
list(): Promise<CloudBackupItem[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Upload an archive to the cloud. Streams the file with its Content-Length so
|
|
56
|
+
* the service can enforce quota before accepting the blob.
|
|
57
|
+
*
|
|
58
|
+
* @param archivePath - Local archive (.tar.gz)
|
|
59
|
+
* @param meta - Optional backupId + device/sha metadata
|
|
60
|
+
* @returns The created snapshot record
|
|
61
|
+
*/
|
|
62
|
+
push(archivePath: string, meta?: PushMeta): Promise<CloudBackupItem>;
|
|
63
|
+
/**
|
|
64
|
+
* Download a snapshot to `destPath` (streamed).
|
|
65
|
+
*
|
|
66
|
+
* @param backupId - Snapshot id
|
|
67
|
+
* @param destPath - Local file to write
|
|
68
|
+
*/
|
|
69
|
+
pull(backupId: string, destPath: string): Promise<void>;
|
|
70
|
+
/** Delete a cloud snapshot. */
|
|
71
|
+
remove(backupId: string): Promise<void>;
|
|
72
|
+
/** Map non-2xx responses to typed errors (402 → upgrade). */
|
|
73
|
+
private assertOk;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=backup-cloud.client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup-cloud.client.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/backup/backup-cloud.client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,oDAAoD;AACpD,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,sBAAsB;gBACvB,OAAO,SAA+E;CAInG;AAED,qDAAqD;AACrD,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,MAAM,CAAC,EAAE,MAAM;gBAD/B,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA;CAKlC;AAED,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,KAAK,GAAG,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,oCAAoC;AACpC,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,kDAAkD;AAClD,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAGtB,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;KAAE;IAKrF,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,WAAW;IAInB,0DAA0D;IACpD,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAOxC;;;;;;;OAOG;IACG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,eAAe,CAAC;IAsB9E;;;;;OAKG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ7D,+BAA+B;IACzB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ7C,6DAA6D;YAC/C,QAAQ;CAoBvB"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup Cloud Client (P3)
|
|
3
|
+
*
|
|
4
|
+
* OSS-side HTTP client for the Pro-gated cloud backup service
|
|
5
|
+
* (`/api/cloud/backup`). Used by `crewly backup push/pull/list` to park an
|
|
6
|
+
* archive in the cloud and pull it back on another machine.
|
|
7
|
+
*
|
|
8
|
+
* Transport-only: it streams files to/from the cloud and surfaces a friendly
|
|
9
|
+
* upgrade error on 402. Auth (access token) + base URL come from
|
|
10
|
+
* CloudClientService; both are injected so this is testable without the cloud.
|
|
11
|
+
*
|
|
12
|
+
* @module services/backup/backup-cloud.client
|
|
13
|
+
*/
|
|
14
|
+
import { createReadStream, createWriteStream } from 'node:fs';
|
|
15
|
+
import * as fs from 'node:fs/promises';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import { Readable } from 'node:stream';
|
|
18
|
+
import { pipeline } from 'node:stream/promises';
|
|
19
|
+
/** Thrown when the account isn't Pro (HTTP 402). */
|
|
20
|
+
export class BackupNotProError extends Error {
|
|
21
|
+
code = 'upgrade_required';
|
|
22
|
+
constructor(message = 'Cloud backup requires a Pro plan. Upgrade at https://crewlyai.com/pricing.') {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'BackupNotProError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Thrown on any other cloud backup HTTP failure. */
|
|
28
|
+
export class BackupCloudError extends Error {
|
|
29
|
+
status;
|
|
30
|
+
constructor(message, status) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.status = status;
|
|
33
|
+
this.name = 'BackupCloudError';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** HTTP client for the cloud backup endpoints. */
|
|
37
|
+
export class BackupCloudClient {
|
|
38
|
+
opts;
|
|
39
|
+
fetchImpl;
|
|
40
|
+
constructor(opts) {
|
|
41
|
+
this.opts = opts;
|
|
42
|
+
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
43
|
+
}
|
|
44
|
+
url(suffix) {
|
|
45
|
+
return `${this.opts.baseUrl.replace(/\/$/, '')}/api/cloud/backup${suffix}`;
|
|
46
|
+
}
|
|
47
|
+
authHeaders(extra = {}) {
|
|
48
|
+
return { Authorization: `Bearer ${this.opts.token}`, ...extra };
|
|
49
|
+
}
|
|
50
|
+
/** List this account's cloud snapshots (newest first). */
|
|
51
|
+
async list() {
|
|
52
|
+
const res = await this.fetchImpl(this.url(''), { headers: this.authHeaders() });
|
|
53
|
+
await this.assertOk(res);
|
|
54
|
+
const json = (await res.json());
|
|
55
|
+
return json.data?.backups ?? [];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Upload an archive to the cloud. Streams the file with its Content-Length so
|
|
59
|
+
* the service can enforce quota before accepting the blob.
|
|
60
|
+
*
|
|
61
|
+
* @param archivePath - Local archive (.tar.gz)
|
|
62
|
+
* @param meta - Optional backupId + device/sha metadata
|
|
63
|
+
* @returns The created snapshot record
|
|
64
|
+
*/
|
|
65
|
+
async push(archivePath, meta = {}) {
|
|
66
|
+
const stat = await fs.stat(archivePath);
|
|
67
|
+
const query = meta.backupId ? `?backupId=${encodeURIComponent(meta.backupId)}` : '';
|
|
68
|
+
const headers = this.authHeaders({
|
|
69
|
+
'Content-Type': 'application/gzip',
|
|
70
|
+
'Content-Length': String(stat.size),
|
|
71
|
+
...(meta.deviceName ? { 'X-Device-Name': meta.deviceName } : {}),
|
|
72
|
+
...(meta.deviceId ? { 'X-Device-Id': meta.deviceId } : {}),
|
|
73
|
+
...(meta.sha256 ? { 'X-Backup-Sha256': meta.sha256 } : {}),
|
|
74
|
+
});
|
|
75
|
+
const res = await this.fetchImpl(this.url(query), {
|
|
76
|
+
method: 'POST',
|
|
77
|
+
headers,
|
|
78
|
+
body: createReadStream(archivePath),
|
|
79
|
+
// Node fetch requires this for a streaming request body.
|
|
80
|
+
duplex: 'half',
|
|
81
|
+
});
|
|
82
|
+
await this.assertOk(res);
|
|
83
|
+
const json = (await res.json());
|
|
84
|
+
return json.data;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Download a snapshot to `destPath` (streamed).
|
|
88
|
+
*
|
|
89
|
+
* @param backupId - Snapshot id
|
|
90
|
+
* @param destPath - Local file to write
|
|
91
|
+
*/
|
|
92
|
+
async pull(backupId, destPath) {
|
|
93
|
+
const res = await this.fetchImpl(this.url(`/${encodeURIComponent(backupId)}`), { headers: this.authHeaders() });
|
|
94
|
+
await this.assertOk(res);
|
|
95
|
+
if (!res.body)
|
|
96
|
+
throw new BackupCloudError('Empty download response from cloud.');
|
|
97
|
+
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
98
|
+
await pipeline(Readable.fromWeb(res.body), createWriteStream(destPath));
|
|
99
|
+
}
|
|
100
|
+
/** Delete a cloud snapshot. */
|
|
101
|
+
async remove(backupId) {
|
|
102
|
+
const res = await this.fetchImpl(this.url(`/${encodeURIComponent(backupId)}`), {
|
|
103
|
+
method: 'DELETE',
|
|
104
|
+
headers: this.authHeaders(),
|
|
105
|
+
});
|
|
106
|
+
await this.assertOk(res);
|
|
107
|
+
}
|
|
108
|
+
/** Map non-2xx responses to typed errors (402 → upgrade). */
|
|
109
|
+
async assertOk(res) {
|
|
110
|
+
if (res.ok)
|
|
111
|
+
return;
|
|
112
|
+
if (res.status === 402) {
|
|
113
|
+
let msg;
|
|
114
|
+
try {
|
|
115
|
+
msg = (await res.json()).error;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
/* ignore */
|
|
119
|
+
}
|
|
120
|
+
throw new BackupNotProError(msg);
|
|
121
|
+
}
|
|
122
|
+
let message = `Cloud backup request failed (HTTP ${res.status}).`;
|
|
123
|
+
try {
|
|
124
|
+
const j = (await res.json());
|
|
125
|
+
if (j.error)
|
|
126
|
+
message = j.error;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
/* non-JSON body */
|
|
130
|
+
}
|
|
131
|
+
throw new BackupCloudError(message, res.status);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=backup-cloud.client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup-cloud.client.js","sourceRoot":"","sources":["../../../../../../backend/src/services/backup/backup-cloud.client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup Restore Service (P1)
|
|
3
|
+
*
|
|
4
|
+
* Restores a workspace archive (produced by BackupArchiveService) onto this
|
|
5
|
+
* machine to resume work after a machine dies / is replaced.
|
|
6
|
+
*
|
|
7
|
+
* Safety model:
|
|
8
|
+
* - `preview()` is non-destructive (dry-run) — reports the plan + conflicts.
|
|
9
|
+
* - `restore()` snapshots the CURRENT CREWLY_HOME first (rollback), refuses
|
|
10
|
+
* on overlapping ids unless mode='overwrite', then applies and — on any
|
|
11
|
+
* failure — rolls back from the snapshot.
|
|
12
|
+
* - device.json is NEVER in the archive, so the target keeps its own identity.
|
|
13
|
+
* - cron `nextRunAt` is reset to null so the scheduler recomputes from
|
|
14
|
+
* `cronExpression` (no stale fires); runtime/session state is wiped so
|
|
15
|
+
* agents start clean.
|
|
16
|
+
*
|
|
17
|
+
* See specs/2026-06-07-workspace-backup.md.
|
|
18
|
+
*
|
|
19
|
+
* @module services/backup/backup-restore.service
|
|
20
|
+
*/
|
|
21
|
+
import { type ComponentLogger } from '../core/logger.service.js';
|
|
22
|
+
import { type RestoreOptions, type RestorePlan, type RestoreResult } from './backup.types.js';
|
|
23
|
+
/** Thrown by restore() when mode='abort' and the target has overlapping data. */
|
|
24
|
+
export declare class RestoreConflictError extends Error {
|
|
25
|
+
readonly plan: RestorePlan;
|
|
26
|
+
constructor(message: string, plan: RestorePlan);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Service that restores workspace backup archives.
|
|
30
|
+
*/
|
|
31
|
+
export declare class BackupRestoreService {
|
|
32
|
+
private readonly logger;
|
|
33
|
+
constructor(logger?: ComponentLogger);
|
|
34
|
+
/**
|
|
35
|
+
* Non-destructive restore plan (dry-run): what would be created/overwritten,
|
|
36
|
+
* id conflicts, resolved project paths, and what's regenerated/discarded.
|
|
37
|
+
*
|
|
38
|
+
* @param options - Restore options (mode/pathMap affect conflict + path resolution)
|
|
39
|
+
* @returns The plan; never writes to disk
|
|
40
|
+
*/
|
|
41
|
+
preview(options: RestoreOptions): Promise<RestorePlan>;
|
|
42
|
+
/**
|
|
43
|
+
* Restore the archive onto this machine.
|
|
44
|
+
*
|
|
45
|
+
* @param options - Restore options
|
|
46
|
+
* @returns Summary of what was restored
|
|
47
|
+
* @throws RestoreConflictError when mode='abort' and ids overlap
|
|
48
|
+
* @throws Error on integrity failure or unsupported schema (no changes applied)
|
|
49
|
+
*/
|
|
50
|
+
restore(options: RestoreOptions): Promise<RestoreResult>;
|
|
51
|
+
/** Extract the archive to a fresh temp dir; returns its path. */
|
|
52
|
+
private extract;
|
|
53
|
+
/** Read + minimally validate the manifest from an extracted archive. */
|
|
54
|
+
private readManifest;
|
|
55
|
+
/** Verify every recorded file's sha256 against the extracted bytes. */
|
|
56
|
+
private verifyChecksums;
|
|
57
|
+
/** Build the dry-run plan (conflicts, resolved project paths, warnings). */
|
|
58
|
+
private buildPlan;
|
|
59
|
+
/** Copy every manifest global file from temp/home/* into CREWLY_HOME. */
|
|
60
|
+
private applyGlobals;
|
|
61
|
+
/** Copy each resolved project's `.crewly/` from the archive to its target path. */
|
|
62
|
+
private applyProjects;
|
|
63
|
+
/** Atomically swap chat.db into place (temp copy → rename). */
|
|
64
|
+
private applyChatDb;
|
|
65
|
+
/** Rewrite projects.json `path` entries using the resolved plan mapping. */
|
|
66
|
+
private rewriteProjectsJson;
|
|
67
|
+
/** Reset cron `nextRunAt` so the scheduler recomputes from cronExpression. */
|
|
68
|
+
private resetCron;
|
|
69
|
+
/** Remove runtime/session state so agents start clean on the restored machine. */
|
|
70
|
+
private wipeRuntime;
|
|
71
|
+
/** Recursively copy a directory tree, skipping top-level names in `skipTop`. */
|
|
72
|
+
private copyTree;
|
|
73
|
+
/** Recursive copy without the top-level skip filter. */
|
|
74
|
+
private copyTreeRec;
|
|
75
|
+
private pathExists;
|
|
76
|
+
private readJson;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=backup-restore.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup-restore.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/backup/backup-restore.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,WAAW,EAEhB,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAQ3B,iFAAiF;AACjF,qBAAa,oBAAqB,SAAQ,KAAK;aAG3B,IAAI,EAAE,WAAW;gBADjC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,WAAW;CAKpC;AAED;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;gBAE7B,MAAM,CAAC,EAAE,eAAe;IAIpC;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAW5D;;;;;;;OAOG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA4D9D,iEAAiE;YACnD,OAAO;IASrB,wEAAwE;YAC1D,YAAY;IAe1B,uEAAuE;YACzD,eAAe;IAiB7B,4EAA4E;YAC9D,SAAS;IAqDvB,yEAAyE;YAC3D,YAAY;IAc1B,mFAAmF;YACrE,aAAa;IAmB3B,+DAA+D;YACjD,WAAW;IAezB,4EAA4E;YAC9D,mBAAmB;IAgBjC,8EAA8E;YAChE,SAAS;IAgBvB,kFAAkF;YACpE,WAAW;IAQzB,gFAAgF;YAClE,QAAQ;IAYtB,wDAAwD;YAC1C,WAAW;YAUX,UAAU;YAIV,QAAQ;CAOvB"}
|