@remnic/core 9.3.548 → 9.3.550

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.
@@ -29,6 +29,7 @@ interface RollbackManifestEntry {
29
29
  targetPath: string;
30
30
  backupPath?: string;
31
31
  createdByMigration?: boolean;
32
+ contentHash?: string;
32
33
  }
33
34
 
34
35
  interface RollbackManifest {
@@ -37,6 +38,12 @@ interface RollbackManifest {
37
38
  entries: RollbackManifestEntry[];
38
39
  }
39
40
 
41
+ interface ValidatedRollbackManifestEntry extends RollbackManifestEntry {
42
+ targetPath: string;
43
+ backupPath?: string;
44
+ contentHash?: string;
45
+ }
46
+
40
47
  export interface MigrationOptions {
41
48
  connectorConfigPaths?: string[];
42
49
  cwd?: string;
@@ -134,6 +141,14 @@ function defaultRollbackCommand(): string {
134
141
  return "remnic migrate --rollback";
135
142
  }
136
143
 
144
+ function resolveMigrationCwd(options?: MigrationOptions): string {
145
+ return path.resolve(options?.cwd ?? process.cwd());
146
+ }
147
+
148
+ function resolveConnectorConfigPath(candidate: string, cwd: string): string {
149
+ return path.isAbsolute(candidate) ? path.resolve(candidate) : path.resolve(cwd, candidate);
150
+ }
151
+
137
152
  async function ensureParent(filePath: string): Promise<void> {
138
153
  await mkdir(path.dirname(filePath), { recursive: true });
139
154
  }
@@ -147,6 +162,10 @@ async function writeOwnerOnlyFile(filePath: string, content: string): Promise<vo
147
162
  await chmod(filePath, TOKEN_STORE_MODE);
148
163
  }
149
164
 
165
+ async function fileContentHash(filePath: string): Promise<string> {
166
+ return createHash("sha256").update(await readFile(filePath)).digest("hex");
167
+ }
168
+
150
169
  async function writeTokenStoreFile(filePath: string, content: string): Promise<void> {
151
170
  await writeOwnerOnlyFile(filePath, content);
152
171
  }
@@ -273,6 +292,221 @@ function isPlainJsonObject(value: unknown): value is Record<string, unknown> {
273
292
  return typeof value === "object" && value !== null && !Array.isArray(value);
274
293
  }
275
294
 
295
+ function parseRollbackManifestEntry(raw: unknown, index: number): RollbackManifestEntry {
296
+ if (!isPlainJsonObject(raw)) {
297
+ throw new Error(`rollback manifest entry ${index} must be an object`);
298
+ }
299
+ if (typeof raw.targetPath !== "string" || raw.targetPath.length === 0 || !path.isAbsolute(raw.targetPath)) {
300
+ throw new Error(`rollback manifest entry ${index} has an invalid targetPath`);
301
+ }
302
+ if (raw.backupPath !== undefined && (typeof raw.backupPath !== "string" || raw.backupPath.length === 0 || !path.isAbsolute(raw.backupPath))) {
303
+ throw new Error(`rollback manifest entry ${index} has an invalid backupPath`);
304
+ }
305
+ if (raw.createdByMigration !== undefined && typeof raw.createdByMigration !== "boolean") {
306
+ throw new Error(`rollback manifest entry ${index} has an invalid createdByMigration flag`);
307
+ }
308
+ if (raw.contentHash !== undefined && (typeof raw.contentHash !== "string" || !/^[a-f0-9]{64}$/u.test(raw.contentHash))) {
309
+ throw new Error(`rollback manifest entry ${index} has an invalid contentHash`);
310
+ }
311
+ return {
312
+ targetPath: raw.targetPath,
313
+ ...(raw.backupPath === undefined ? {} : { backupPath: raw.backupPath }),
314
+ ...(raw.createdByMigration === undefined ? {} : { createdByMigration: raw.createdByMigration }),
315
+ ...(raw.contentHash === undefined ? {} : { contentHash: raw.contentHash }),
316
+ };
317
+ }
318
+
319
+ function parseRollbackManifest(raw: unknown, manifestPath: string): RollbackManifest {
320
+ if (!isPlainJsonObject(raw)) {
321
+ throw new Error(`rollback manifest must be an object: ${manifestPath}`);
322
+ }
323
+ if (raw.version !== 1) {
324
+ throw new Error(`rollback manifest has unsupported version: ${manifestPath}`);
325
+ }
326
+ if (typeof raw.createdAt !== "string") {
327
+ throw new Error(`rollback manifest has an invalid createdAt: ${manifestPath}`);
328
+ }
329
+ if (!Array.isArray(raw.entries)) {
330
+ throw new Error(`rollback manifest entries must be an array: ${manifestPath}`);
331
+ }
332
+ return {
333
+ version: 1,
334
+ createdAt: raw.createdAt,
335
+ entries: raw.entries.map(parseRollbackManifestEntry),
336
+ };
337
+ }
338
+
339
+ function isPathInside(parentPath: string, candidatePath: string): boolean {
340
+ const relative = path.relative(path.resolve(parentPath), path.resolve(candidatePath));
341
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
342
+ }
343
+
344
+ function isPathDescendant(parentPath: string, candidatePath: string): boolean {
345
+ const relative = path.relative(path.resolve(parentPath), path.resolve(candidatePath));
346
+ return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
347
+ }
348
+
349
+ function hasConnectorConfigShape(targetPath: string, homeDir: string): boolean {
350
+ const relative = path.relative(path.resolve(homeDir), path.resolve(targetPath));
351
+ if (relative === ".claude.json" || relative === path.join(".claude", ".mcp.json")) {
352
+ return true;
353
+ }
354
+
355
+ return hasRepoConnectorConfigShape(relative);
356
+ }
357
+
358
+ function hasRepoConnectorConfigShape(relativePath: string): boolean {
359
+ const parts = relativePath.split(path.sep);
360
+ const last = parts.at(-1);
361
+ const packageName = parts.at(-2);
362
+ const packagesDir = parts.at(-3);
363
+ return last === ".mcp.json" &&
364
+ packagesDir === "packages" &&
365
+ (packageName === "plugin-claude-code" || packageName === "plugin-codex");
366
+ }
367
+
368
+ function connectorBackupPathForTarget(targetPath: string, homeDir: string): string {
369
+ const digest = createHash("sha256").update(targetPath).digest("hex").slice(0, 12);
370
+ return path.join(backupRoot(homeDir), "mcp", `${digest}.json`);
371
+ }
372
+
373
+ function isRollbackTargetAllowed(
374
+ entry: RollbackManifestEntry,
375
+ targetPath: string,
376
+ homeDir: string,
377
+ options?: MigrationOptions,
378
+ ): boolean {
379
+ const resolvedTarget = path.resolve(targetPath);
380
+ if (isPathDescendant(remnicRoot(homeDir), resolvedTarget)) {
381
+ if (entry.createdByMigration && !entry.backupPath) return true;
382
+ return Boolean(entry.backupPath) && isRemnicTokenStorePath(resolvedTarget, homeDir);
383
+ }
384
+ if (isPathDescendant(path.join(homeDir, ".config", "remnic"), resolvedTarget)) {
385
+ return entry.createdByMigration === true && !entry.backupPath;
386
+ }
387
+
388
+ const serviceTargets = new Set([
389
+ path.resolve(path.join(homeDir, "Library", "LaunchAgents", "ai.remnic.daemon.plist")),
390
+ path.resolve(path.join(homeDir, ".config", "systemd", "user", "remnic.service")),
391
+ ]);
392
+ if (serviceTargets.has(resolvedTarget)) return true;
393
+
394
+ const cwd = resolveMigrationCwd(options);
395
+ const allowedConnectorPaths = new Set(
396
+ [
397
+ ...defaultConnectorConfigPaths(homeDir, cwd),
398
+ ...(options?.connectorConfigPaths ?? []),
399
+ ].map((candidate) => resolveConnectorConfigPath(candidate, cwd)),
400
+ );
401
+ if (allowedConnectorPaths.has(resolvedTarget)) return true;
402
+
403
+ return isPathInside(homeDir, resolvedTarget) && hasConnectorConfigShape(resolvedTarget, homeDir);
404
+ }
405
+
406
+ function isRollbackBackupAllowed(backupPath: string, homeDir: string): boolean {
407
+ return isPathInside(backupRoot(homeDir), backupPath);
408
+ }
409
+
410
+ async function assertNoSymlinkPathSegments(filePath: string, trustedRoot: string, label: string): Promise<void> {
411
+ const resolvedPath = path.resolve(filePath);
412
+ const resolvedRoot = path.resolve(trustedRoot);
413
+ if (!isPathInside(resolvedRoot, resolvedPath)) {
414
+ throw new Error(`${label} is outside the trusted rollback root: ${filePath}`);
415
+ }
416
+ const segments = path.relative(resolvedRoot, resolvedPath).split(path.sep).filter(Boolean);
417
+ let current = resolvedRoot;
418
+
419
+ for (const [index, segment] of segments.entries()) {
420
+ current = path.join(current, segment);
421
+ try {
422
+ const currentStat = await lstat(current);
423
+ if (currentStat.isSymbolicLink()) {
424
+ throw new Error(`${label} must not contain symlink segments: ${filePath}`);
425
+ }
426
+ } catch (error) {
427
+ if ((error as NodeJS.ErrnoException).code === "ENOENT" && index === segments.length - 1) return;
428
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") {
429
+ throw new Error(`${label} must not contain missing parent segments: ${filePath}`);
430
+ }
431
+ throw error;
432
+ }
433
+ }
434
+ }
435
+
436
+ function rollbackTargetSymlinkRoot(targetPath: string, homeDir: string, options?: MigrationOptions): string {
437
+ if (isPathInside(homeDir, targetPath)) return homeDir;
438
+
439
+ const cwd = resolveMigrationCwd(options);
440
+ if (isPathInside(cwd, targetPath)) return cwd;
441
+
442
+ return path.parse(targetPath).root;
443
+ }
444
+
445
+ async function validateRollbackManifestEntries(
446
+ manifest: RollbackManifest,
447
+ homeDir: string,
448
+ options?: MigrationOptions,
449
+ ): Promise<ValidatedRollbackManifestEntry[]> {
450
+ const validated: ValidatedRollbackManifestEntry[] = [];
451
+
452
+ for (const entry of manifest.entries) {
453
+ const targetPath = path.resolve(entry.targetPath);
454
+ if (!isRollbackTargetAllowed(entry, targetPath, homeDir, options)) {
455
+ throw new Error(`rollback manifest target is outside migration-owned paths: ${entry.targetPath}`);
456
+ }
457
+ if (entry.backupPath && entry.createdByMigration) {
458
+ throw new Error(`rollback manifest entry cannot restore and remove the same target: ${entry.targetPath}`);
459
+ }
460
+ const targetExists = await pathExistsNoFollow(targetPath);
461
+ if (!entry.createdByMigration || targetExists) {
462
+ const targetSymlinkRoot = rollbackTargetSymlinkRoot(targetPath, homeDir, options);
463
+ await assertNoSymlinkPathSegments(targetPath, targetSymlinkRoot, "rollback manifest target");
464
+ }
465
+ if (entry.createdByMigration && targetExists) {
466
+ await assertCreatedRollbackTargetMatchesRecord(entry, targetPath);
467
+ }
468
+
469
+ let backupPath: string | undefined;
470
+ if (entry.backupPath) {
471
+ backupPath = path.resolve(entry.backupPath);
472
+ if (!isRollbackBackupAllowed(backupPath, homeDir)) {
473
+ throw new Error(`rollback manifest backup is outside migration backup storage: ${entry.backupPath}`);
474
+ }
475
+ if (await pathExistsNoFollow(backupPath)) {
476
+ await assertNoSymlinkPathSegments(backupPath, homeDir, "rollback manifest backup");
477
+ await assertExistingRegularFileNoFollow(backupPath, "rollback manifest backup");
478
+ }
479
+ if (backupPath !== connectorBackupPathForTarget(targetPath, homeDir)) {
480
+ throw new Error(`rollback manifest backup does not match target: ${entry.targetPath}`);
481
+ }
482
+ }
483
+
484
+ validated.push({
485
+ targetPath,
486
+ ...(backupPath === undefined ? {} : { backupPath }),
487
+ ...(entry.createdByMigration === undefined ? {} : { createdByMigration: entry.createdByMigration }),
488
+ ...(entry.contentHash === undefined ? {} : { contentHash: entry.contentHash }),
489
+ });
490
+ }
491
+
492
+ return validated;
493
+ }
494
+
495
+ async function assertCreatedRollbackTargetMatchesRecord(
496
+ entry: RollbackManifestEntry,
497
+ targetPath: string,
498
+ ): Promise<boolean> {
499
+ const targetStat = await lstat(targetPath);
500
+ if (targetStat.isDirectory()) {
501
+ throw new Error(`rollback manifest created target must be a file path: ${entry.targetPath}`);
502
+ }
503
+ if (!targetStat.isFile() || !entry.contentHash) return false;
504
+ if (await fileContentHash(targetPath) !== entry.contentHash) {
505
+ throw new Error(`rollback manifest created target content does not match migration record: ${entry.targetPath}`);
506
+ }
507
+ return true;
508
+ }
509
+
276
510
  async function rewriteTokensIfPresent(filePath: string): Promise<number> {
277
511
  if (!existsSync(filePath)) return 0;
278
512
  await assertExistingRegularFileNoFollow(filePath, "Remnic token store");
@@ -461,8 +695,7 @@ async function backupFile(
461
695
  if (manifest.entries.some((entry) => entry.targetPath === targetPath && entry.backupPath)) {
462
696
  return;
463
697
  }
464
- const digest = createHash("sha256").update(targetPath).digest("hex").slice(0, 12);
465
- const backupPath = path.join(backupRoot(homeDir), "mcp", `${digest}.json`);
698
+ const backupPath = connectorBackupPathForTarget(targetPath, homeDir);
466
699
  await ensureParent(backupPath);
467
700
  if (isRemnicTokenStorePath(targetPath, homeDir)) {
468
701
  await writeOwnerOnlyFile(backupPath, originalContent);
@@ -481,7 +714,24 @@ async function recordCreatedPath(
481
714
  persistManifest?: PersistRollbackManifest,
482
715
  ): Promise<void> {
483
716
  if (manifest.entries.some((entry) => entry.targetPath === filePath)) return;
484
- manifest.entries.push({ targetPath: filePath, createdByMigration: true });
717
+ manifest.entries.push({
718
+ targetPath: filePath,
719
+ createdByMigration: true,
720
+ contentHash: await fileContentHash(filePath),
721
+ });
722
+ await persistManifest?.();
723
+ }
724
+
725
+ async function refreshCreatedPathHash(
726
+ filePath: string,
727
+ manifest: RollbackManifest,
728
+ persistManifest?: PersistRollbackManifest,
729
+ ): Promise<void> {
730
+ const entry = manifest.entries.find((candidate) =>
731
+ candidate.targetPath === filePath && candidate.createdByMigration
732
+ );
733
+ if (!entry) return;
734
+ entry.contentHash = await fileContentHash(filePath);
485
735
  await persistManifest?.();
486
736
  }
487
737
 
@@ -504,8 +754,9 @@ async function updateConnectorConfigs(
504
754
  const updated: string[] = [];
505
755
  const candidates = options?.connectorConfigPaths ?? defaultConnectorConfigPaths(homeDir, cwd);
506
756
  for (const targetPath of candidates) {
507
- if (await rewriteJsonFile(targetPath, homeDir, manifest, persistManifest)) {
508
- updated.push(targetPath);
757
+ const resolvedTarget = resolveConnectorConfigPath(targetPath, cwd);
758
+ if (await rewriteJsonFile(resolvedTarget, homeDir, manifest, persistManifest)) {
759
+ updated.push(resolvedTarget);
509
760
  }
510
761
  }
511
762
  return updated;
@@ -616,12 +867,26 @@ async function writeRollbackManifest(homeDir: string, manifest: RollbackManifest
616
867
 
617
868
  async function readRollbackManifest(homeDir: string): Promise<RollbackManifest | null> {
618
869
  const target = rollbackManifestPath(homeDir);
619
- if (!existsSync(target)) return null;
870
+ let targetStat: Awaited<ReturnType<typeof lstat>>;
871
+ try {
872
+ targetStat = await lstat(target);
873
+ } catch (error) {
874
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
875
+ throw error;
876
+ }
877
+ if (targetStat.isSymbolicLink()) {
878
+ throw new Error(`rollback manifest must not be a symlink: ${target}`);
879
+ }
880
+ if (!targetStat.isFile()) {
881
+ throw new Error(`rollback manifest must be a regular file: ${target}`);
882
+ }
883
+ let parsed: unknown;
620
884
  try {
621
- return JSON.parse(await readFile(target, "utf8")) as RollbackManifest;
885
+ parsed = JSON.parse(await readFile(target, "utf8")) as unknown;
622
886
  } catch {
623
887
  return null;
624
888
  }
889
+ return parseRollbackManifest(parsed, target);
625
890
  }
626
891
 
627
892
  async function acquireLock(homeDir: string): Promise<() => Promise<void>> {
@@ -699,6 +964,7 @@ export async function rollbackFromEngramMigration(options?: MigrationOptions): P
699
964
  const removed: string[] = [];
700
965
 
701
966
  if (!manifest) return { restored, removed };
967
+ const entries = await validateRollbackManifestEntries(manifest, homeDir, options);
702
968
 
703
969
  if (platform === "darwin") {
704
970
  const remnicPlist = path.join(homeDir, "Library", "LaunchAgents", "ai.remnic.daemon.plist");
@@ -718,8 +984,10 @@ export async function rollbackFromEngramMigration(options?: MigrationOptions): P
718
984
  }
719
985
  }
720
986
 
721
- for (const entry of [...manifest.entries].reverse()) {
722
- if (entry.backupPath && existsSync(entry.backupPath)) {
987
+ for (const entry of [...entries].reverse()) {
988
+ if (entry.backupPath && await pathExistsNoFollow(entry.backupPath)) {
989
+ await assertNoSymlinkPathSegments(entry.backupPath, homeDir, "rollback manifest backup");
990
+ await assertExistingRegularFileNoFollow(entry.backupPath, "rollback manifest backup");
723
991
  await ensureParent(entry.targetPath);
724
992
  await copyFile(entry.backupPath, entry.targetPath);
725
993
  if (isRemnicTokenStorePath(entry.targetPath, homeDir)) {
@@ -729,6 +997,9 @@ export async function rollbackFromEngramMigration(options?: MigrationOptions): P
729
997
  continue;
730
998
  }
731
999
  if (entry.createdByMigration && existsSync(entry.targetPath)) {
1000
+ const targetSymlinkRoot = rollbackTargetSymlinkRoot(entry.targetPath, homeDir, options);
1001
+ await assertNoSymlinkPathSegments(entry.targetPath, targetSymlinkRoot, "rollback manifest target");
1002
+ if (!await assertCreatedRollbackTargetMatchesRecord(entry, entry.targetPath)) continue;
732
1003
  await rm(entry.targetPath, { recursive: true, force: true });
733
1004
  removed.push(entry.targetPath);
734
1005
  }
@@ -749,7 +1020,7 @@ export async function rollbackFromEngramMigration(options?: MigrationOptions): P
749
1020
 
750
1021
  export async function migrateFromEngram(options?: MigrationOptions): Promise<MigrationResult> {
751
1022
  const homeDir = resolveMigrationHome(options);
752
- const cwd = options?.cwd ?? process.cwd();
1023
+ const cwd = resolveMigrationCwd(options);
753
1024
  const logger = resolveLogger(options);
754
1025
  const copied: string[] = [];
755
1026
  let tokensRegenerated = 0;
@@ -806,6 +1077,7 @@ export async function migrateFromEngram(options?: MigrationOptions): Promise<Mig
806
1077
  const remnicTokens = path.join(remnicRoot(homeDir), "tokens.json");
807
1078
  if (copied.includes(remnicTokens)) {
808
1079
  tokensRegenerated += await rewriteTokensIfPresent(remnicTokens);
1080
+ await refreshCreatedPathHash(remnicTokens, manifest, persistManifest);
809
1081
  } else {
810
1082
  tokensRegenerated += await mergeLegacyTokens(
811
1083
  legacyTokens,
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/migrate/from-engram.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport {\n chmod,\n copyFile,\n lstat,\n mkdir,\n open,\n readFile,\n readdir,\n rm,\n stat,\n unlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { resolveHomeDir } from \"../runtime/env.js\";\nimport { launchProcessSync } from \"../runtime/child-process.js\";\n\nexport interface MigrationResult {\n status: \"fresh-install\" | \"already-migrated\" | \"migrated\";\n copied: string[];\n tokensRegenerated: number;\n servicesReinstalled: string[];\n rollbackCommand: string;\n}\n\ninterface RollbackManifestEntry {\n targetPath: string;\n backupPath?: string;\n createdByMigration?: boolean;\n}\n\ninterface RollbackManifest {\n version: 1;\n createdAt: string;\n entries: RollbackManifestEntry[];\n}\n\nexport interface MigrationOptions {\n connectorConfigPaths?: string[];\n cwd?: string;\n execCommand?: (command: string, args: string[]) => void;\n homeDir?: string;\n logger?: (message: string) => void;\n platform?: NodeJS.Platform;\n quiet?: boolean;\n}\n\nexport interface RollbackResult {\n removed: string[];\n restored: string[];\n}\n\ninterface TokenEntry {\n connector: string;\n createdAt: string;\n token: string;\n}\n\ntype PersistRollbackManifest = () => Promise<void>;\n\nconst MARKER_FILE = \".migrated-from-engram\";\nconst LOCK_FILE = \".migration.lock\";\nconst ROLLBACK_MANIFEST = \".rollback.json\";\nconst BACKUP_DIR = \".backup\";\nconst LOCK_RETRY_MS = 100;\nconst LOCK_TIMEOUT_MS = 5_000;\nconst TOKEN_STORE_MODE = 0o600;\n\nfunction resolvePlatform(options?: MigrationOptions): NodeJS.Platform {\n return options?.platform ?? process.platform;\n}\n\nfunction resolveMigrationHome(options?: MigrationOptions): string {\n return options?.homeDir ?? resolveHomeDir();\n}\n\nfunction resolveLogger(options?: MigrationOptions): (message: string) => void {\n const sink = options?.logger ?? ((message: string) => console.log(message));\n return (message: string) => {\n if (!options?.quiet) sink(`[remnic] ${message}`);\n };\n}\n\nfunction resolveExec(options?: MigrationOptions): (command: string, args: string[]) => void {\n return options?.execCommand ?? ((command: string, args: string[]) => {\n const result = launchProcessSync(command, args, { stdio: \"ignore\" });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n const reason = result.status === null\n ? `signal ${result.signal ?? \"unknown\"}`\n : `exit code ${result.status}`;\n throw new Error(`migration command failed: ${command} ${args.join(\" \")} (${reason})`);\n }\n });\n}\n\nfunction remnicRoot(homeDir: string): string {\n return path.join(homeDir, \".remnic\");\n}\n\nfunction legacyRoot(homeDir: string): string {\n return path.join(homeDir, \".engram\");\n}\n\nfunction legacyConfigPath(homeDir: string): string {\n return path.join(homeDir, \".config\", \"engram\", \"config.json\");\n}\n\nfunction remnicConfigPath(homeDir: string): string {\n return path.join(homeDir, \".config\", \"remnic\", \"config.json\");\n}\n\nfunction markerPath(homeDir: string): string {\n return path.join(remnicRoot(homeDir), MARKER_FILE);\n}\n\nfunction lockPath(homeDir: string): string {\n return path.join(remnicRoot(homeDir), LOCK_FILE);\n}\n\nfunction rollbackManifestPath(homeDir: string): string {\n return path.join(remnicRoot(homeDir), ROLLBACK_MANIFEST);\n}\n\nfunction backupRoot(homeDir: string): string {\n return path.join(remnicRoot(homeDir), BACKUP_DIR);\n}\n\nfunction defaultRollbackCommand(): string {\n return \"remnic migrate --rollback\";\n}\n\nasync function ensureParent(filePath: string): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true });\n}\n\nasync function secureTokenFilePermissions(filePath: string): Promise<void> {\n await chmod(filePath, TOKEN_STORE_MODE);\n}\n\nasync function writeOwnerOnlyFile(filePath: string, content: string): Promise<void> {\n await writeFile(filePath, content, { encoding: \"utf8\", mode: TOKEN_STORE_MODE });\n await chmod(filePath, TOKEN_STORE_MODE);\n}\n\nasync function writeTokenStoreFile(filePath: string, content: string): Promise<void> {\n await writeOwnerOnlyFile(filePath, content);\n}\n\nfunction isRemnicTokenStorePath(filePath: string, homeDir: string): boolean {\n return path.resolve(filePath) === path.resolve(path.join(remnicRoot(homeDir), \"tokens.json\"));\n}\n\nasync function pathExistsNoFollow(filePath: string): Promise<boolean> {\n try {\n await lstat(filePath);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n}\n\nasync function assertExistingRegularFileNoFollow(filePath: string, label: string): Promise<void> {\n const fileStat = await lstat(filePath);\n if (fileStat.isSymbolicLink()) {\n throw new Error(`${label} must not be a symlink: ${filePath}`);\n }\n if (!fileStat.isFile()) {\n throw new Error(`${label} must be a regular file: ${filePath}`);\n }\n}\n\nasync function isExistingRegularFileNoFollow(filePath: string): Promise<boolean> {\n try {\n const fileStat = await lstat(filePath);\n return fileStat.isFile() && !fileStat.isSymbolicLink();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n}\n\nasync function copyTreeMissing(\n source: string,\n destination: string,\n copied: string[],\n manifest: RollbackManifest,\n persistManifest?: PersistRollbackManifest,\n isRoot = true,\n): Promise<void> {\n if (!existsSync(source)) return;\n const sourceStat = await lstat(source);\n if (sourceStat.isSymbolicLink()) {\n if (isRoot) {\n throw new Error(`legacy migration root must not be a symlink: ${source}`);\n }\n return;\n }\n if (sourceStat.isDirectory()) {\n await mkdir(destination, { recursive: true });\n const entries = await readdir(source, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === MARKER_FILE || entry.name === LOCK_FILE || entry.name === ROLLBACK_MANIFEST) {\n continue;\n }\n await copyTreeMissing(\n path.join(source, entry.name),\n path.join(destination, entry.name),\n copied,\n manifest,\n persistManifest,\n false,\n );\n }\n return;\n }\n\n if (await pathExistsNoFollow(destination)) return;\n await ensureParent(destination);\n await copyFile(source, destination);\n await recordCreatedPath(destination, manifest, persistManifest);\n copied.push(destination);\n}\n\nfunction rewriteRemnicText(content: string): string {\n return content\n .replaceAll(\".engram/\", \".remnic/\")\n .replaceAll(\".engram\\\\\", \".remnic\\\\\")\n .replaceAll(\"ENGRAM_\", \"REMNIC_\")\n .replaceAll(\"{{ENGRAM_TOKEN}}\", \"{{REMNIC_TOKEN}}\")\n .replaceAll(\"${ENGRAM_AUTH_TOKEN}\", \"${REMNIC_AUTH_TOKEN}\")\n .replaceAll(\"ai.engram.daemon\", \"ai.remnic.daemon\")\n .replaceAll(\"engram.service\", \"remnic.service\");\n}\n\nfunction rewriteTokenValue(token: string): string {\n return token.startsWith(\"engram_\") ? `remnic_${token.slice(\"engram_\".length)}` : token;\n}\n\nfunction parseTokenEntries(raw: unknown): TokenEntry[] {\n if (typeof raw !== \"object\" || raw === null) return [];\n\n if (Array.isArray((raw as { tokens?: unknown }).tokens)) {\n return ((raw as { tokens: unknown[] }).tokens)\n .filter((entry): entry is TokenEntry => {\n if (typeof entry !== \"object\" || entry === null) return false;\n const candidate = entry as Partial<TokenEntry>;\n return typeof candidate.connector === \"string\" &&\n candidate.connector.length > 0 &&\n typeof candidate.token === \"string\" &&\n candidate.token.length > 0 &&\n typeof candidate.createdAt === \"string\" &&\n candidate.createdAt.length > 0;\n })\n .map((entry) => ({ ...entry }));\n }\n\n return Object.entries(raw)\n .filter(([key, value]) => key !== \"tokens\" && typeof value === \"string\" && value.length > 0)\n .map(([connector, token]) => ({\n connector,\n createdAt: new Date().toISOString(),\n token,\n }));\n}\n\nfunction isPlainJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nasync function rewriteTokensIfPresent(filePath: string): Promise<number> {\n if (!existsSync(filePath)) return 0;\n await assertExistingRegularFileNoFollow(filePath, \"Remnic token store\");\n await secureTokenFilePermissions(filePath);\n let raw: Record<string, unknown>;\n try {\n raw = JSON.parse(await readFile(filePath, \"utf8\")) as Record<string, unknown>;\n } catch {\n return 0;\n }\n let rewritten = 0;\n\n if (Array.isArray(raw.tokens)) {\n for (const entry of raw.tokens as Array<Record<string, unknown>>) {\n if (typeof entry.token === \"string\") {\n const next = rewriteTokenValue(entry.token);\n if (next !== entry.token) {\n entry.token = next;\n rewritten += 1;\n }\n }\n }\n } else {\n for (const [key, value] of Object.entries(raw)) {\n if (typeof value === \"string\") {\n const next = rewriteTokenValue(value);\n if (next !== value) {\n raw[key] = next;\n rewritten += 1;\n }\n }\n }\n }\n\n if (rewritten > 0) {\n await writeTokenStoreFile(filePath, `${JSON.stringify(raw, null, 2)}\\n`);\n }\n return rewritten;\n}\n\nasync function mergeLegacyTokens(\n legacyTokensPath: string,\n remnicTokensPath: string,\n homeDir: string,\n manifest: RollbackManifest,\n backupExisting: boolean,\n persistManifest?: PersistRollbackManifest,\n): Promise<number> {\n if (existsSync(legacyTokensPath)) {\n await assertExistingRegularFileNoFollow(legacyTokensPath, \"legacy Engram token store\");\n }\n if (!existsSync(remnicTokensPath)) return 0;\n await assertExistingRegularFileNoFollow(remnicTokensPath, \"Remnic token store\");\n await secureTokenFilePermissions(remnicTokensPath);\n if (!existsSync(legacyTokensPath)) return rewriteTokensIfPresent(remnicTokensPath);\n\n let remnicRaw: unknown;\n let legacyRaw: unknown;\n const originalRemnic = await readFile(remnicTokensPath, \"utf8\");\n\n try {\n remnicRaw = JSON.parse(originalRemnic) as unknown;\n legacyRaw = JSON.parse(await readFile(legacyTokensPath, \"utf8\")) as unknown;\n } catch {\n try {\n legacyRaw = JSON.parse(await readFile(legacyTokensPath, \"utf8\")) as unknown;\n } catch {\n return rewriteTokensIfPresent(remnicTokensPath);\n }\n\n const legacyEntries = parseTokenEntries(legacyRaw);\n let rewritten = 0;\n const recoveredEntries = legacyEntries.map((entry) => {\n const nextToken = rewriteTokenValue(entry.token);\n if (nextToken !== entry.token) rewritten += 1;\n return {\n ...entry,\n token: nextToken,\n };\n });\n\n if (backupExisting) {\n await backupFile(remnicTokensPath, originalRemnic, homeDir, manifest, persistManifest);\n }\n\n await writeTokenStoreFile(\n remnicTokensPath,\n `${JSON.stringify({ tokens: recoveredEntries }, null, 2)}\\n`,\n );\n return rewritten;\n }\n\n const mergedEntries = parseTokenEntries(remnicRaw);\n const legacyEntries = parseTokenEntries(legacyRaw);\n const existingConnectors = new Set(mergedEntries.map((entry) => entry.connector));\n let rewritten = 0;\n let changed = false;\n\n for (const entry of mergedEntries) {\n const nextToken = rewriteTokenValue(entry.token);\n if (nextToken !== entry.token) {\n entry.token = nextToken;\n rewritten += 1;\n changed = true;\n }\n }\n\n for (const entry of legacyEntries) {\n const nextToken = rewriteTokenValue(entry.token);\n if (nextToken !== entry.token) {\n rewritten += 1;\n }\n if (existingConnectors.has(entry.connector)) continue;\n mergedEntries.push({ ...entry, token: nextToken });\n existingConnectors.add(entry.connector);\n changed = true;\n }\n\n if (!changed) return rewritten;\n\n if (backupExisting) {\n await backupFile(remnicTokensPath, originalRemnic, homeDir, manifest, persistManifest);\n }\n\n await writeTokenStoreFile(\n remnicTokensPath,\n `${JSON.stringify({ tokens: mergedEntries }, null, 2)}\\n`,\n );\n return rewritten;\n}\n\nasync function rewriteJsonFile(\n targetPath: string,\n homeDir: string,\n manifest: RollbackManifest,\n persistManifest?: PersistRollbackManifest,\n): Promise<boolean> {\n if (!existsSync(targetPath)) return false;\n const targetStat = await lstat(targetPath);\n if (targetStat.isSymbolicLink()) return false;\n if (!targetStat.isFile()) {\n const error = new Error(`connector config must be a regular file: ${targetPath}`) as NodeJS.ErrnoException;\n error.code = targetStat.isDirectory() ? \"EISDIR\" : \"EINVAL\";\n throw error;\n }\n\n const original = await readFile(targetPath, \"utf8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(original) as unknown;\n } catch {\n return false;\n }\n if (!isPlainJsonObject(parsed)) return false;\n\n let changed = false;\n if (\n parsed.mcpServers &&\n typeof parsed.mcpServers === \"object\" &&\n !Array.isArray(parsed.mcpServers)\n ) {\n const servers = parsed.mcpServers as Record<string, unknown>;\n if (servers.engram && !servers.remnic) {\n servers.remnic = servers.engram;\n delete servers.engram;\n changed = true;\n }\n }\n\n const rewritten = rewriteRemnicText(JSON.stringify(parsed, null, 2));\n const next = `${rewritten}\\n`;\n if (!changed && next === original) return false;\n\n await backupFile(targetPath, original, homeDir, manifest, persistManifest);\n await writeFile(targetPath, next, \"utf8\");\n return true;\n}\n\nasync function backupFile(\n targetPath: string,\n originalContent: string,\n homeDir: string,\n manifest: RollbackManifest,\n persistManifest?: PersistRollbackManifest,\n): Promise<void> {\n if (manifest.entries.some((entry) => entry.targetPath === targetPath && entry.backupPath)) {\n return;\n }\n const digest = createHash(\"sha256\").update(targetPath).digest(\"hex\").slice(0, 12);\n const backupPath = path.join(backupRoot(homeDir), \"mcp\", `${digest}.json`);\n await ensureParent(backupPath);\n if (isRemnicTokenStorePath(targetPath, homeDir)) {\n await writeOwnerOnlyFile(backupPath, originalContent);\n } else {\n const originalMode = (await stat(targetPath)).mode & 0o777;\n await writeFile(backupPath, originalContent, { encoding: \"utf8\", mode: originalMode });\n await chmod(backupPath, originalMode);\n }\n manifest.entries.push({ targetPath, backupPath });\n await persistManifest?.();\n}\n\nasync function recordCreatedPath(\n filePath: string,\n manifest: RollbackManifest,\n persistManifest?: PersistRollbackManifest,\n): Promise<void> {\n if (manifest.entries.some((entry) => entry.targetPath === filePath)) return;\n manifest.entries.push({ targetPath: filePath, createdByMigration: true });\n await persistManifest?.();\n}\n\nfunction defaultConnectorConfigPaths(homeDir: string, cwd: string): string[] {\n return [\n path.join(homeDir, \".claude.json\"),\n path.join(homeDir, \".claude\", \".mcp.json\"),\n path.join(cwd, \"packages\", \"plugin-claude-code\", \".mcp.json\"),\n path.join(cwd, \"packages\", \"plugin-codex\", \".mcp.json\"),\n ];\n}\n\nasync function updateConnectorConfigs(\n homeDir: string,\n cwd: string,\n options: MigrationOptions | undefined,\n manifest: RollbackManifest,\n persistManifest?: PersistRollbackManifest,\n): Promise<string[]> {\n const updated: string[] = [];\n const candidates = options?.connectorConfigPaths ?? defaultConnectorConfigPaths(homeDir, cwd);\n for (const targetPath of candidates) {\n if (await rewriteJsonFile(targetPath, homeDir, manifest, persistManifest)) {\n updated.push(targetPath);\n }\n }\n return updated;\n}\n\nasync function copyLegacyConfig(\n homeDir: string,\n copied: string[],\n manifest: RollbackManifest,\n persistManifest?: PersistRollbackManifest,\n): Promise<void> {\n const source = legacyConfigPath(homeDir);\n const destination = remnicConfigPath(homeDir);\n if (!existsSync(source) || existsSync(destination)) return;\n if (!(await isExistingRegularFileNoFollow(source))) return;\n await ensureParent(destination);\n const original = await readFile(source, \"utf8\");\n let next = rewriteRemnicText(original);\n try {\n const parsed = JSON.parse(next) as unknown;\n if (isPlainJsonObject(parsed) && parsed.engram && !parsed.remnic) {\n parsed.remnic = parsed.engram;\n delete parsed.engram;\n next = JSON.stringify(parsed, null, 2);\n }\n } catch {\n // Keep rewritten text when config is not JSON.\n }\n await writeFile(destination, `${next.trimEnd()}\\n`, \"utf8\");\n await recordCreatedPath(destination, manifest, persistManifest);\n copied.push(destination);\n}\n\nfunction rewriteServiceText(content: string): string {\n return rewriteRemnicText(content);\n}\n\nasync function migrateServices(\n homeDir: string,\n options: MigrationOptions | undefined,\n manifest: RollbackManifest,\n persistManifest?: PersistRollbackManifest,\n): Promise<string[]> {\n const logger = resolveLogger(options);\n const exec = resolveExec(options);\n const servicesReinstalled: string[] = [];\n const platform = resolvePlatform(options);\n\n if (platform === \"darwin\") {\n const legacyPlist = path.join(homeDir, \"Library\", \"LaunchAgents\", \"ai.engram.daemon.plist\");\n const remnicPlist = path.join(homeDir, \"Library\", \"LaunchAgents\", \"ai.remnic.daemon.plist\");\n if (existsSync(legacyPlist) && !existsSync(remnicPlist)) {\n if (!(await isExistingRegularFileNoFollow(legacyPlist))) return servicesReinstalled;\n const next = rewriteServiceText(await readFile(legacyPlist, \"utf8\"));\n await ensureParent(remnicPlist);\n await writeFile(remnicPlist, next, \"utf8\");\n await recordCreatedPath(remnicPlist, manifest, persistManifest);\n try {\n exec(\"launchctl\", [\"unload\", legacyPlist]);\n } catch {\n // Keep migration fail-open when launchd rejects unload.\n }\n try {\n exec(\"launchctl\", [\"load\", \"-w\", remnicPlist]);\n } catch {\n // Keep migration fail-open when launchd rejects load.\n }\n servicesReinstalled.push(\"ai.remnic.daemon\");\n logger(\"launchd: ai.engram.daemon unloaded, ai.remnic.daemon installed\");\n }\n return servicesReinstalled;\n }\n\n if (platform === \"linux\") {\n const legacyUnit = path.join(homeDir, \".config\", \"systemd\", \"user\", \"engram.service\");\n const remnicUnit = path.join(homeDir, \".config\", \"systemd\", \"user\", \"remnic.service\");\n if (existsSync(legacyUnit) && !existsSync(remnicUnit)) {\n if (!(await isExistingRegularFileNoFollow(legacyUnit))) return servicesReinstalled;\n const next = rewriteServiceText(await readFile(legacyUnit, \"utf8\"));\n await ensureParent(remnicUnit);\n await writeFile(remnicUnit, next, \"utf8\");\n await recordCreatedPath(remnicUnit, manifest, persistManifest);\n try {\n exec(\"systemctl\", [\"--user\", \"stop\", \"engram.service\"]);\n exec(\"systemctl\", [\"--user\", \"disable\", \"engram.service\"]);\n exec(\"systemctl\", [\"--user\", \"daemon-reload\"]);\n exec(\"systemctl\", [\"--user\", \"enable\", \"remnic.service\"]);\n exec(\"systemctl\", [\"--user\", \"start\", \"remnic.service\"]);\n } catch {\n // Keep migration fail-open when systemd is unavailable.\n }\n servicesReinstalled.push(\"remnic.service\");\n logger(\"systemd: engram.service disabled, remnic.service installed\");\n }\n }\n\n return servicesReinstalled;\n}\n\nasync function writeRollbackManifest(homeDir: string, manifest: RollbackManifest): Promise<void> {\n await ensureParent(rollbackManifestPath(homeDir));\n await writeFile(\n rollbackManifestPath(homeDir),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nasync function readRollbackManifest(homeDir: string): Promise<RollbackManifest | null> {\n const target = rollbackManifestPath(homeDir);\n if (!existsSync(target)) return null;\n try {\n return JSON.parse(await readFile(target, \"utf8\")) as RollbackManifest;\n } catch {\n return null;\n }\n}\n\nasync function acquireLock(homeDir: string): Promise<() => Promise<void>> {\n const target = lockPath(homeDir);\n await mkdir(remnicRoot(homeDir), { recursive: true });\n const started = Date.now();\n\n while (true) {\n try {\n const handle = await open(target, \"wx\");\n await handle.writeFile(`${process.pid}\\n${Date.now()}\\n`, \"utf8\");\n return async () => {\n try {\n await handle.close();\n } finally {\n await unlink(target).catch(() => undefined);\n }\n };\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") throw error;\n\n const details = await readFile(target, \"utf8\").catch(() => null);\n if (details === null) {\n if (await removeLock(target)) continue;\n } else {\n const lines = details.split(\"\\n\");\n const pid = Number.parseInt(lines[0] ?? \"\", 10);\n const createdAt = Number.parseInt(lines[1] ?? \"\", 10);\n const malformed = !Number.isSafeInteger(pid) || pid <= 0 || !Number.isFinite(createdAt);\n const deadPid = !malformed && !processIsAlive(pid);\n if (malformed || deadPid) {\n if (await removeLockIfUnchanged(target, details)) continue;\n }\n }\n if (Date.now() - started > LOCK_TIMEOUT_MS) {\n throw new Error(`timed out waiting for migration lock: ${target}`);\n }\n await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));\n }\n }\n}\n\nasync function removeLockIfUnchanged(target: string, expectedContent: string): Promise<boolean> {\n const current = await readFile(target, \"utf8\").catch(() => null);\n if (current !== expectedContent) return false;\n return removeLock(target);\n}\n\nasync function removeLock(target: string): Promise<boolean> {\n try {\n await rm(target, { force: true });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction processIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EPERM\") return true;\n return false;\n }\n}\n\nexport async function rollbackFromEngramMigration(options?: MigrationOptions): Promise<RollbackResult> {\n const homeDir = resolveMigrationHome(options);\n const manifest = await readRollbackManifest(homeDir);\n const exec = resolveExec(options);\n const platform = resolvePlatform(options);\n const restored: string[] = [];\n const removed: string[] = [];\n\n if (!manifest) return { restored, removed };\n\n if (platform === \"darwin\") {\n const remnicPlist = path.join(homeDir, \"Library\", \"LaunchAgents\", \"ai.remnic.daemon.plist\");\n if (existsSync(remnicPlist)) {\n try {\n exec(\"launchctl\", [\"unload\", remnicPlist]);\n } catch {\n // Ignore launchctl rollback failures.\n }\n }\n } else if (platform === \"linux\") {\n try {\n exec(\"systemctl\", [\"--user\", \"stop\", \"remnic.service\"]);\n exec(\"systemctl\", [\"--user\", \"disable\", \"remnic.service\"]);\n } catch {\n // Ignore systemd rollback failures.\n }\n }\n\n for (const entry of [...manifest.entries].reverse()) {\n if (entry.backupPath && existsSync(entry.backupPath)) {\n await ensureParent(entry.targetPath);\n await copyFile(entry.backupPath, entry.targetPath);\n if (isRemnicTokenStorePath(entry.targetPath, homeDir)) {\n await secureTokenFilePermissions(entry.targetPath);\n }\n restored.push(entry.targetPath);\n continue;\n }\n if (entry.createdByMigration && existsSync(entry.targetPath)) {\n await rm(entry.targetPath, { recursive: true, force: true });\n removed.push(entry.targetPath);\n }\n }\n\n if (platform === \"linux\") {\n try {\n exec(\"systemctl\", [\"--user\", \"daemon-reload\"]);\n } catch {\n // Ignore systemd rollback failures after removing unit files.\n }\n }\n\n await rm(markerPath(homeDir), { force: true }).catch(() => undefined);\n await rm(rollbackManifestPath(homeDir), { force: true }).catch(() => undefined);\n return { restored, removed };\n}\n\nexport async function migrateFromEngram(options?: MigrationOptions): Promise<MigrationResult> {\n const homeDir = resolveMigrationHome(options);\n const cwd = options?.cwd ?? process.cwd();\n const logger = resolveLogger(options);\n const copied: string[] = [];\n let tokensRegenerated = 0;\n let servicesReinstalled: string[] = [];\n\n if (existsSync(markerPath(homeDir))) {\n return {\n status: \"already-migrated\",\n copied,\n tokensRegenerated,\n servicesReinstalled,\n rollbackCommand: defaultRollbackCommand(),\n };\n }\n\n const hasLegacyRoot = existsSync(legacyRoot(homeDir));\n const hasLegacyConfig = existsSync(legacyConfigPath(homeDir));\n if (!hasLegacyRoot && !hasLegacyConfig) {\n return {\n status: \"fresh-install\",\n copied,\n tokensRegenerated,\n servicesReinstalled,\n rollbackCommand: defaultRollbackCommand(),\n };\n }\n\n const releaseLock = await acquireLock(homeDir);\n try {\n if (existsSync(markerPath(homeDir))) {\n return {\n status: \"already-migrated\",\n copied,\n tokensRegenerated,\n servicesReinstalled,\n rollbackCommand: defaultRollbackCommand(),\n };\n }\n\n const manifest: RollbackManifest = await readRollbackManifest(homeDir) ?? {\n version: 1,\n createdAt: new Date().toISOString(),\n entries: [],\n };\n const persistManifest = () => writeRollbackManifest(homeDir, manifest);\n\n logger(\"First run after Engram -> Remnic rename. Migrating...\");\n await mkdir(remnicRoot(homeDir), { recursive: true });\n await persistManifest();\n await copyTreeMissing(legacyRoot(homeDir), remnicRoot(homeDir), copied, manifest, persistManifest);\n await copyLegacyConfig(homeDir, copied, manifest, persistManifest);\n\n const legacyTokens = path.join(legacyRoot(homeDir), \"tokens.json\");\n const remnicTokens = path.join(remnicRoot(homeDir), \"tokens.json\");\n if (copied.includes(remnicTokens)) {\n tokensRegenerated += await rewriteTokensIfPresent(remnicTokens);\n } else {\n tokensRegenerated += await mergeLegacyTokens(\n legacyTokens,\n remnicTokens,\n homeDir,\n manifest,\n true,\n persistManifest,\n );\n }\n if (existsSync(remnicTokens)) {\n logger(\"tokens copied to ~/.remnic/tokens.json (legacy prefixes rewritten)\");\n }\n\n const updatedConfigs = await updateConnectorConfigs(homeDir, cwd, options, manifest, persistManifest);\n for (const updated of updatedConfigs) {\n logger(`Updated connector config: ${updated}`);\n }\n\n servicesReinstalled = await migrateServices(homeDir, options, manifest, persistManifest);\n await writeRollbackManifest(homeDir, manifest);\n await writeFile(markerPath(homeDir), `${new Date().toISOString()}\\n`, \"utf8\");\n logger(\"Migration complete. Welcome to Remnic.\");\n\n return {\n status: \"migrated\",\n copied,\n tokensRegenerated,\n servicesReinstalled,\n rollbackCommand: defaultRollbackCommand(),\n };\n } finally {\n await releaseLock();\n }\n}\n"],"mappings":"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","names":["legacyEntries","rewritten"]}