@okclaw-build/cli 1.0.0-beta.41 → 1.0.0-beta.43
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 +48 -0
- package/dist/commands/backup.d.ts +16 -0
- package/dist/commands/backup.js +72 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/migration.d.ts +1 -0
- package/dist/commands/migration.js +205 -0
- package/dist/commands/migration.js.map +1 -0
- package/dist/commands/restore.d.ts +16 -0
- package/dist/commands/restore.js +67 -0
- package/dist/commands/restore.js.map +1 -0
- package/dist/commands/service.js +21 -31
- package/dist/commands/service.js.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/installers/openclaw.d.ts +1 -14
- package/dist/installers/openclaw.js +12 -64
- package/dist/installers/openclaw.js.map +1 -1
- package/dist/migration/archive.d.ts +14 -0
- package/dist/migration/archive.js +84 -0
- package/dist/migration/archive.js.map +1 -0
- package/dist/migration/crypto.d.ts +16 -0
- package/dist/migration/crypto.js +56 -0
- package/dist/migration/crypto.js.map +1 -0
- package/dist/migration/manifest.d.ts +39 -0
- package/dist/migration/manifest.js +140 -0
- package/dist/migration/manifest.js.map +1 -0
- package/dist/openclaw-user-data.d.ts +63 -0
- package/dist/openclaw-user-data.js +246 -0
- package/dist/openclaw-user-data.js.map +1 -0
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.js +4 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/openclaw-daemon.d.ts +43 -8
- package/dist/utils/openclaw-daemon.js +124 -18
- package/dist/utils/openclaw-daemon.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
import type { Installer } from './base.js';
|
|
2
|
-
|
|
3
|
-
existsSync(path: string): boolean;
|
|
4
|
-
mkdirSync(path: string, options?: {
|
|
5
|
-
recursive?: boolean;
|
|
6
|
-
}): unknown;
|
|
7
|
-
cpSync(src: string, dest: string, options?: {
|
|
8
|
-
recursive?: boolean;
|
|
9
|
-
}): unknown;
|
|
10
|
-
statSync(path: string): {
|
|
11
|
-
isDirectory(): boolean;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
export declare function backupOpenclawUserData(now?: Date, fsOps?: BackupFs): string | null;
|
|
2
|
+
export { backupOpenclawUserData } from '../openclaw-user-data.js';
|
|
15
3
|
export declare class OpenclawInstaller implements Installer {
|
|
16
4
|
checkDeps(): Promise<void>;
|
|
17
5
|
install(version: string): Promise<void>;
|
|
@@ -30,4 +18,3 @@ export declare class OpenclawInstaller implements Installer {
|
|
|
30
18
|
configure(config: Record<string, unknown>): Promise<void>;
|
|
31
19
|
uninstall(): Promise<void>;
|
|
32
20
|
}
|
|
33
|
-
export {};
|
|
@@ -1,69 +1,13 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, existsSync, cpSync, mkdirSync, rmSync
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, cpSync, mkdirSync, rmSync } from 'node:fs';
|
|
2
2
|
import { shell, shellRetry, shellCapture } from '../utils/shell.js';
|
|
3
3
|
import { ensureNodeVersion, checkDiskSpace } from '../utils/deps.js';
|
|
4
4
|
import { info, warn } from '../utils/logger.js';
|
|
5
|
-
import { stopDaemonForExclusiveAccess } from '../utils/openclaw-daemon.js';
|
|
6
|
-
import { OPENCLAW_HOME,
|
|
5
|
+
import { stopDaemonForExclusiveAccess, stopGateway, cleanupGatewayServiceFiles, } from '../utils/openclaw-daemon.js';
|
|
6
|
+
import { OPENCLAW_HOME, OKCLAW_BACKUP_DIR, NPM_REGISTRY } from '../utils/constants.js';
|
|
7
7
|
import { purgePhaseB } from './openviking-purge.js';
|
|
8
|
+
import { backupOpenclawUserData } from '../openclaw-user-data.js';
|
|
9
|
+
export { backupOpenclawUserData } from '../openclaw-user-data.js';
|
|
8
10
|
const OPENCLAW_CONFIG = `${OPENCLAW_HOME}/openclaw.json`;
|
|
9
|
-
const LEGACY_OPENCLAW_WORKSPACE = '/root/openclaw/workspace';
|
|
10
|
-
const OPENCLAW_USER_DATA_FILES = [
|
|
11
|
-
'MEMORY.md',
|
|
12
|
-
'USER.md',
|
|
13
|
-
'IDENTITY.md',
|
|
14
|
-
'SOUL.md',
|
|
15
|
-
'TOOLS.md',
|
|
16
|
-
'AGENTS.md',
|
|
17
|
-
];
|
|
18
|
-
const realBackupFs = { existsSync, mkdirSync, cpSync, statSync };
|
|
19
|
-
function formatBackupTimestamp(now) {
|
|
20
|
-
return now.toISOString().replace(/\.\d{3}Z$/, 'Z').replace(/:/g, '');
|
|
21
|
-
}
|
|
22
|
-
function copyIfExists(fsOps, src, dest, recursive = false) {
|
|
23
|
-
if (!fsOps.existsSync(src))
|
|
24
|
-
return false;
|
|
25
|
-
fsOps.cpSync(src, dest, recursive ? { recursive: true } : undefined);
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
export function backupOpenclawUserData(now = new Date(), fsOps = realBackupFs) {
|
|
29
|
-
const backupDir = `${OKCLAW_BACKUP_DIR}/openclaw-user-data-${formatBackupTimestamp(now)}`;
|
|
30
|
-
const workspaces = Array.from(new Set([OPENCLAW_WORKSPACE, LEGACY_OPENCLAW_WORKSPACE]));
|
|
31
|
-
let copiedItems = 0;
|
|
32
|
-
let copiedWorkspaces = 0;
|
|
33
|
-
for (const workspace of workspaces) {
|
|
34
|
-
if (!fsOps.existsSync(workspace))
|
|
35
|
-
continue;
|
|
36
|
-
const workspaceBackupName = copiedWorkspaces === 0 ? 'workspace' : 'workspace-root-openclaw';
|
|
37
|
-
const workspaceBackupDir = `${backupDir}/${workspaceBackupName}`;
|
|
38
|
-
let workspaceDirCreated = false;
|
|
39
|
-
const ensureWorkspaceBackupDir = () => {
|
|
40
|
-
if (workspaceDirCreated)
|
|
41
|
-
return;
|
|
42
|
-
fsOps.mkdirSync(workspaceBackupDir, { recursive: true });
|
|
43
|
-
workspaceDirCreated = true;
|
|
44
|
-
};
|
|
45
|
-
for (const file of OPENCLAW_USER_DATA_FILES) {
|
|
46
|
-
const src = `${workspace}/${file}`;
|
|
47
|
-
if (!fsOps.existsSync(src))
|
|
48
|
-
continue;
|
|
49
|
-
ensureWorkspaceBackupDir();
|
|
50
|
-
if (copyIfExists(fsOps, src, `${workspaceBackupDir}/${file}`)) {
|
|
51
|
-
copiedItems += 1;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
const skillsDir = `${workspace}/skills`;
|
|
55
|
-
if (fsOps.existsSync(skillsDir) && fsOps.statSync(skillsDir).isDirectory()) {
|
|
56
|
-
ensureWorkspaceBackupDir();
|
|
57
|
-
if (copyIfExists(fsOps, skillsDir, `${workspaceBackupDir}/skills`, true)) {
|
|
58
|
-
copiedItems += 1;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (workspaceDirCreated) {
|
|
62
|
-
copiedWorkspaces += 1;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return copiedItems > 0 ? backupDir : null;
|
|
66
|
-
}
|
|
67
11
|
export class OpenclawInstaller {
|
|
68
12
|
async checkDeps() {
|
|
69
13
|
await checkDiskSpace(500);
|
|
@@ -218,9 +162,13 @@ export class OpenclawInstaller {
|
|
|
218
162
|
// 否则 pkill + npm uninstall 只删二进制,service 文件留着仍指向旧路径,新版装完
|
|
219
163
|
// systemd 会在旧 ExecStart 上无限 restart 直到下次手工 restart。
|
|
220
164
|
await shell(`openclaw gateway uninstall 2>/dev/null || true`).catch(() => { });
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
await
|
|
165
|
+
// `openclaw gateway uninstall` 只删主 .service,残留的 .bak / .service.d/
|
|
166
|
+
// drop-in 会污染下次 install,一并清掉。
|
|
167
|
+
await cleanupGatewayServiceFiles();
|
|
168
|
+
// 兜底停掉残留 gateway 进程(systemd 没接管的情况)。按监听端口杀 ——
|
|
169
|
+
// gateway 进程名在新版 openclaw 下是 `openclaw` / `node`,旧的
|
|
170
|
+
// `pkill -f openclaw-gateway` 匹配不到;按端口杀也绝不会误命中本 CLI 进程。
|
|
171
|
+
await stopGateway().catch(() => { });
|
|
224
172
|
// 多 package manager 容忍:主机可能用 npm / pnpm / yarn 任一装过 openclaw,
|
|
225
173
|
// 没装的包管理器跑也 tolerate,各自清各自的 store。
|
|
226
174
|
// 见 P5 真机排障:测试主机 which openclaw 指向 /root/.local/share/pnpm/openclaw,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../../src/installers/openclaw.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../../src/installers/openclaw.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const ARCHIVE_MANIFEST_NAME = "migration-manifest.json";
|
|
2
|
+
export interface TarCreateOptions {
|
|
3
|
+
tarPath: string;
|
|
4
|
+
manifestPath: string;
|
|
5
|
+
existingIncludePaths: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function buildTarCreateArgs(options: TarCreateOptions): string[];
|
|
8
|
+
export declare function buildTarExtractArgs(tarPath: string): string[];
|
|
9
|
+
export declare function buildTarListArgs(tarPath: string): string[];
|
|
10
|
+
export declare function validateTarEntries(entries: string[], allowedAbsoluteRoots: string[]): void;
|
|
11
|
+
export declare function buildTarExtractManifestArgs(tarPath: string, outDir: string): string[];
|
|
12
|
+
export declare function buildTarCommand(args: string[]): string;
|
|
13
|
+
export declare function buildCreateEncryptedArchiveCommand(keyFile: string, inputTarPath: string, outputArchivePath: string): string;
|
|
14
|
+
export declare function buildDecryptArchiveCommand(keyFile: string, inputArchivePath: string, outputTarPath: string): string;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { basename, dirname } from 'node:path';
|
|
2
|
+
import { excludePatterns } from './manifest.js';
|
|
3
|
+
import { buildAgeCommand, buildAgeDecryptArgs, buildAgeEncryptArgs, quoteShellArg } from './crypto.js';
|
|
4
|
+
export const ARCHIVE_MANIFEST_NAME = 'migration-manifest.json';
|
|
5
|
+
export function buildTarCreateArgs(options) {
|
|
6
|
+
return [
|
|
7
|
+
'--create',
|
|
8
|
+
'--file',
|
|
9
|
+
options.tarPath,
|
|
10
|
+
'--xattrs',
|
|
11
|
+
'--acls',
|
|
12
|
+
'--numeric-owner',
|
|
13
|
+
...excludePatterns.map((pattern) => `--exclude=${pattern}`),
|
|
14
|
+
'-C',
|
|
15
|
+
dirname(options.manifestPath),
|
|
16
|
+
basename(options.manifestPath),
|
|
17
|
+
'-C',
|
|
18
|
+
'/',
|
|
19
|
+
...options.existingIncludePaths.map(toTarRelativePath),
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
export function buildTarExtractArgs(tarPath) {
|
|
23
|
+
return [
|
|
24
|
+
'--extract',
|
|
25
|
+
'--file',
|
|
26
|
+
tarPath,
|
|
27
|
+
'--same-owner',
|
|
28
|
+
'--preserve-permissions',
|
|
29
|
+
'--numeric-owner',
|
|
30
|
+
'-C',
|
|
31
|
+
'/',
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
export function buildTarListArgs(tarPath) {
|
|
35
|
+
return [
|
|
36
|
+
'--list',
|
|
37
|
+
'--file',
|
|
38
|
+
tarPath,
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
export function validateTarEntries(entries, allowedAbsoluteRoots) {
|
|
42
|
+
const allowed = new Set([
|
|
43
|
+
ARCHIVE_MANIFEST_NAME,
|
|
44
|
+
...allowedAbsoluteRoots.map(toTarRelativePath).map(stripTrailingSlash),
|
|
45
|
+
]);
|
|
46
|
+
for (const raw of entries) {
|
|
47
|
+
const entry = stripTrailingSlash(raw.trim());
|
|
48
|
+
if (!entry)
|
|
49
|
+
continue;
|
|
50
|
+
if (entry.startsWith('/') || entry.split('/').includes('..')) {
|
|
51
|
+
throw new Error(`Unsafe archive entry: ${raw}`);
|
|
52
|
+
}
|
|
53
|
+
const ok = [...allowed].some((root) => entry === root || entry.startsWith(`${root}/`));
|
|
54
|
+
if (!ok) {
|
|
55
|
+
throw new Error(`Archive entry outside manifest paths: ${raw}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function buildTarExtractManifestArgs(tarPath, outDir) {
|
|
60
|
+
return [
|
|
61
|
+
'--extract',
|
|
62
|
+
'--file',
|
|
63
|
+
tarPath,
|
|
64
|
+
'-C',
|
|
65
|
+
outDir,
|
|
66
|
+
ARCHIVE_MANIFEST_NAME,
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
export function buildTarCommand(args) {
|
|
70
|
+
return ['tar', ...args.map(quoteShellArg)].join(' ');
|
|
71
|
+
}
|
|
72
|
+
export function buildCreateEncryptedArchiveCommand(keyFile, inputTarPath, outputArchivePath) {
|
|
73
|
+
return buildAgeCommand(buildAgeEncryptArgs(keyFile, inputTarPath, outputArchivePath));
|
|
74
|
+
}
|
|
75
|
+
export function buildDecryptArchiveCommand(keyFile, inputArchivePath, outputTarPath) {
|
|
76
|
+
return buildAgeCommand(buildAgeDecryptArgs(keyFile, inputArchivePath, outputTarPath));
|
|
77
|
+
}
|
|
78
|
+
function toTarRelativePath(path) {
|
|
79
|
+
return path.replace(/^\/+/, '');
|
|
80
|
+
}
|
|
81
|
+
function stripTrailingSlash(path) {
|
|
82
|
+
return path.replace(/\/+$/, '');
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=archive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/migration/archive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const AUTHENTICATED_ENCRYPTION_TOOL = "age";
|
|
2
|
+
export declare const AUTHENTICATED_ENCRYPTION_CONTRACT = "age-v1-X25519-ChaCha20Poly1305";
|
|
3
|
+
export declare function buildAgeEncryptArgs(keyFile: string, inputPath: string, outputPath: string): string[];
|
|
4
|
+
export declare function buildAgeDecryptArgs(keyFile: string, inputPath: string, outputPath: string): string[];
|
|
5
|
+
export declare function buildAgeCommand(args: string[]): string;
|
|
6
|
+
export declare function assertAuthenticatedEncryptionAvailable(): Promise<void>;
|
|
7
|
+
export declare function quoteShellArg(value: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* export 用 `--recipient-file`,必须是 age 公钥;若误传私钥(identity),age 会在运行期才报错。
|
|
10
|
+
* 提前在 CLI 层显式校验,避免操作人把私钥当公钥用。
|
|
11
|
+
*/
|
|
12
|
+
export declare function assertAgeRecipientContent(content: string, keyFile: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* restore 用 `--identity`,必须是 age 私钥;若误传只含公钥的文件,提前报错而不是等 age 运行期失败。
|
|
15
|
+
*/
|
|
16
|
+
export declare function assertAgeIdentityContent(content: string, keyFile: string): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { commandExists } from '../utils/shell.js';
|
|
2
|
+
export const AUTHENTICATED_ENCRYPTION_TOOL = 'age';
|
|
3
|
+
export const AUTHENTICATED_ENCRYPTION_CONTRACT = 'age-v1-X25519-ChaCha20Poly1305';
|
|
4
|
+
export function buildAgeEncryptArgs(keyFile, inputPath, outputPath) {
|
|
5
|
+
return [
|
|
6
|
+
'--encrypt',
|
|
7
|
+
'--recipient-file',
|
|
8
|
+
keyFile,
|
|
9
|
+
'--output',
|
|
10
|
+
outputPath,
|
|
11
|
+
inputPath,
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
export function buildAgeDecryptArgs(keyFile, inputPath, outputPath) {
|
|
15
|
+
return [
|
|
16
|
+
'--decrypt',
|
|
17
|
+
'--identity',
|
|
18
|
+
keyFile,
|
|
19
|
+
'--output',
|
|
20
|
+
outputPath,
|
|
21
|
+
inputPath,
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
export function buildAgeCommand(args) {
|
|
25
|
+
return [AUTHENTICATED_ENCRYPTION_TOOL, ...args.map(quoteShellArg)].join(' ');
|
|
26
|
+
}
|
|
27
|
+
export async function assertAuthenticatedEncryptionAvailable() {
|
|
28
|
+
if (!await commandExists(AUTHENTICATED_ENCRYPTION_TOOL)) {
|
|
29
|
+
throw new Error('Missing authenticated encryption tool: age');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function quoteShellArg(value) {
|
|
33
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
34
|
+
}
|
|
35
|
+
const AGE_SECRET_KEY_MARKER = /AGE-SECRET-KEY-/;
|
|
36
|
+
const OPENSSH_PRIVATE_KEY_MARKER = /BEGIN OPENSSH PRIVATE KEY/;
|
|
37
|
+
const AGE_RECIPIENT_MARKER = /(^|\n)\s*age1[0-9a-z]/;
|
|
38
|
+
/**
|
|
39
|
+
* export 用 `--recipient-file`,必须是 age 公钥;若误传私钥(identity),age 会在运行期才报错。
|
|
40
|
+
* 提前在 CLI 层显式校验,避免操作人把私钥当公钥用。
|
|
41
|
+
*/
|
|
42
|
+
export function assertAgeRecipientContent(content, keyFile) {
|
|
43
|
+
if (AGE_SECRET_KEY_MARKER.test(content)) {
|
|
44
|
+
throw new Error(`--key-file 应为 age 公钥(recipient)文件,但 ${keyFile} 含 age 私钥;export 加密只需公钥`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* restore 用 `--identity`,必须是 age 私钥;若误传只含公钥的文件,提前报错而不是等 age 运行期失败。
|
|
49
|
+
*/
|
|
50
|
+
export function assertAgeIdentityContent(content, keyFile) {
|
|
51
|
+
const hasIdentity = AGE_SECRET_KEY_MARKER.test(content) || OPENSSH_PRIVATE_KEY_MARKER.test(content);
|
|
52
|
+
if (!hasIdentity && AGE_RECIPIENT_MARKER.test(content)) {
|
|
53
|
+
throw new Error(`--key-file 应为 age 私钥(identity)文件,但 ${keyFile} 仅含 age 公钥;restore 解密需要私钥`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/migration/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAK,CAAC;AACnD,MAAM,CAAC,MAAM,iCAAiC,GAAG,gCAAgC,CAAC;AAElF,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,SAAiB,EAAE,UAAkB;IACxF,OAAO;QACL,WAAW;QACX,kBAAkB;QAClB,OAAO;QACP,UAAU;QACV,UAAU;QACV,SAAS;KACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,SAAiB,EAAE,UAAkB;IACxF,OAAO;QACL,WAAW;QACX,YAAY;QACZ,OAAO;QACP,UAAU;QACV,UAAU;QACV,SAAS;KACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,OAAO,CAAC,6BAA6B,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sCAAsC;IAC1D,IAAI,CAAC,MAAM,aAAa,CAAC,6BAA6B,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AAChD,MAAM,0BAA0B,GAAG,2BAA2B,CAAC;AAC/D,MAAM,oBAAoB,GAAG,uBAAuB,CAAC;AAErD;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAe,EAAE,OAAe;IACxE,IAAI,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,yBAAyB,CAAC,CAAC;IAC3F,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAe,EAAE,OAAe;IACvE,MAAM,WAAW,GAAG,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpG,IAAI,CAAC,WAAW,IAAI,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,sCAAsC,OAAO,2BAA2B,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export declare const MIGRATION_MANIFEST_VERSION = "openclaw-runtime-v1";
|
|
2
|
+
export declare const LEGACY_OPENCLAW_WORKSPACE = "/root/openclaw/workspace";
|
|
3
|
+
export declare const includePaths: string[];
|
|
4
|
+
export declare const excludePatterns: string[];
|
|
5
|
+
export declare const requiredRuntimeFiles: string[];
|
|
6
|
+
export interface MigrationManifestPath {
|
|
7
|
+
path: string;
|
|
8
|
+
status: 'included' | 'missing';
|
|
9
|
+
type?: 'file' | 'directory' | 'symlink' | 'other';
|
|
10
|
+
mode?: number;
|
|
11
|
+
uid?: number;
|
|
12
|
+
gid?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface MigrationManifest {
|
|
15
|
+
version: typeof MIGRATION_MANIFEST_VERSION;
|
|
16
|
+
createdAt: string;
|
|
17
|
+
taskId: string;
|
|
18
|
+
shrimpId: string;
|
|
19
|
+
sourceHostId: string;
|
|
20
|
+
targetHostId: string;
|
|
21
|
+
includePaths: string[];
|
|
22
|
+
excludePatterns: string[];
|
|
23
|
+
requiredRuntimeFiles: string[];
|
|
24
|
+
missingPaths: string[];
|
|
25
|
+
paths: MigrationManifestPath[];
|
|
26
|
+
}
|
|
27
|
+
export interface MigrationIdentity {
|
|
28
|
+
taskId: string;
|
|
29
|
+
shrimpId: string;
|
|
30
|
+
sourceHostId: string;
|
|
31
|
+
targetHostId: string;
|
|
32
|
+
}
|
|
33
|
+
export interface BuildManifestOptions extends MigrationIdentity {
|
|
34
|
+
rootDir?: string;
|
|
35
|
+
createdAt?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function buildMigrationManifest(options: BuildManifestOptions): MigrationManifest;
|
|
38
|
+
export declare function existingManifestPaths(manifest: MigrationManifest): string[];
|
|
39
|
+
export declare function validateMigrationManifest(value: unknown, expected: MigrationIdentity): MigrationManifest;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { existsSync, lstatSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { OKCLAW_BACKUP_DIR, OKCLAW_CONFIG_DIR, OPENCLAW_HOME, OPENCLAW_WORKSPACE, OPENVIKING_HOME, } from '../utils/constants.js';
|
|
4
|
+
export const MIGRATION_MANIFEST_VERSION = 'openclaw-runtime-v1';
|
|
5
|
+
export const LEGACY_OPENCLAW_WORKSPACE = '/root/openclaw/workspace';
|
|
6
|
+
export const includePaths = [
|
|
7
|
+
OPENCLAW_HOME,
|
|
8
|
+
OPENCLAW_WORKSPACE,
|
|
9
|
+
LEGACY_OPENCLAW_WORKSPACE,
|
|
10
|
+
OKCLAW_CONFIG_DIR,
|
|
11
|
+
OKCLAW_BACKUP_DIR,
|
|
12
|
+
OPENVIKING_HOME,
|
|
13
|
+
];
|
|
14
|
+
export const excludePatterns = [
|
|
15
|
+
'**/*.sock',
|
|
16
|
+
'**/*.pid',
|
|
17
|
+
'**/*.lock',
|
|
18
|
+
'**/tmp/**',
|
|
19
|
+
'**/.cache/**',
|
|
20
|
+
'**/node_modules/.cache/**',
|
|
21
|
+
];
|
|
22
|
+
export const requiredRuntimeFiles = [
|
|
23
|
+
`${OPENCLAW_HOME}/openclaw.json`,
|
|
24
|
+
];
|
|
25
|
+
export function buildMigrationManifest(options) {
|
|
26
|
+
const rootDir = options.rootDir ?? '/';
|
|
27
|
+
const missingCritical = requiredRuntimeFiles.filter((path) => !existsSync(toHostPath(rootDir, path)));
|
|
28
|
+
if (missingCritical.length > 0) {
|
|
29
|
+
throw new Error(`Missing critical runtime file: ${missingCritical.join(', ')}`);
|
|
30
|
+
}
|
|
31
|
+
const paths = includePaths.map((path) => {
|
|
32
|
+
const hostPath = toHostPath(rootDir, path);
|
|
33
|
+
if (!existsSync(hostPath)) {
|
|
34
|
+
return { path, status: 'missing' };
|
|
35
|
+
}
|
|
36
|
+
const stat = lstatSync(hostPath);
|
|
37
|
+
return {
|
|
38
|
+
path,
|
|
39
|
+
status: 'included',
|
|
40
|
+
type: stat.isDirectory() ? 'directory' : stat.isFile() ? 'file' : stat.isSymbolicLink() ? 'symlink' : 'other',
|
|
41
|
+
mode: stat.mode,
|
|
42
|
+
uid: stat.uid,
|
|
43
|
+
gid: stat.gid,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
version: MIGRATION_MANIFEST_VERSION,
|
|
48
|
+
createdAt: options.createdAt ?? new Date().toISOString(),
|
|
49
|
+
taskId: options.taskId,
|
|
50
|
+
shrimpId: options.shrimpId,
|
|
51
|
+
sourceHostId: options.sourceHostId,
|
|
52
|
+
targetHostId: options.targetHostId,
|
|
53
|
+
includePaths: [...includePaths],
|
|
54
|
+
excludePatterns: [...excludePatterns],
|
|
55
|
+
requiredRuntimeFiles: [...requiredRuntimeFiles],
|
|
56
|
+
missingPaths: paths.filter((item) => item.status === 'missing').map((item) => item.path),
|
|
57
|
+
paths,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function existingManifestPaths(manifest) {
|
|
61
|
+
return manifest.paths.filter((item) => item.status === 'included').map((item) => item.path);
|
|
62
|
+
}
|
|
63
|
+
export function validateMigrationManifest(value, expected) {
|
|
64
|
+
if (!isManifest(value)) {
|
|
65
|
+
throw new Error('Invalid migration manifest');
|
|
66
|
+
}
|
|
67
|
+
if (value.version !== MIGRATION_MANIFEST_VERSION) {
|
|
68
|
+
throw new Error(`Unsupported manifest version: ${value.version}`);
|
|
69
|
+
}
|
|
70
|
+
assertEqual('taskId', value.taskId, expected.taskId);
|
|
71
|
+
assertEqual('shrimpId', value.shrimpId, expected.shrimpId);
|
|
72
|
+
assertEqual('sourceHostId', value.sourceHostId, expected.sourceHostId);
|
|
73
|
+
assertEqual('targetHostId', value.targetHostId, expected.targetHostId);
|
|
74
|
+
/*
|
|
75
|
+
* Restore cannot trust the archive's manifest to define its own allowed roots.
|
|
76
|
+
* The tar safety check extracts to /, so a malicious package that declares /etc
|
|
77
|
+
* as an included path would otherwise turn the manifest into an allow-list bypass.
|
|
78
|
+
* Keep the manifest useful for audit, but require every path list to match the
|
|
79
|
+
* hard-coded runtime contract compiled into this CLI version.
|
|
80
|
+
*/
|
|
81
|
+
assertStringArrayEqual('includePaths', value.includePaths, includePaths);
|
|
82
|
+
assertStringArrayEqual('excludePatterns', value.excludePatterns, excludePatterns);
|
|
83
|
+
assertStringArrayEqual('requiredRuntimeFiles', value.requiredRuntimeFiles, requiredRuntimeFiles);
|
|
84
|
+
validateManifestPathSet(value);
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
function assertEqual(field, actual, expected) {
|
|
88
|
+
if (actual !== expected) {
|
|
89
|
+
throw new Error(`Manifest ${field} mismatch: expected ${expected}, got ${actual}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function isManifest(value) {
|
|
93
|
+
if (typeof value !== 'object' || value === null)
|
|
94
|
+
return false;
|
|
95
|
+
const candidate = value;
|
|
96
|
+
return typeof candidate.version === 'string'
|
|
97
|
+
&& typeof candidate.taskId === 'string'
|
|
98
|
+
&& typeof candidate.shrimpId === 'string'
|
|
99
|
+
&& typeof candidate.sourceHostId === 'string'
|
|
100
|
+
&& typeof candidate.targetHostId === 'string'
|
|
101
|
+
&& Array.isArray(candidate.includePaths)
|
|
102
|
+
&& Array.isArray(candidate.excludePatterns)
|
|
103
|
+
&& Array.isArray(candidate.requiredRuntimeFiles)
|
|
104
|
+
&& Array.isArray(candidate.missingPaths)
|
|
105
|
+
&& Array.isArray(candidate.paths);
|
|
106
|
+
}
|
|
107
|
+
function assertStringArrayEqual(field, actual, expected) {
|
|
108
|
+
if (!Array.isArray(actual) || actual.length !== expected.length
|
|
109
|
+
|| actual.some((item, index) => item !== expected[index])) {
|
|
110
|
+
throw new Error(`Manifest ${field} does not match CLI runtime contract`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function validateManifestPathSet(manifest) {
|
|
114
|
+
const allowed = new Set(includePaths);
|
|
115
|
+
const seen = new Set();
|
|
116
|
+
const missing = new Set();
|
|
117
|
+
for (const item of manifest.paths) {
|
|
118
|
+
if (!item || typeof item.path !== 'string' || !allowed.has(item.path)) {
|
|
119
|
+
throw new Error(`Manifest path outside CLI runtime contract: ${item?.path ?? '<invalid>'}`);
|
|
120
|
+
}
|
|
121
|
+
if (seen.has(item.path)) {
|
|
122
|
+
throw new Error(`Manifest path duplicated: ${item.path}`);
|
|
123
|
+
}
|
|
124
|
+
seen.add(item.path);
|
|
125
|
+
if (item.status !== 'included' && item.status !== 'missing') {
|
|
126
|
+
throw new Error(`Manifest path has invalid status: ${item.path}`);
|
|
127
|
+
}
|
|
128
|
+
if (item.status === 'missing') {
|
|
129
|
+
missing.add(item.path);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (manifest.missingPaths.length !== missing.size
|
|
133
|
+
|| manifest.missingPaths.some((path) => !missing.has(path))) {
|
|
134
|
+
throw new Error('Manifest missingPaths does not match path statuses');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function toHostPath(rootDir, absolutePath) {
|
|
138
|
+
return join(rootDir, absolutePath.replace(/^\/+/, ''));
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/migration/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,MAAM,0BAA0B,GAAG,qBAAqB,CAAC;AAChE,MAAM,CAAC,MAAM,yBAAyB,GAAG,0BAA0B,CAAC;AAEpE,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,aAAa;IACb,kBAAkB;IAClB,yBAAyB;IACzB,iBAAiB;IACjB,iBAAiB;IACjB,eAAe;CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,WAAW;IACX,UAAU;IACV,WAAW;IACX,WAAW;IACX,cAAc;IACd,2BAA2B;CAC5B,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,GAAG,aAAa,gBAAgB;CACjC,CAAC;AAqCF,MAAM,UAAU,sBAAsB,CAAC,OAA6B;IAClE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC;IACvC,MAAM,eAAe,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACtG,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,kCAAkC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAyB,EAAE;QAC7D,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QACrC,CAAC;QAED,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjC,OAAO;YACL,IAAI;YACJ,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;YAC7G,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE,0BAA0B;QACnC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACxD,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,YAAY,EAAE,CAAC,GAAG,YAAY,CAAC;QAC/B,eAAe,EAAE,CAAC,GAAG,eAAe,CAAC;QACrC,oBAAoB,EAAE,CAAC,GAAG,oBAAoB,CAAC;QAC/C,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;QACxF,KAAK;KACN,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,QAA2B;IAC/D,OAAO,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAc,EAAE,QAA2B;IACnF,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,KAAK,0BAA0B,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,iCAAiC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACrD,WAAW,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC3D,WAAW,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACvE,WAAW,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACvE;;;;;;OAMG;IACH,sBAAsB,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACzE,sBAAsB,CAAC,iBAAiB,EAAE,KAAK,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;IAClF,sBAAsB,CAAC,sBAAsB,EAAE,KAAK,CAAC,oBAAoB,EAAE,oBAAoB,CAAC,CAAC;IACjG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,KAA8B,EAAE,MAAc,EAAE,QAAgB;IACnF,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,YAAY,KAAK,uBAAuB,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;IACrF,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,SAAS,GAAG,KAAgC,CAAC;IACnD,OAAO,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ;WACvC,OAAO,SAAS,CAAC,MAAM,KAAK,QAAQ;WACpC,OAAO,SAAS,CAAC,QAAQ,KAAK,QAAQ;WACtC,OAAO,SAAS,CAAC,YAAY,KAAK,QAAQ;WAC1C,OAAO,SAAS,CAAC,YAAY,KAAK,QAAQ;WAC1C,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,YAAY,CAAC;WACrC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,eAAe,CAAC;WACxC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,oBAAoB,CAAC;WAC7C,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,YAAY,CAAC;WACrC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAa,EAAE,MAAgB,EAAE,QAAkB;IACjF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;WACxD,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,YAAY,KAAK,sCAAsC,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,QAA2B;IAC1D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,KAAK,CAAC,+CAA+C,IAAI,EAAE,IAAI,IAAI,WAAW,EAAE,CAAC,CAAC;QAC9F,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,OAAO,CAAC,IAAI;WAC1C,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,OAAe,EAAE,YAAoB;IACvD,OAAO,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export declare const OPENCLAW_USER_DATA_FILES: readonly ["MEMORY.md", "USER.md", "IDENTITY.md", "SOUL.md", "TOOLS.md", "AGENTS.md", "HEARTBEAT.md"];
|
|
2
|
+
export declare const LEGACY_OPENCLAW_WORKSPACE = "/root/openclaw/workspace";
|
|
3
|
+
export type BackupFs = {
|
|
4
|
+
existsSync(path: string): boolean;
|
|
5
|
+
mkdirSync(path: string, options?: {
|
|
6
|
+
recursive?: boolean;
|
|
7
|
+
}): unknown;
|
|
8
|
+
cpSync(src: string, dest: string, options?: {
|
|
9
|
+
recursive?: boolean;
|
|
10
|
+
}): unknown;
|
|
11
|
+
statSync(path: string): {
|
|
12
|
+
isDirectory(): boolean;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export type ArchiveFs = BackupFs & {
|
|
16
|
+
readdirSync(path: string, options?: {
|
|
17
|
+
withFileTypes?: boolean;
|
|
18
|
+
}): Array<DirentLike>;
|
|
19
|
+
};
|
|
20
|
+
export type RestoreFs = BackupFs & {
|
|
21
|
+
rmSync(path: string, options?: {
|
|
22
|
+
recursive?: boolean;
|
|
23
|
+
force?: boolean;
|
|
24
|
+
}): unknown;
|
|
25
|
+
chmodSync(path: string, mode: number): unknown;
|
|
26
|
+
readdirSync(path: string, options?: {
|
|
27
|
+
withFileTypes?: boolean;
|
|
28
|
+
}): Array<DirentLike>;
|
|
29
|
+
};
|
|
30
|
+
type DirentLike = {
|
|
31
|
+
name: string;
|
|
32
|
+
isDirectory(): boolean;
|
|
33
|
+
isFile(): boolean;
|
|
34
|
+
};
|
|
35
|
+
export type ArchiveResult = {
|
|
36
|
+
backupDir: string | null;
|
|
37
|
+
archivePath: string | null;
|
|
38
|
+
includedFiles: string[];
|
|
39
|
+
};
|
|
40
|
+
export type RestoreResult = {
|
|
41
|
+
stagingDir: string;
|
|
42
|
+
archivePath: string;
|
|
43
|
+
restoredFiles: string[];
|
|
44
|
+
};
|
|
45
|
+
type ShellOps = {
|
|
46
|
+
shell(command: string): Promise<void>;
|
|
47
|
+
capture?(command: string): Promise<string>;
|
|
48
|
+
};
|
|
49
|
+
export declare function formatBackupTimestamp(now: Date): string;
|
|
50
|
+
export declare function backupOpenclawUserData(now?: Date, fsOps?: BackupFs): string | null;
|
|
51
|
+
export declare function createOpenclawUserDataArchive(options?: {
|
|
52
|
+
archivePath?: string;
|
|
53
|
+
now?: Date;
|
|
54
|
+
fsOps?: ArchiveFs;
|
|
55
|
+
shellOps?: ShellOps;
|
|
56
|
+
}): Promise<ArchiveResult>;
|
|
57
|
+
export declare function restoreOpenclawUserDataArchive(options: {
|
|
58
|
+
archivePath: string;
|
|
59
|
+
now?: Date;
|
|
60
|
+
fsOps?: RestoreFs;
|
|
61
|
+
shellOps?: ShellOps;
|
|
62
|
+
}): Promise<RestoreResult>;
|
|
63
|
+
export {};
|