@hasna/mementos 0.14.4 → 0.14.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -2106,6 +2106,8 @@ import { homedir as homedir2 } from "os";
2106
2106
  import { join as join2 } from "path";
2107
2107
  import { homedir } from "os";
2108
2108
  import { join, relative } from "path";
2109
+ import { homedir as homedir3 } from "os";
2110
+ import { join as join3 } from "path";
2109
2111
  function __accessProp2(key) {
2110
2112
  return this[key];
2111
2113
  }
@@ -2139,6 +2141,9 @@ class SqliteAdapter {
2139
2141
  exec(sql) {
2140
2142
  this.db.exec(sql);
2141
2143
  }
2144
+ query(sql) {
2145
+ return this.db.query(sql);
2146
+ }
2142
2147
  prepare(sql) {
2143
2148
  const stmt = this.db.prepare(sql);
2144
2149
  return {
@@ -2739,6 +2744,126 @@ function custom(check, _params = {}, fatal) {
2739
2744
  });
2740
2745
  return ZodAny.create();
2741
2746
  }
2747
+
2748
+ class SyncProgressTracker {
2749
+ db;
2750
+ progress = new Map;
2751
+ startTimes = new Map;
2752
+ callback;
2753
+ constructor(db, callback) {
2754
+ this.db = db;
2755
+ this.callback = callback;
2756
+ this.ensureResumeTable();
2757
+ }
2758
+ ensureResumeTable() {
2759
+ this.db.exec(`
2760
+ CREATE TABLE IF NOT EXISTS _sync_resume (
2761
+ table_name TEXT PRIMARY KEY,
2762
+ last_row_id TEXT,
2763
+ direction TEXT,
2764
+ started_at TEXT,
2765
+ status TEXT DEFAULT 'in_progress'
2766
+ )
2767
+ `);
2768
+ }
2769
+ start(table, total, direction) {
2770
+ const resumed = this.canResume(table);
2771
+ const now = Date.now();
2772
+ this.startTimes.set(table, now);
2773
+ const status = resumed ? "resumed" : "in_progress";
2774
+ const info = {
2775
+ table,
2776
+ total,
2777
+ done: 0,
2778
+ percent: 0,
2779
+ elapsed_ms: 0,
2780
+ eta_ms: 0,
2781
+ status
2782
+ };
2783
+ this.progress.set(table, info);
2784
+ this.db.run(`INSERT INTO _sync_resume (table_name, last_row_id, direction, started_at, status)
2785
+ VALUES (?, ?, ?, datetime('now'), ?)
2786
+ ON CONFLICT (table_name) DO UPDATE SET
2787
+ direction = excluded.direction,
2788
+ started_at = datetime('now'),
2789
+ status = excluded.status`, table, "", direction, status);
2790
+ this.notify(table);
2791
+ }
2792
+ update(table, done, lastRowId) {
2793
+ const info = this.progress.get(table);
2794
+ if (!info)
2795
+ return;
2796
+ const startTime = this.startTimes.get(table) ?? Date.now();
2797
+ const elapsed = Date.now() - startTime;
2798
+ const rate = done > 0 ? elapsed / done : 0;
2799
+ const remaining = info.total - done;
2800
+ const eta = remaining > 0 ? Math.round(rate * remaining) : 0;
2801
+ info.done = done;
2802
+ info.percent = info.total > 0 ? Math.round(done / info.total * 100) : 0;
2803
+ info.elapsed_ms = elapsed;
2804
+ info.eta_ms = eta;
2805
+ info.status = "in_progress";
2806
+ this.db.run(`UPDATE _sync_resume SET last_row_id = ?, status = 'in_progress' WHERE table_name = ?`, lastRowId, table);
2807
+ this.notify(table);
2808
+ }
2809
+ markComplete(table) {
2810
+ const info = this.progress.get(table);
2811
+ if (info) {
2812
+ const startTime = this.startTimes.get(table) ?? Date.now();
2813
+ info.elapsed_ms = Date.now() - startTime;
2814
+ info.done = info.total;
2815
+ info.percent = 100;
2816
+ info.eta_ms = 0;
2817
+ info.status = "completed";
2818
+ this.notify(table);
2819
+ }
2820
+ this.db.run(`UPDATE _sync_resume SET status = 'completed' WHERE table_name = ?`, table);
2821
+ }
2822
+ markFailed(table, _error) {
2823
+ const info = this.progress.get(table);
2824
+ if (info) {
2825
+ const startTime = this.startTimes.get(table) ?? Date.now();
2826
+ info.elapsed_ms = Date.now() - startTime;
2827
+ info.status = "failed";
2828
+ this.notify(table);
2829
+ }
2830
+ this.db.run(`UPDATE _sync_resume SET status = 'failed' WHERE table_name = ?`, table);
2831
+ }
2832
+ canResume(table) {
2833
+ const row = this.db.get(`SELECT status FROM _sync_resume WHERE table_name = ?`, table);
2834
+ if (!row)
2835
+ return false;
2836
+ return row.status === "in_progress" || row.status === "resumed";
2837
+ }
2838
+ getResumePoint(table) {
2839
+ const row = this.db.get(`SELECT table_name, last_row_id, direction, started_at, status FROM _sync_resume WHERE table_name = ?`, table);
2840
+ if (!row)
2841
+ return null;
2842
+ if (row.status !== "in_progress" && row.status !== "resumed")
2843
+ return null;
2844
+ return row;
2845
+ }
2846
+ clearResume(table) {
2847
+ this.db.run(`DELETE FROM _sync_resume WHERE table_name = ?`, table);
2848
+ this.progress.delete(table);
2849
+ this.startTimes.delete(table);
2850
+ }
2851
+ getProgress(table) {
2852
+ return this.progress.get(table) ?? null;
2853
+ }
2854
+ getAllProgress() {
2855
+ return Array.from(this.progress.values());
2856
+ }
2857
+ listResumeRecords() {
2858
+ return this.db.all(`SELECT table_name, last_row_id, direction, started_at, status FROM _sync_resume ORDER BY started_at DESC`);
2859
+ }
2860
+ notify(table) {
2861
+ const info = this.progress.get(table);
2862
+ if (info && this.callback) {
2863
+ this.callback({ ...info });
2864
+ }
2865
+ }
2866
+ }
2742
2867
  var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __toESMCache_node2, __toESMCache_esm2, __toESM2 = (mod, isNodeMode, target) => {
2743
2868
  var canCache = mod != null && typeof mod === "object";
2744
2869
  if (canCache) {
@@ -2982,7 +3107,7 @@ var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __t
2982
3107
  }
2983
3108
  }, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, BRAND, ZodBranded, ZodPipeline, ZodReadonly, late, ZodFirstPartyTypeKind, instanceOfType = (cls, params = {
2984
3109
  message: `Input not instance of ${cls.name}`
2985
- }) => custom((data) => data instanceof cls, params), stringType, numberType, nanType, bigIntType, booleanType, dateType, symbolType, undefinedType, nullType, anyType, unknownType, neverType, voidType, arrayType, objectType, strictObjectType, unionType, discriminatedUnionType, intersectionType, tupleType, recordType, mapType, setType, functionType, lazyType, literalType, enumType, nativeEnumType, promiseType, effectsType, optionalType, nullableType, preprocessType, pipelineType, ostring = () => stringType().optional(), onumber = () => numberType().optional(), oboolean = () => booleanType().optional(), coerce, NEVER, HASNA_DIR, CloudConfigSchema, CONFIG_DIR, CONFIG_PATH;
3110
+ }) => custom((data) => data instanceof cls, params), stringType, numberType, nanType, bigIntType, booleanType, dateType, symbolType, undefinedType, nullType, anyType, unknownType, neverType, voidType, arrayType, objectType, strictObjectType, unionType, discriminatedUnionType, intersectionType, tupleType, recordType, mapType, setType, functionType, lazyType, literalType, enumType, nativeEnumType, promiseType, effectsType, optionalType, nullableType, preprocessType, pipelineType, ostring = () => stringType().optional(), onumber = () => numberType().optional(), oboolean = () => booleanType().optional(), coerce, NEVER, HASNA_DIR, CloudConfigSchema, CONFIG_DIR, CONFIG_PATH, AUTO_SYNC_CONFIG_PATH;
2986
3111
  var init_dist = __esm(() => {
2987
3112
  __create2 = Object.create;
2988
3113
  __getProtoOf2 = Object.getPrototypeOf;
@@ -10925,6 +11050,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
10925
11050
  });
10926
11051
  CONFIG_DIR = join2(homedir2(), ".hasna", "cloud");
10927
11052
  CONFIG_PATH = join2(CONFIG_DIR, "config.json");
11053
+ AUTO_SYNC_CONFIG_PATH = join3(homedir3(), ".hasna", "cloud", "config.json");
10928
11054
  });
10929
11055
 
10930
11056
  // src/db/database.ts
@@ -10940,14 +11066,14 @@ __export(exports_database, {
10940
11066
  closeDatabase: () => closeDatabase
10941
11067
  });
10942
11068
  import { existsSync, mkdirSync, cpSync } from "fs";
10943
- import { dirname, join as join3, resolve } from "path";
11069
+ import { dirname, join as join4, resolve } from "path";
10944
11070
  function isInMemoryDb(path) {
10945
11071
  return path === ":memory:" || path.startsWith("file::memory:");
10946
11072
  }
10947
11073
  function findNearestMementosDb(startDir) {
10948
11074
  let dir = resolve(startDir);
10949
11075
  while (true) {
10950
- const candidate = join3(dir, ".mementos", "mementos.db");
11076
+ const candidate = join4(dir, ".mementos", "mementos.db");
10951
11077
  if (existsSync(candidate))
10952
11078
  return candidate;
10953
11079
  const parent = dirname(dir);
@@ -10960,7 +11086,7 @@ function findNearestMementosDb(startDir) {
10960
11086
  function findGitRoot(startDir) {
10961
11087
  let dir = resolve(startDir);
10962
11088
  while (true) {
10963
- if (existsSync(join3(dir, ".git")))
11089
+ if (existsSync(join4(dir, ".git")))
10964
11090
  return dir;
10965
11091
  const parent = dirname(dir);
10966
11092
  if (parent === dir)
@@ -10971,10 +11097,10 @@ function findGitRoot(startDir) {
10971
11097
  }
10972
11098
  function migrateGlobalDir() {
10973
11099
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
10974
- const newDir = join3(home, ".hasna", "mementos");
10975
- const oldDir = join3(home, ".mementos");
11100
+ const newDir = join4(home, ".hasna", "mementos");
11101
+ const oldDir = join4(home, ".mementos");
10976
11102
  if (!existsSync(newDir) && existsSync(oldDir)) {
10977
- mkdirSync(join3(home, ".hasna"), { recursive: true });
11103
+ mkdirSync(join4(home, ".hasna"), { recursive: true });
10978
11104
  cpSync(oldDir, newDir, { recursive: true });
10979
11105
  }
10980
11106
  }
@@ -10990,12 +11116,12 @@ function getDbPath() {
10990
11116
  if (process.env["MEMENTOS_DB_SCOPE"] === "project") {
10991
11117
  const gitRoot = findGitRoot(cwd);
10992
11118
  if (gitRoot) {
10993
- return join3(gitRoot, ".mementos", "mementos.db");
11119
+ return join4(gitRoot, ".mementos", "mementos.db");
10994
11120
  }
10995
11121
  }
10996
11122
  migrateGlobalDir();
10997
11123
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
10998
- return join3(home, ".hasna", "mementos", "mementos.db");
11124
+ return join4(home, ".hasna", "mementos", "mementos.db");
10999
11125
  }
11000
11126
  function ensureDir(filePath) {
11001
11127
  if (isInMemoryDb(filePath))
@@ -17136,7 +17262,7 @@ __export(exports_session_registry, {
17136
17262
  });
17137
17263
  import { Database as Database2 } from "bun:sqlite";
17138
17264
  import { existsSync as existsSync5, mkdirSync as mkdirSync5 } from "fs";
17139
- import { dirname as dirname3, join as join8 } from "path";
17265
+ import { dirname as dirname3, join as join9 } from "path";
17140
17266
  function getDb() {
17141
17267
  if (_db2)
17142
17268
  return _db2;
@@ -17315,7 +17441,7 @@ function closeRegistry() {
17315
17441
  }
17316
17442
  var DB_PATH, _db2 = null;
17317
17443
  var init_session_registry = __esm(() => {
17318
- DB_PATH = join8(process.env["HOME"] || process.env["USERPROFILE"] || "~", ".open-sessions-registry.db");
17444
+ DB_PATH = join9(process.env["HOME"] || process.env["USERPROFILE"] || "~", ".open-sessions-registry.db");
17319
17445
  });
17320
17446
 
17321
17447
  // node_modules/commander/esm.mjs
@@ -17339,8 +17465,8 @@ init_database();
17339
17465
  init_memories();
17340
17466
  import chalk2 from "chalk";
17341
17467
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, existsSync as existsSync6, unlinkSync as unlinkSync2, accessSync, statSync, copyFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync3, constants as fsConstants } from "fs";
17342
- import { dirname as dirname4, join as join9, resolve as resolve3 } from "path";
17343
- import { homedir as homedir7 } from "os";
17468
+ import { dirname as dirname4, join as join10, resolve as resolve3 } from "path";
17469
+ import { homedir as homedir8 } from "os";
17344
17470
  import { fileURLToPath } from "url";
17345
17471
 
17346
17472
  // src/db/agents.ts
@@ -17561,8 +17687,8 @@ init_search();
17561
17687
 
17562
17688
  // src/lib/config.ts
17563
17689
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync, writeFileSync, unlinkSync, cpSync as cpSync2 } from "fs";
17564
- import { homedir as homedir3 } from "os";
17565
- import { basename, dirname as dirname2, join as join5, resolve as resolve2 } from "path";
17690
+ import { homedir as homedir4 } from "os";
17691
+ import { basename, dirname as dirname2, join as join6, resolve as resolve2 } from "path";
17566
17692
  var DEFAULT_CONFIG = {
17567
17693
  default_scope: "private",
17568
17694
  default_category: "knowledge",
@@ -17619,7 +17745,7 @@ function isValidCategory(value) {
17619
17745
  return VALID_CATEGORIES.includes(value);
17620
17746
  }
17621
17747
  function loadConfig() {
17622
- const configPath = join5(homedir3(), ".hasna", "mementos", "config.json");
17748
+ const configPath = join6(homedir4(), ".hasna", "mementos", "config.json");
17623
17749
  let fileConfig = {};
17624
17750
  if (existsSync2(configPath)) {
17625
17751
  try {
@@ -17646,10 +17772,10 @@ function loadConfig() {
17646
17772
  return merged;
17647
17773
  }
17648
17774
  function profilesDir() {
17649
- return join5(homedir3(), ".hasna", "mementos", "profiles");
17775
+ return join6(homedir4(), ".hasna", "mementos", "profiles");
17650
17776
  }
17651
17777
  function globalConfigPath() {
17652
- return join5(homedir3(), ".hasna", "mementos", "config.json");
17778
+ return join6(homedir4(), ".hasna", "mementos", "config.json");
17653
17779
  }
17654
17780
  function readGlobalConfig() {
17655
17781
  const p = globalConfigPath();
@@ -17689,7 +17815,7 @@ function listProfiles() {
17689
17815
  return readdirSync(dir).filter((f) => f.endsWith(".db")).map((f) => basename(f, ".db")).sort();
17690
17816
  }
17691
17817
  function deleteProfile(name) {
17692
- const dbPath = join5(profilesDir(), `${name}.db`);
17818
+ const dbPath = join6(profilesDir(), `${name}.db`);
17693
17819
  if (!existsSync2(dbPath))
17694
17820
  return false;
17695
17821
  unlinkSync(dbPath);
@@ -17831,8 +17957,8 @@ import {
17831
17957
  writeFileSync as writeFileSync3,
17832
17958
  readdirSync as readdirSync2
17833
17959
  } from "fs";
17834
- import { homedir as homedir6 } from "os";
17835
- import { join as join7 } from "path";
17960
+ import { homedir as homedir7 } from "os";
17961
+ import { join as join8 } from "path";
17836
17962
  import chalk from "chalk";
17837
17963
 
17838
17964
  // src/lib/gatherer.ts
@@ -17910,11 +18036,11 @@ var gatherTrainingData = async (options = {}) => {
17910
18036
 
17911
18037
  // src/lib/model-config.ts
17912
18038
  import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
17913
- import { homedir as homedir5 } from "os";
17914
- import { join as join6 } from "path";
18039
+ import { homedir as homedir6 } from "os";
18040
+ import { join as join7 } from "path";
17915
18041
  var DEFAULT_MODEL = "gpt-4o-mini";
17916
- var CONFIG_DIR2 = join6(homedir5(), ".hasna", "mementos");
17917
- var CONFIG_PATH2 = join6(CONFIG_DIR2, "config.json");
18042
+ var CONFIG_DIR2 = join7(homedir6(), ".hasna", "mementos");
18043
+ var CONFIG_PATH2 = join7(CONFIG_DIR2, "config.json");
17918
18044
  function readConfig() {
17919
18045
  if (!existsSync3(CONFIG_PATH2))
17920
18046
  return {};
@@ -17974,12 +18100,12 @@ function makeBrainsCommand() {
17974
18100
  limit: opts.limit,
17975
18101
  since
17976
18102
  });
17977
- const outputDir = opts.output ?? join7(homedir6(), ".hasna", "mementos", "training");
18103
+ const outputDir = opts.output ?? join8(homedir7(), ".hasna", "mementos", "training");
17978
18104
  if (!existsSync4(outputDir)) {
17979
18105
  mkdirSync4(outputDir, { recursive: true });
17980
18106
  }
17981
18107
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
17982
- const outputPath = join7(outputDir, `mementos-training-${timestamp}.jsonl`);
18108
+ const outputPath = join8(outputDir, `mementos-training-${timestamp}.jsonl`);
17983
18109
  const jsonl = result.examples.map((ex) => JSON.stringify(ex)).join(`
17984
18110
  `);
17985
18111
  writeFileSync3(outputPath, jsonl + `
@@ -18003,7 +18129,7 @@ function makeBrainsCommand() {
18003
18129
  try {
18004
18130
  let datasetPath = opts.dataset;
18005
18131
  if (!datasetPath) {
18006
- const trainingDir = join7(homedir6(), ".hasna", "mementos", "training");
18132
+ const trainingDir = join8(homedir7(), ".hasna", "mementos", "training");
18007
18133
  if (!existsSync4(trainingDir)) {
18008
18134
  printError("No training data found. Run `mementos brains gather` first.");
18009
18135
  process.exit(1);
@@ -18014,7 +18140,7 @@ function makeBrainsCommand() {
18014
18140
  printError("No JSONL training files found. Run `mementos brains gather` first.");
18015
18141
  process.exit(1);
18016
18142
  }
18017
- datasetPath = join7(trainingDir, latestFile);
18143
+ datasetPath = join8(trainingDir, latestFile);
18018
18144
  }
18019
18145
  if (!datasetPath || !existsSync4(datasetPath)) {
18020
18146
  printError(`Dataset file not found: ${datasetPath ?? "(unresolved)"}`);
@@ -18120,7 +18246,7 @@ function makeBrainsCommand() {
18120
18246
  // src/cli/index.tsx
18121
18247
  function getPackageVersion() {
18122
18248
  try {
18123
- const pkgPath = join9(dirname4(fileURLToPath(import.meta.url)), "..", "..", "package.json");
18249
+ const pkgPath = join10(dirname4(fileURLToPath(import.meta.url)), "..", "..", "package.json");
18124
18250
  const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
18125
18251
  return pkg.version || "0.0.0";
18126
18252
  } catch {
@@ -18348,7 +18474,7 @@ function resolveKeyOrId(keyOrId, opts, globalOpts) {
18348
18474
  program2.name("mementos").description("Universal memory system for AI agents").version(getPackageVersion()).option("--project <path>", "Project path for scoping").option("--json", "Output as JSON").option("--format <fmt>", "Output format: compact, json, csv, yaml").option("--agent <name>", "Agent name or ID").option("--session <id>", "Session ID");
18349
18475
  program2.command("init").description("One-command setup: register MCP, install stop hook, configure auto-start").action(async () => {
18350
18476
  const { platform } = process;
18351
- const home = homedir7();
18477
+ const home = homedir8();
18352
18478
  const isMac = platform === "darwin";
18353
18479
  console.log("");
18354
18480
  console.log(chalk2.bold(" mementos \u2014 setting up your memory layer"));
@@ -18403,9 +18529,9 @@ program2.command("init").description("One-command setup: register MCP, install s
18403
18529
  } else {
18404
18530
  console.log(chalk2.green(" \u2713 MCP server registered with Claude Code"));
18405
18531
  }
18406
- const hooksDir = join9(home, ".claude", "hooks");
18407
- const hookDest = join9(hooksDir, "mementos-stop-hook.ts");
18408
- const settingsPath = join9(home, ".claude", "settings.json");
18532
+ const hooksDir = join10(home, ".claude", "hooks");
18533
+ const hookDest = join10(hooksDir, "mementos-stop-hook.ts");
18534
+ const settingsPath = join10(home, ".claude", "settings.json");
18409
18535
  const hookCommand = `bun ${hookDest}`;
18410
18536
  let hookAlreadyInstalled = false;
18411
18537
  let hookError = null;
@@ -18430,9 +18556,9 @@ program2.command("init").description("One-command setup: register MCP, install s
18430
18556
  if (!existsSync6(hookDest)) {
18431
18557
  const packageDir = dirname4(dirname4(fileURLToPath(import.meta.url)));
18432
18558
  const candidatePaths = [
18433
- join9(packageDir, "scripts", "hooks", "claude-stop-hook.ts"),
18434
- join9(packageDir, "..", "scripts", "hooks", "claude-stop-hook.ts"),
18435
- join9(home, ".bun", "install", "global", "node_modules", "@hasna", "mementos", "scripts", "hooks", "claude-stop-hook.ts")
18559
+ join10(packageDir, "scripts", "hooks", "claude-stop-hook.ts"),
18560
+ join10(packageDir, "..", "scripts", "hooks", "claude-stop-hook.ts"),
18561
+ join10(home, ".bun", "install", "global", "node_modules", "@hasna", "mementos", "scripts", "hooks", "claude-stop-hook.ts")
18436
18562
  ];
18437
18563
  let hookSourceFound = false;
18438
18564
  for (const src of candidatePaths) {
@@ -18502,7 +18628,7 @@ main().catch(() => {});
18502
18628
  if (!isMac) {
18503
18629
  console.log(chalk2.dim(` \xB7 Auto-start skipped (not macOS \u2014 platform: ${platform})`));
18504
18630
  } else {
18505
- const plistPath = join9(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
18631
+ const plistPath = join10(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
18506
18632
  const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
18507
18633
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
18508
18634
  <plist version="1.0">
@@ -18530,7 +18656,7 @@ main().catch(() => {});
18530
18656
  if (existsSync6(plistPath)) {
18531
18657
  autoStartAlreadyInstalled = true;
18532
18658
  } else {
18533
- const launchAgentsDir = join9(home, "Library", "LaunchAgents");
18659
+ const launchAgentsDir = join10(home, "Library", "LaunchAgents");
18534
18660
  if (!existsSync6(launchAgentsDir)) {
18535
18661
  mkdirSync6(launchAgentsDir, { recursive: true });
18536
18662
  }
@@ -18547,7 +18673,7 @@ main().catch(() => {});
18547
18673
  console.log(chalk2.green(" \u2713 Auto-start configured (starts on login)"));
18548
18674
  }
18549
18675
  if (!autoStartAlreadyInstalled && !autoStartError) {
18550
- const plistPath2 = join9(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
18676
+ const plistPath2 = join10(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
18551
18677
  const loadResult = await run(["launchctl", "load", plistPath2]);
18552
18678
  if (!loadResult.ok) {
18553
18679
  console.log(chalk2.dim(` \xB7 launchctl load: ${loadResult.output || "already loaded"}`));
@@ -19717,7 +19843,7 @@ program2.command("doctor").description("Diagnose common issues with the mementos
19717
19843
  checks.push({ name: "MCP server", status: "warn", detail: "could not check (is claude CLI installed?)" });
19718
19844
  }
19719
19845
  try {
19720
- const settingsFilePath = join9(homedir7(), ".claude", "settings.json");
19846
+ const settingsFilePath = join10(homedir8(), ".claude", "settings.json");
19721
19847
  if (existsSync6(settingsFilePath)) {
19722
19848
  const settings = JSON.parse(readFileSync3(settingsFilePath, "utf-8"));
19723
19849
  const hooksObj = settings["hooks"] || {};
@@ -19735,7 +19861,7 @@ program2.command("doctor").description("Diagnose common issues with the mementos
19735
19861
  checks.push({ name: "Stop hook", status: "warn", detail: "could not check stop hook" });
19736
19862
  }
19737
19863
  if (process.platform === "darwin") {
19738
- const plistFilePath = join9(homedir7(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
19864
+ const plistFilePath = join10(homedir8(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
19739
19865
  checks.push({
19740
19866
  name: "Auto-start",
19741
19867
  status: existsSync6(plistFilePath) ? "ok" : "warn",
@@ -20248,7 +20374,7 @@ program2.command("backup [path]").description("Backup the SQLite database to a f
20248
20374
  try {
20249
20375
  const globalOpts = program2.opts();
20250
20376
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
20251
- const backupsDir = join9(home, ".hasna", "mementos", "backups");
20377
+ const backupsDir = join10(home, ".hasna", "mementos", "backups");
20252
20378
  if (opts.list) {
20253
20379
  if (!existsSync6(backupsDir)) {
20254
20380
  if (globalOpts.json) {
@@ -20259,7 +20385,7 @@ program2.command("backup [path]").description("Backup the SQLite database to a f
20259
20385
  return;
20260
20386
  }
20261
20387
  const files = readdirSync3(backupsDir).filter((f) => f.endsWith(".db")).map((f) => {
20262
- const filePath = join9(backupsDir, f);
20388
+ const filePath = join10(backupsDir, f);
20263
20389
  const st2 = statSync(filePath);
20264
20390
  return { name: f, path: filePath, size: st2.size, mtime: st2.mtime };
20265
20391
  }).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
@@ -20305,7 +20431,7 @@ program2.command("backup [path]").description("Backup the SQLite database to a f
20305
20431
  }
20306
20432
  const now3 = new Date;
20307
20433
  const ts = now3.toISOString().replace(/[-:T]/g, "").replace(/\..+/, "").slice(0, 15);
20308
- dest = join9(backupsDir, `mementos-${ts}.db`);
20434
+ dest = join10(backupsDir, `mementos-${ts}.db`);
20309
20435
  }
20310
20436
  const destDir = dirname4(dest);
20311
20437
  if (!existsSync6(destDir)) {
@@ -20328,7 +20454,7 @@ program2.command("restore [file]").description("Restore the database from a back
20328
20454
  try {
20329
20455
  const globalOpts = program2.opts();
20330
20456
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
20331
- const backupsDir = join9(home, ".hasna", "mementos", "backups");
20457
+ const backupsDir = join10(home, ".hasna", "mementos", "backups");
20332
20458
  let source;
20333
20459
  if (opts.latest) {
20334
20460
  if (!existsSync6(backupsDir)) {
@@ -20336,7 +20462,7 @@ program2.command("restore [file]").description("Restore the database from a back
20336
20462
  process.exit(1);
20337
20463
  }
20338
20464
  const files = readdirSync3(backupsDir).filter((f) => f.endsWith(".db")).map((f) => {
20339
- const fp = join9(backupsDir, f);
20465
+ const fp = join10(backupsDir, f);
20340
20466
  const st = statSync(fp);
20341
20467
  return { path: fp, mtime: st.mtime };
20342
20468
  }).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
@@ -20749,7 +20875,7 @@ function validateConfigKeyValue(key, value) {
20749
20875
  return null;
20750
20876
  }
20751
20877
  function getConfigPath() {
20752
- return join9(homedir7(), ".hasna", "mementos", "config.json");
20878
+ return join10(homedir8(), ".hasna", "mementos", "config.json");
20753
20879
  }
20754
20880
  function readFileConfig() {
20755
20881
  const configPath = getConfigPath();