abtars 0.2.1-alpha.7 → 0.2.1-alpha.9

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
@@ -29,31 +29,28 @@ abTARS (agent brain)
29
29
  ## Quick Start
30
30
 
31
31
  ```bash
32
- npm install -g abtars
33
- abtars init
32
+ npm install -g abtars@alpha abmind@alpha
33
+ abmind install
34
+ abtars install
35
+ abtars update
36
+ abtars onboard
37
+ sudo $(which abtars) daemon install
34
38
  ```
35
39
 
36
- The init wizard walks you through:
37
- 1. Telegram bot token (from [@BotFather](https://t.me/BotFather))
38
- 2. Model provider (kiro-cli, gemini-cli, ollama, or OpenRouter)
39
- 3. Your user ID
40
-
41
- Then start:
42
-
43
- ```bash
44
- abtars start
45
- ```
40
+ Full installation guide: **[docs/wiki/install.md](docs/wiki/install.md)**
46
41
 
47
42
  ## Documentation
48
43
 
49
- Full docs, configuration reference, and guides: **[Wiki](https://github.com/aksika/abtars/wiki)**
44
+ Docs live in the repo at **[docs/wiki/](docs/wiki/)** — always up to date with the code.
50
45
 
51
- - [Installation](https://github.com/aksika/abtars/wiki/Installation)
52
- - [Configuration](https://github.com/aksika/abtars/wiki/Configuration)
53
- - [Commands](https://github.com/aksika/abtars/wiki/Commands)
46
+ - [Installation](docs/wiki/install.md)
47
+ - [Configuration](docs/wiki/commands.md)
48
+ - [Commands](docs/wiki/cli.md)
54
49
  - [Memory System (abmind)](https://github.com/aksika/abmind)
55
- - [Skills & Extensions](https://github.com/aksika/abtars/wiki/Skills)
56
- - [Deployment & Watchdog](https://github.com/aksika/abtars/wiki/Deployment)
50
+ - [Skills & Extensions](docs/wiki/skills.md)
51
+ - [Deployment & Supervision](docs/wiki/supervision.md)
52
+
53
+ > **Note:** The [aksika.github.io](https://aksika.github.io/abtars/) site may be outdated. Always refer to the docs in this repo.
57
54
 
58
55
  ## Supported Transports
59
56
 
@@ -301,112 +301,198 @@ async function uninstall(opts) {
301
301
 
302
302
  // src/cli/commands/backup.ts
303
303
  init_paths();
304
- import { existsSync as existsSync3, mkdirSync, readdirSync as readdirSync2, statSync, renameSync, unlinkSync as unlinkSync3, copyFileSync } from "node:fs";
305
- import { join as join4, dirname } from "node:path";
304
+ import { existsSync as existsSync3, mkdirSync, readdirSync as readdirSync2, statSync, unlinkSync as unlinkSync3, renameSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
305
+ import { join as join4, dirname, basename } from "node:path";
306
306
  import { spawnSync } from "node:child_process";
307
- var AB_SAVE = ["config", "secret", "tasks", "logo", "workspace", "skills/custom", "skills/self"];
307
+ import { createCipheriv, hkdfSync, randomBytes } from "node:crypto";
308
308
  var DEFAULT_PRUNE_DAYS = 7;
309
- async function backup(outputDir, pruneDays) {
309
+ var ABTARS_EXCLUDE = [
310
+ "releases",
311
+ "current",
312
+ "bin",
313
+ "app",
314
+ "logs",
315
+ "node_modules",
316
+ "overflow",
317
+ "browser-socket",
318
+ "bridge.lock",
319
+ "watchdog.lock",
320
+ "browse-spawn.sock",
321
+ "*.sock"
322
+ ];
323
+ var ABMIND_EXCLUDE = [
324
+ "memory/memory.db",
325
+ "lib",
326
+ "node_modules",
327
+ "backups",
328
+ "*.sock",
329
+ "*.db-wal",
330
+ "*.db-shm"
331
+ ];
332
+ var CONFIG_DIRS = ["config", "secret", "tasks", "skills", "core", "agents"];
333
+ async function backup(opts = {}) {
310
334
  const abHome = abtarsHome();
335
+ const abmindHome = process.env["ABMIND_HOME"] ?? join4(dirname(abHome), ".abmind");
311
336
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
312
- const destDir = outputDir ?? join4(dirname(abHome), ".backup-abtars");
337
+ const destDir = opts.outputDir ?? join4(dirname(abHome), ".backup-abtars");
313
338
  mkdirSync(destDir, { recursive: true });
314
- const abmindPaths = [
315
- join4(dirname(abHome), ".abmind", "lib", "node_modules", "abmind", "dist", "cli", "abmind-backup.js"),
316
- join4(dirname(abHome), "workspace", "ab", "abmind", "dist", "cli", "abmind-backup.js")
317
- ];
318
- const abmindBin = abmindPaths.find((p) => existsSync3(p));
319
- let abmResult;
320
- if (abmindBin) {
321
- abmResult = spawnSync("node", [abmindBin], { encoding: "utf-8", env: { ...process.env } });
322
- } else {
323
- abmResult = spawnSync("abmind", ["backup"], { encoding: "utf-8", env: { ...process.env } });
324
- }
325
- if (abmResult.status !== 0) {
326
- process.stderr.write(`\u26A0\uFE0F abmind backup failed: ${abmResult.stderr || abmResult.stdout}
327
- `);
328
- return 1;
329
- }
330
- const abmindBackupsDir = join4(dirname(abHome), ".abmind", "backups");
331
- let abmFile;
332
- if (existsSync3(abmindBackupsDir)) {
333
- const abmFiles = readdirSync2(abmindBackupsDir).filter((f) => f.endsWith(".abm")).sort().reverse();
334
- if (abmFiles.length > 0) abmFile = abmFiles[0];
335
- }
336
- if (abmFile) {
337
- const src = join4(abmindBackupsDir, abmFile);
338
- const dest = join4(destDir, `abmind-${date}.abm`);
339
- renameSync(src, dest);
340
- const size = (statSync(dest).size / 1024).toFixed(0);
341
- process.stdout.write(`\u2713 abmind-${date}.abm (${size}KB, encrypted)
342
- `);
339
+ const isConfig = opts.config === true;
340
+ const prefix = isConfig ? `abtars-config-${date}` : `abtars-${date}`;
341
+ const zipExcludes = [];
342
+ if (isConfig) {
343
343
  } else {
344
- process.stderr.write(`\u26A0\uFE0F abmind backup produced no .abm file
345
- `);
346
- }
347
- const files = [];
348
- for (const dir of AB_SAVE) {
349
- const abs = join4(abHome, dir);
350
- if (existsSync3(abs)) collectDir(abs, dir, files);
351
- }
352
- if (files.length === 0) {
353
- process.stderr.write("Nothing to zip from abtars.\n");
354
- return 1;
355
- }
356
- const tmpDir = join4(process.env["TMPDIR"] ?? "/tmp", `abtars-backup-${Date.now()}`);
357
- mkdirSync(tmpDir, { recursive: true });
358
- for (const f of files) {
359
- const dest = join4(tmpDir, f.zipPath);
360
- mkdirSync(dirname(dest), { recursive: true });
361
- copyFileSync(f.absPath, dest);
344
+ for (const ex of ABTARS_EXCLUDE) {
345
+ zipExcludes.push(`${ex}/*`, ex);
346
+ }
347
+ zipExcludes.push("*.db-wal", "*.db-shm", "*.sock");
362
348
  }
363
- const zipPath = join4(destDir, `abtars-${date}.zip`);
364
349
  const has7z = spawnSync("which", ["7z"], { encoding: "utf-8" }).status === 0;
350
+ const zipExt = has7z ? ".7z" : ".zip";
351
+ let zipPath = join4(destDir, prefix + zipExt);
365
352
  let zipOk;
366
- if (has7z) {
367
- const r = spawnSync("7z", ["a", zipPath.replace(/\.zip$/, ".7z"), "."], { cwd: tmpDir, encoding: "utf-8" });
368
- zipOk = r.status === 0;
353
+ if (isConfig) {
354
+ const existingDirs = CONFIG_DIRS.filter((d) => existsSync3(join4(abHome, d)));
355
+ if (existingDirs.length === 0) {
356
+ process.stderr.write("Nothing to backup \u2014 no config dirs found\n");
357
+ return 1;
358
+ }
359
+ if (has7z) {
360
+ const r = spawnSync("7z", ["a", zipPath, ...existingDirs], { cwd: abHome, encoding: "utf-8" });
361
+ zipOk = r.status === 0;
362
+ } else {
363
+ const r = spawnSync("zip", ["-qr", zipPath, ...existingDirs], { cwd: abHome, encoding: "utf-8" });
364
+ zipOk = r.status === 0;
365
+ }
369
366
  } else {
370
- const r = spawnSync("zip", ["-r", zipPath, "."], { cwd: tmpDir, encoding: "utf-8" });
371
- zipOk = r.status === 0;
367
+ if (has7z) {
368
+ const excludeArgs = ABTARS_EXCLUDE.flatMap((ex) => ["-xr!" + ex]);
369
+ excludeArgs.push("-xr!*.db-wal", "-xr!*.db-shm", "-xr!*.sock");
370
+ const r = spawnSync("7z", ["a", zipPath, ".", ...excludeArgs], { cwd: abHome, encoding: "utf-8" });
371
+ zipOk = r.status === 0;
372
+ } else {
373
+ const excludeArgs = ABTARS_EXCLUDE.flatMap((ex) => ["-x", `${ex}/*`, "-x", ex]);
374
+ excludeArgs.push("-x", "*.db-wal", "-x", "*.db-shm", "-x", "*.sock");
375
+ const r = spawnSync("zip", ["-qr", zipPath, ".", ...excludeArgs], { cwd: abHome, encoding: "utf-8" });
376
+ zipOk = r.status === 0;
377
+ }
378
+ if (zipOk && existsSync3(abmindHome)) {
379
+ if (has7z) {
380
+ const excludeArgs = ABMIND_EXCLUDE.flatMap((ex) => ["-xr!" + ex]);
381
+ const r = spawnSync("7z", ["a", zipPath, ".", ...excludeArgs], { cwd: abmindHome, encoding: "utf-8" });
382
+ zipOk = r.status === 0;
383
+ } else {
384
+ const excludeArgs = ABMIND_EXCLUDE.flatMap((ex) => ["-x", `${ex}/*`, "-x", ex]);
385
+ const r = spawnSync("zip", ["-qr", zipPath, "-g", ".", ...excludeArgs], { cwd: abmindHome, encoding: "utf-8" });
386
+ zipOk = r.status === 0;
387
+ }
388
+ }
389
+ const dbPath = join4(abmindHome, "memory", "memory.db");
390
+ if (zipOk && existsSync3(dbPath)) {
391
+ const tmpDb = join4(process.env["TMPDIR"] ?? "/tmp", `abtars-backup-memory-${Date.now()}.db`);
392
+ const sqliteResult = spawnSync("sqlite3", [dbPath, `.backup '${tmpDb}'`], { encoding: "utf-8" });
393
+ if (sqliteResult.status === 0 && existsSync3(tmpDb)) {
394
+ if (has7z) {
395
+ spawnSync("7z", ["a", zipPath, tmpDb], { encoding: "utf-8" });
396
+ } else {
397
+ spawnSync("zip", ["-qj", zipPath, tmpDb], { encoding: "utf-8" });
398
+ }
399
+ try {
400
+ unlinkSync3(tmpDb);
401
+ } catch {
402
+ }
403
+ }
404
+ }
372
405
  }
373
- spawnSync("rm", ["-rf", tmpDir]);
374
406
  if (!zipOk) {
375
- process.stderr.write(`\u26A0\uFE0F zip/7z failed
376
- `);
407
+ process.stderr.write("Backup zip failed\n");
377
408
  return 1;
378
409
  }
379
- const actualZip = has7z ? zipPath.replace(/\.zip$/, ".7z") : zipPath;
380
- const sizeMb = (statSync(actualZip).size / 1024 / 1024).toFixed(1);
381
- process.stdout.write(`\u2713 ${actualZip.split("/").pop()} (${sizeMb}MB, ${files.length} files)
410
+ if (!isConfig) {
411
+ const actual = statSync(zipPath).size;
412
+ if (actual < 1e5) {
413
+ process.stderr.write(`\u26A0\uFE0F Backup suspiciously small (${actual} bytes)
382
414
  `);
383
- const maxAge = (pruneDays ?? DEFAULT_PRUNE_DAYS) * 864e5;
384
- const now = Date.now();
385
- for (const f of readdirSync2(destDir)) {
386
- if (!(f.startsWith("abtars-") || f.startsWith("abmind-"))) continue;
387
- if (!(f.endsWith(".zip") || f.endsWith(".7z") || f.endsWith(".abm"))) continue;
388
- const fPath = join4(destDir, f);
389
- try {
390
- if (now - statSync(fPath).mtimeMs > maxAge) {
391
- unlinkSync3(fPath);
392
- process.stdout.write(` \u{1F5D1} pruned ${f}
415
+ }
416
+ }
417
+ const zipSize = (statSync(zipPath).size / 1024 / 1024).toFixed(1);
418
+ process.stdout.write(`\u2713 ${basename(zipPath)} (${zipSize}MB)
393
419
  `);
420
+ if (opts.encrypt) {
421
+ const encPath = zipPath + ".enc";
422
+ const ok = encryptFile(zipPath, encPath, abmindHome);
423
+ if (!ok) return 1;
424
+ unlinkSync3(zipPath);
425
+ zipPath = encPath;
426
+ process.stdout.write(`\u2713 encrypted \u2192 ${basename(encPath)}
427
+ `);
428
+ }
429
+ if (!isConfig) {
430
+ const abmResult = runAbmindBackup(abHome, abmindHome);
431
+ if (abmResult) {
432
+ const dest = join4(destDir, `abmind-${date}.abm`);
433
+ renameSync(abmResult, dest);
434
+ const size = (statSync(dest).size / 1024).toFixed(0);
435
+ process.stdout.write(`\u2713 abmind-${date}.abm (${size}KB, encrypted)
436
+ `);
437
+ } else {
438
+ process.stderr.write("\u26A0\uFE0F abmind backup failed or produced no .abm\n");
439
+ }
440
+ }
441
+ const pruneDays = opts.pruneDays ?? DEFAULT_PRUNE_DAYS;
442
+ if (pruneDays > 0) {
443
+ const maxAge = pruneDays * 864e5;
444
+ const now = Date.now();
445
+ for (const f of readdirSync2(destDir)) {
446
+ if (!(f.startsWith("abtars-") || f.startsWith("abmind-"))) continue;
447
+ if (!(f.endsWith(".zip") || f.endsWith(".7z") || f.endsWith(".abm") || f.endsWith(".enc"))) continue;
448
+ const fPath = join4(destDir, f);
449
+ try {
450
+ if (now - statSync(fPath).mtimeMs > maxAge) {
451
+ unlinkSync3(fPath);
452
+ process.stdout.write(` \u{1F5D1} pruned ${f}
453
+ `);
454
+ }
455
+ } catch {
394
456
  }
395
- } catch {
396
457
  }
397
458
  }
398
459
  return 0;
399
460
  }
400
- function collectDir(dir, prefix, out) {
401
- for (const entry of readdirSync2(dir, { withFileTypes: true })) {
402
- const abs = join4(dir, entry.name);
403
- const rel = `${prefix}/${entry.name}`;
404
- if (entry.isDirectory()) {
405
- collectDir(abs, rel, out);
406
- } else if (entry.isFile()) {
407
- out.push({ absPath: abs, zipPath: rel });
408
- }
461
+ function runAbmindBackup(abHome, abmindHome) {
462
+ const abmindPaths = [
463
+ join4(dirname(abHome), "workspace", "ab", "abmind", "dist", "cli", "abmind-backup.js"),
464
+ join4(abmindHome, "lib", "node_modules", "abmind", "dist", "cli", "abmind-backup.js")
465
+ ];
466
+ const abmindBin = abmindPaths.find((p) => existsSync3(p));
467
+ let result;
468
+ if (abmindBin) {
469
+ result = spawnSync("node", [abmindBin], { encoding: "utf-8", env: { ...process.env } });
470
+ } else {
471
+ result = spawnSync("abmind", ["backup"], { encoding: "utf-8", env: { ...process.env } });
409
472
  }
473
+ if (result.status !== 0) return null;
474
+ const backupsDir = join4(abmindHome, "backups");
475
+ if (!existsSync3(backupsDir)) return null;
476
+ const abmFiles = readdirSync2(backupsDir).filter((f) => f.endsWith(".abm")).sort().reverse();
477
+ return abmFiles[0] ? join4(backupsDir, abmFiles[0]) : null;
478
+ }
479
+ function encryptFile(inputPath, outputPath, abmindHome) {
480
+ const keyPath = join4(abmindHome, "secret", "abmind.key");
481
+ if (!existsSync3(keyPath)) {
482
+ process.stderr.write(`\u26A0\uFE0F --encrypt requires ${keyPath}
483
+ `);
484
+ return false;
485
+ }
486
+ const master = Buffer.from(readFileSync2(keyPath, "utf-8").trim(), "hex");
487
+ const key = Buffer.from(hkdfSync("sha256", master, "", "abtars-backup-v1", 32));
488
+ const iv = randomBytes(12);
489
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
490
+ const input = readFileSync2(inputPath);
491
+ const encrypted = Buffer.concat([cipher.update(input), cipher.final()]);
492
+ const tag = cipher.getAuthTag();
493
+ const out = Buffer.concat([iv, encrypted, tag]);
494
+ writeFileSync(outputPath, out);
495
+ return true;
410
496
  }
411
497
 
412
498
  // src/cli/commands/onboard.ts
@@ -417,7 +503,7 @@ import { homedir as homedir2 } from "node:os";
417
503
  import { fileURLToPath } from "node:url";
418
504
 
419
505
  // src/components/hints.ts
420
- import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync, renameSync as renameSync2 } from "node:fs";
506
+ import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync2 } from "node:fs";
421
507
  import { join as join5 } from "node:path";
422
508
  function manifestPath() {
423
509
  const home = process.env["ABTARS_HOME"] ?? join5(process.env["HOME"] ?? "", ".abtars");
@@ -427,7 +513,7 @@ function readManifest2() {
427
513
  const path = manifestPath();
428
514
  if (!existsSync4(path)) return {};
429
515
  try {
430
- return JSON.parse(readFileSync2(path, "utf-8"));
516
+ return JSON.parse(readFileSync3(path, "utf-8"));
431
517
  } catch {
432
518
  return {};
433
519
  }
@@ -435,7 +521,7 @@ function readManifest2() {
435
521
  function writeManifestAtomic(data) {
436
522
  const path = manifestPath();
437
523
  const tmp = path + ".tmp";
438
- writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n");
524
+ writeFileSync2(tmp, JSON.stringify(data, null, 2) + "\n");
439
525
  renameSync2(tmp, path);
440
526
  }
441
527
  function showHintOnce(id, text) {
@@ -1209,7 +1295,7 @@ Rollback complete.
1209
1295
 
1210
1296
  // src/cli/commands/status.ts
1211
1297
  import { existsSync as existsSync6 } from "node:fs";
1212
- import { readFileSync as readFileSync3 } from "node:fs";
1298
+ import { readFileSync as readFileSync4 } from "node:fs";
1213
1299
  import { join as join8 } from "node:path";
1214
1300
  async function status() {
1215
1301
  const paths = packagePaths("abtars");
@@ -1239,7 +1325,7 @@ Run 'abtars install' to set up.
1239
1325
  ` host: ${manifest.host}`
1240
1326
  ];
1241
1327
  try {
1242
- const bridgeLock = JSON.parse(readFileSync3(join8(paths.home, "bridge.lock"), "utf-8"));
1328
+ const bridgeLock = JSON.parse(readFileSync4(join8(paths.home, "bridge.lock"), "utf-8"));
1243
1329
  if (bridgeLock.pid) {
1244
1330
  const alive = (() => {
1245
1331
  try {
@@ -1280,7 +1366,7 @@ Run 'abtars install' to set up.
1280
1366
  // src/cli/commands/update.ts
1281
1367
  import { hostname } from "node:os";
1282
1368
  import { join as join11 } from "node:path";
1283
- import { readFileSync as readFileSync5, existsSync as existsSync9 } from "node:fs";
1369
+ import { readFileSync as readFileSync6, existsSync as existsSync9 } from "node:fs";
1284
1370
  import { copyFile as copyFile2, mkdir as mkdir4, chmod, readdir } from "node:fs/promises";
1285
1371
  import { rmSync as rmSync3, cpSync, readdirSync as readdirSync3, mkdirSync as mkdirSync2 } from "node:fs";
1286
1372
 
@@ -1411,7 +1497,7 @@ function makeLocalBuildSource(opts = {}) {
1411
1497
 
1412
1498
  // src/cli/update-sources/npm.ts
1413
1499
  import { spawnSync as spawnSync3 } from "node:child_process";
1414
- import { existsSync as existsSync8, readFileSync as readFileSync4, unlinkSync as unlinkSync4 } from "node:fs";
1500
+ import { existsSync as existsSync8, readFileSync as readFileSync5, unlinkSync as unlinkSync4 } from "node:fs";
1415
1501
  import { mkdir as mkdir3, rm as rm2 } from "node:fs/promises";
1416
1502
  import { join as join10 } from "node:path";
1417
1503
  var TIMEOUT_MS = 6e4;
@@ -1423,7 +1509,7 @@ function run(cmd, args, cwd) {
1423
1509
  }
1424
1510
  function readLocalVersion(home) {
1425
1511
  try {
1426
- const pkg = JSON.parse(readFileSync4(join10(home, "app", "package.json"), "utf-8"));
1512
+ const pkg = JSON.parse(readFileSync5(join10(home, "app", "package.json"), "utf-8"));
1427
1513
  return pkg.version ?? null;
1428
1514
  } catch {
1429
1515
  return null;
@@ -1455,7 +1541,7 @@ function makeNpmSource(packageName) {
1455
1541
  // src/cli/commands/update.ts
1456
1542
  function readJsonField2(file, field) {
1457
1543
  try {
1458
- return JSON.parse(readFileSync5(file, "utf-8"))[field];
1544
+ return JSON.parse(readFileSync6(file, "utf-8"))[field];
1459
1545
  } catch {
1460
1546
  return void 0;
1461
1547
  }
@@ -1522,12 +1608,12 @@ Use --source local (default) or --source npm.
1522
1608
  {
1523
1609
  const pkgPath = join11(staged.stagedPath, "package.json");
1524
1610
  try {
1525
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
1611
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
1526
1612
  const externals = { patchright: "^1.59.4", "rettiwt-api": "^4.1.3" };
1527
1613
  pkg.dependencies = { ...pkg.dependencies, ...externals };
1528
1614
  if (pkg.dependencies?.abmind?.startsWith("file:")) delete pkg.dependencies.abmind;
1529
- const { writeFileSync: writeFileSync2 } = await import("node:fs");
1530
- writeFileSync2(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
1615
+ const { writeFileSync: writeFileSync3 } = await import("node:fs");
1616
+ writeFileSync3(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
1531
1617
  const { execSync } = await import("node:child_process");
1532
1618
  execSync("npm install --omit=dev --ignore-scripts 2>/dev/null", { cwd: staged.stagedPath, timeout: 6e4 });
1533
1619
  process.stdout.write(`\u2713 external deps installed
@@ -1700,7 +1786,7 @@ async function postSwapHousekeeping(paths, repoRoot, _staged) {
1700
1786
  const transportJson = join11(paths.home, "config", "transport.json");
1701
1787
  if (existsSync9(transportJson)) {
1702
1788
  try {
1703
- const tc = JSON.parse(readFileSync5(transportJson, "utf-8"));
1789
+ const tc = JSON.parse(readFileSync6(transportJson, "utf-8"));
1704
1790
  let cleared = false;
1705
1791
  for (const agent of Object.values(tc.agents ?? {})) {
1706
1792
  if (agent.demoted) {
@@ -1719,8 +1805,8 @@ async function postSwapHousekeeping(paths, repoRoot, _staged) {
1719
1805
  }
1720
1806
  }
1721
1807
  if (cleared) {
1722
- const { writeFileSync: writeFileSync2 } = await import("node:fs");
1723
- writeFileSync2(transportJson, JSON.stringify(tc, null, 2) + "\n");
1808
+ const { writeFileSync: writeFileSync3 } = await import("node:fs");
1809
+ writeFileSync3(transportJson, JSON.stringify(tc, null, 2) + "\n");
1724
1810
  }
1725
1811
  } catch {
1726
1812
  }
@@ -1858,8 +1944,8 @@ Usage:
1858
1944
  abtars uninstall [--yes]
1859
1945
  abtars update [--source local|npm|github] [--from-local]
1860
1946
  abtars rollback [--to <version>]
1861
- abtars backup
1862
- abtars restore <file.zip|.7z>
1947
+ abtars backup [--config] [--encrypt] [--output <dir>] [--prune-days N]
1948
+ abtars restore <file.zip|.7z|.abm|.enc> [--config] [--passphrase <p>]
1863
1949
  abtars doctor [<args passed to doctor.sh>...]
1864
1950
  abtars onboard [--non-interactive --accept-risk --telegram-token ... --telegram-chat-id ...]
1865
1951
  abtars restart [--cold]
@@ -1893,10 +1979,18 @@ async function main(argv) {
1893
1979
  case "rollback":
1894
1980
  return await rollback();
1895
1981
  case "backup":
1896
- return await backup(typeof flags.get("output") === "string" ? flags.get("output") : void 0);
1982
+ return await backup({
1983
+ config: flags.get("config") === true,
1984
+ encrypt: flags.get("encrypt") === true,
1985
+ outputDir: typeof flags.get("output") === "string" ? flags.get("output") : void 0,
1986
+ pruneDays: typeof flags.get("prune-days") === "string" ? Number(flags.get("prune-days")) : void 0
1987
+ });
1897
1988
  case "restore": {
1898
- const { restore } = await import("./restore-ROJF22R2.js");
1899
- return await restore(argv[1] ?? "");
1989
+ const { restore } = await import("./restore-MFSW3EBL.js");
1990
+ return await restore(argv[1] ?? "", {
1991
+ config: flags.get("config") === true,
1992
+ passphrase: typeof flags.get("passphrase") === "string" ? flags.get("passphrase") : void 0
1993
+ });
1900
1994
  }
1901
1995
  case "doctor":
1902
1996
  return await doctor(argv.slice(1).filter((a) => a !== ""));