@hasna/mementos 0.14.5 → 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/index.js CHANGED
@@ -22,6 +22,8 @@ import { homedir as homedir2 } from "os";
22
22
  import { join as join2 } from "path";
23
23
  import { homedir } from "os";
24
24
  import { join, relative } from "path";
25
+ import { homedir as homedir3 } from "os";
26
+ import { join as join3 } from "path";
25
27
  function __accessProp(key) {
26
28
  return this[key];
27
29
  }
@@ -55,6 +57,9 @@ class SqliteAdapter {
55
57
  exec(sql) {
56
58
  this.db.exec(sql);
57
59
  }
60
+ query(sql) {
61
+ return this.db.query(sql);
62
+ }
58
63
  prepare(sql) {
59
64
  const stmt = this.db.prepare(sql);
60
65
  return {
@@ -655,6 +660,126 @@ function custom(check, _params = {}, fatal) {
655
660
  });
656
661
  return ZodAny.create();
657
662
  }
663
+
664
+ class SyncProgressTracker {
665
+ db;
666
+ progress = new Map;
667
+ startTimes = new Map;
668
+ callback;
669
+ constructor(db, callback) {
670
+ this.db = db;
671
+ this.callback = callback;
672
+ this.ensureResumeTable();
673
+ }
674
+ ensureResumeTable() {
675
+ this.db.exec(`
676
+ CREATE TABLE IF NOT EXISTS _sync_resume (
677
+ table_name TEXT PRIMARY KEY,
678
+ last_row_id TEXT,
679
+ direction TEXT,
680
+ started_at TEXT,
681
+ status TEXT DEFAULT 'in_progress'
682
+ )
683
+ `);
684
+ }
685
+ start(table, total, direction) {
686
+ const resumed = this.canResume(table);
687
+ const now = Date.now();
688
+ this.startTimes.set(table, now);
689
+ const status = resumed ? "resumed" : "in_progress";
690
+ const info = {
691
+ table,
692
+ total,
693
+ done: 0,
694
+ percent: 0,
695
+ elapsed_ms: 0,
696
+ eta_ms: 0,
697
+ status
698
+ };
699
+ this.progress.set(table, info);
700
+ this.db.run(`INSERT INTO _sync_resume (table_name, last_row_id, direction, started_at, status)
701
+ VALUES (?, ?, ?, datetime('now'), ?)
702
+ ON CONFLICT (table_name) DO UPDATE SET
703
+ direction = excluded.direction,
704
+ started_at = datetime('now'),
705
+ status = excluded.status`, table, "", direction, status);
706
+ this.notify(table);
707
+ }
708
+ update(table, done, lastRowId) {
709
+ const info = this.progress.get(table);
710
+ if (!info)
711
+ return;
712
+ const startTime = this.startTimes.get(table) ?? Date.now();
713
+ const elapsed = Date.now() - startTime;
714
+ const rate = done > 0 ? elapsed / done : 0;
715
+ const remaining = info.total - done;
716
+ const eta = remaining > 0 ? Math.round(rate * remaining) : 0;
717
+ info.done = done;
718
+ info.percent = info.total > 0 ? Math.round(done / info.total * 100) : 0;
719
+ info.elapsed_ms = elapsed;
720
+ info.eta_ms = eta;
721
+ info.status = "in_progress";
722
+ this.db.run(`UPDATE _sync_resume SET last_row_id = ?, status = 'in_progress' WHERE table_name = ?`, lastRowId, table);
723
+ this.notify(table);
724
+ }
725
+ markComplete(table) {
726
+ const info = this.progress.get(table);
727
+ if (info) {
728
+ const startTime = this.startTimes.get(table) ?? Date.now();
729
+ info.elapsed_ms = Date.now() - startTime;
730
+ info.done = info.total;
731
+ info.percent = 100;
732
+ info.eta_ms = 0;
733
+ info.status = "completed";
734
+ this.notify(table);
735
+ }
736
+ this.db.run(`UPDATE _sync_resume SET status = 'completed' WHERE table_name = ?`, table);
737
+ }
738
+ markFailed(table, _error) {
739
+ const info = this.progress.get(table);
740
+ if (info) {
741
+ const startTime = this.startTimes.get(table) ?? Date.now();
742
+ info.elapsed_ms = Date.now() - startTime;
743
+ info.status = "failed";
744
+ this.notify(table);
745
+ }
746
+ this.db.run(`UPDATE _sync_resume SET status = 'failed' WHERE table_name = ?`, table);
747
+ }
748
+ canResume(table) {
749
+ const row = this.db.get(`SELECT status FROM _sync_resume WHERE table_name = ?`, table);
750
+ if (!row)
751
+ return false;
752
+ return row.status === "in_progress" || row.status === "resumed";
753
+ }
754
+ getResumePoint(table) {
755
+ const row = this.db.get(`SELECT table_name, last_row_id, direction, started_at, status FROM _sync_resume WHERE table_name = ?`, table);
756
+ if (!row)
757
+ return null;
758
+ if (row.status !== "in_progress" && row.status !== "resumed")
759
+ return null;
760
+ return row;
761
+ }
762
+ clearResume(table) {
763
+ this.db.run(`DELETE FROM _sync_resume WHERE table_name = ?`, table);
764
+ this.progress.delete(table);
765
+ this.startTimes.delete(table);
766
+ }
767
+ getProgress(table) {
768
+ return this.progress.get(table) ?? null;
769
+ }
770
+ getAllProgress() {
771
+ return Array.from(this.progress.values());
772
+ }
773
+ listResumeRecords() {
774
+ return this.db.all(`SELECT table_name, last_row_id, direction, started_at, status FROM _sync_resume ORDER BY started_at DESC`);
775
+ }
776
+ notify(table) {
777
+ const info = this.progress.get(table);
778
+ if (info && this.callback) {
779
+ this.callback({ ...info });
780
+ }
781
+ }
782
+ }
658
783
  var __create, __getProtoOf, __defProp2, __getOwnPropNames, __hasOwnProp, __toESMCache_node, __toESMCache_esm, __toESM = (mod, isNodeMode, target) => {
659
784
  var canCache = mod != null && typeof mod === "object";
660
785
  if (canCache) {
@@ -898,7 +1023,7 @@ var __create, __getProtoOf, __defProp2, __getOwnPropNames, __hasOwnProp, __toESM
898
1023
  }
899
1024
  }, 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 = {
900
1025
  message: `Input not instance of ${cls.name}`
901
- }) => 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;
1026
+ }) => 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;
902
1027
  var init_dist = __esm(() => {
903
1028
  __create = Object.create;
904
1029
  __getProtoOf = Object.getPrototypeOf;
@@ -8841,6 +8966,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
8841
8966
  });
8842
8967
  CONFIG_DIR = join2(homedir2(), ".hasna", "cloud");
8843
8968
  CONFIG_PATH = join2(CONFIG_DIR, "config.json");
8969
+ AUTO_SYNC_CONFIG_PATH = join3(homedir3(), ".hasna", "cloud", "config.json");
8844
8970
  });
8845
8971
 
8846
8972
  // src/db/database.ts
@@ -8856,14 +8982,14 @@ __export(exports_database, {
8856
8982
  closeDatabase: () => closeDatabase
8857
8983
  });
8858
8984
  import { existsSync, mkdirSync, cpSync } from "fs";
8859
- import { dirname, join as join3, resolve } from "path";
8985
+ import { dirname, join as join4, resolve } from "path";
8860
8986
  function isInMemoryDb(path) {
8861
8987
  return path === ":memory:" || path.startsWith("file::memory:");
8862
8988
  }
8863
8989
  function findNearestMementosDb(startDir) {
8864
8990
  let dir = resolve(startDir);
8865
8991
  while (true) {
8866
- const candidate = join3(dir, ".mementos", "mementos.db");
8992
+ const candidate = join4(dir, ".mementos", "mementos.db");
8867
8993
  if (existsSync(candidate))
8868
8994
  return candidate;
8869
8995
  const parent = dirname(dir);
@@ -8876,7 +9002,7 @@ function findNearestMementosDb(startDir) {
8876
9002
  function findGitRoot(startDir) {
8877
9003
  let dir = resolve(startDir);
8878
9004
  while (true) {
8879
- if (existsSync(join3(dir, ".git")))
9005
+ if (existsSync(join4(dir, ".git")))
8880
9006
  return dir;
8881
9007
  const parent = dirname(dir);
8882
9008
  if (parent === dir)
@@ -8887,10 +9013,10 @@ function findGitRoot(startDir) {
8887
9013
  }
8888
9014
  function migrateGlobalDir() {
8889
9015
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
8890
- const newDir = join3(home, ".hasna", "mementos");
8891
- const oldDir = join3(home, ".mementos");
9016
+ const newDir = join4(home, ".hasna", "mementos");
9017
+ const oldDir = join4(home, ".mementos");
8892
9018
  if (!existsSync(newDir) && existsSync(oldDir)) {
8893
- mkdirSync(join3(home, ".hasna"), { recursive: true });
9019
+ mkdirSync(join4(home, ".hasna"), { recursive: true });
8894
9020
  cpSync(oldDir, newDir, { recursive: true });
8895
9021
  }
8896
9022
  }
@@ -8906,12 +9032,12 @@ function getDbPath() {
8906
9032
  if (process.env["MEMENTOS_DB_SCOPE"] === "project") {
8907
9033
  const gitRoot = findGitRoot(cwd);
8908
9034
  if (gitRoot) {
8909
- return join3(gitRoot, ".mementos", "mementos.db");
9035
+ return join4(gitRoot, ".mementos", "mementos.db");
8910
9036
  }
8911
9037
  }
8912
9038
  migrateGlobalDir();
8913
9039
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
8914
- return join3(home, ".hasna", "mementos", "mementos.db");
9040
+ return join4(home, ".hasna", "mementos", "mementos.db");
8915
9041
  }
8916
9042
  function ensureDir(filePath) {
8917
9043
  if (isInMemoryDb(filePath))
@@ -11768,8 +11894,8 @@ function logSearchQuery(query, resultCount, agentId, projectId, db) {
11768
11894
  }
11769
11895
  // src/lib/config.ts
11770
11896
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync, writeFileSync, unlinkSync, cpSync as cpSync2 } from "fs";
11771
- import { homedir as homedir3 } from "os";
11772
- import { basename, dirname as dirname2, join as join5, resolve as resolve2 } from "path";
11897
+ import { homedir as homedir4 } from "os";
11898
+ import { basename, dirname as dirname2, join as join6, resolve as resolve2 } from "path";
11773
11899
  var DEFAULT_CONFIG = {
11774
11900
  default_scope: "private",
11775
11901
  default_category: "knowledge",
@@ -11826,7 +11952,7 @@ function isValidCategory(value) {
11826
11952
  return VALID_CATEGORIES.includes(value);
11827
11953
  }
11828
11954
  function loadConfig() {
11829
- const configPath = join5(homedir3(), ".hasna", "mementos", "config.json");
11955
+ const configPath = join6(homedir4(), ".hasna", "mementos", "config.json");
11830
11956
  let fileConfig = {};
11831
11957
  if (existsSync2(configPath)) {
11832
11958
  try {
@@ -11853,10 +11979,10 @@ function loadConfig() {
11853
11979
  return merged;
11854
11980
  }
11855
11981
  function profilesDir() {
11856
- return join5(homedir3(), ".hasna", "mementos", "profiles");
11982
+ return join6(homedir4(), ".hasna", "mementos", "profiles");
11857
11983
  }
11858
11984
  function globalConfigPath() {
11859
- return join5(homedir3(), ".hasna", "mementos", "config.json");
11985
+ return join6(homedir4(), ".hasna", "mementos", "config.json");
11860
11986
  }
11861
11987
  function readGlobalConfig() {
11862
11988
  const p = globalConfigPath();
@@ -11896,7 +12022,7 @@ function listProfiles() {
11896
12022
  return readdirSync(dir).filter((f) => f.endsWith(".db")).map((f) => basename(f, ".db")).sort();
11897
12023
  }
11898
12024
  function deleteProfile(name) {
11899
- const dbPath = join5(profilesDir(), `${name}.db`);
12025
+ const dbPath = join6(profilesDir(), `${name}.db`);
11900
12026
  if (!existsSync2(dbPath))
11901
12027
  return false;
11902
12028
  unlinkSync(dbPath);
@@ -12259,17 +12385,17 @@ function runCleanup(config, db) {
12259
12385
  }
12260
12386
  // src/lib/sync.ts
12261
12387
  import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
12262
- import { homedir as homedir5 } from "os";
12263
- import { join as join6 } from "path";
12388
+ import { homedir as homedir6 } from "os";
12389
+ import { join as join7 } from "path";
12264
12390
  function getAgentSyncDir(agentName) {
12265
- const dir = join6(homedir5(), ".hasna", "mementos", "agents", agentName);
12391
+ const dir = join7(homedir6(), ".hasna", "mementos", "agents", agentName);
12266
12392
  if (!existsSync3(dir)) {
12267
12393
  mkdirSync3(dir, { recursive: true });
12268
12394
  }
12269
12395
  return dir;
12270
12396
  }
12271
12397
  function setHighWaterMark(agentDir, timestamp) {
12272
- const markFile = join6(agentDir, ".highwatermark");
12398
+ const markFile = join7(agentDir, ".highwatermark");
12273
12399
  writeFileSync2(markFile, timestamp, "utf-8");
12274
12400
  }
12275
12401
  function resolveConflict(local, remote, resolution) {
@@ -12290,7 +12416,7 @@ function pushMemories(agentName, agentId, projectId, db) {
12290
12416
  status: "active",
12291
12417
  limit: 1e4
12292
12418
  }, db);
12293
- const outFile = join6(agentDir, "memories.json");
12419
+ const outFile = join7(agentDir, "memories.json");
12294
12420
  writeFileSync2(outFile, JSON.stringify(memories, null, 2), "utf-8");
12295
12421
  if (memories.length > 0) {
12296
12422
  const latest = memories.reduce((a, b) => new Date(a.updated_at).getTime() > new Date(b.updated_at).getTime() ? a : b);
@@ -12300,7 +12426,7 @@ function pushMemories(agentName, agentId, projectId, db) {
12300
12426
  }
12301
12427
  function pullMemories(agentName, conflictResolution = "prefer-newer", db) {
12302
12428
  const agentDir = getAgentSyncDir(agentName);
12303
- const inFile = join6(agentDir, "memories.json");
12429
+ const inFile = join7(agentDir, "memories.json");
12304
12430
  if (!existsSync3(inFile)) {
12305
12431
  return { pulled: 0, conflicts: 0 };
12306
12432
  }
@@ -13369,11 +13495,11 @@ var gatherTrainingData = async (options = {}) => {
13369
13495
  };
13370
13496
  // src/lib/model-config.ts
13371
13497
  import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
13372
- import { homedir as homedir6 } from "os";
13373
- import { join as join7 } from "path";
13498
+ import { homedir as homedir7 } from "os";
13499
+ import { join as join8 } from "path";
13374
13500
  var DEFAULT_MODEL = "gpt-4o-mini";
13375
- var CONFIG_DIR2 = join7(homedir6(), ".hasna", "mementos");
13376
- var CONFIG_PATH2 = join7(CONFIG_DIR2, "config.json");
13501
+ var CONFIG_DIR2 = join8(homedir7(), ".hasna", "mementos");
13502
+ var CONFIG_PATH2 = join8(CONFIG_DIR2, "config.json");
13377
13503
  function readConfig() {
13378
13504
  if (!existsSync4(CONFIG_PATH2))
13379
13505
  return {};
package/dist/mcp/index.js CHANGED
@@ -116,6 +116,8 @@ import { homedir as homedir2 } from "os";
116
116
  import { join as join2 } from "path";
117
117
  import { homedir } from "os";
118
118
  import { join, relative } from "path";
119
+ import { homedir as homedir3 } from "os";
120
+ import { join as join3 } from "path";
119
121
  function __accessProp2(key) {
120
122
  return this[key];
121
123
  }
@@ -149,6 +151,9 @@ class SqliteAdapter {
149
151
  exec(sql) {
150
152
  this.db.exec(sql);
151
153
  }
154
+ query(sql) {
155
+ return this.db.query(sql);
156
+ }
152
157
  prepare(sql) {
153
158
  const stmt = this.db.prepare(sql);
154
159
  return {
@@ -749,6 +754,126 @@ function custom2(check, _params = {}, fatal) {
749
754
  });
750
755
  return ZodAny2.create();
751
756
  }
757
+
758
+ class SyncProgressTracker {
759
+ db;
760
+ progress = new Map;
761
+ startTimes = new Map;
762
+ callback;
763
+ constructor(db, callback) {
764
+ this.db = db;
765
+ this.callback = callback;
766
+ this.ensureResumeTable();
767
+ }
768
+ ensureResumeTable() {
769
+ this.db.exec(`
770
+ CREATE TABLE IF NOT EXISTS _sync_resume (
771
+ table_name TEXT PRIMARY KEY,
772
+ last_row_id TEXT,
773
+ direction TEXT,
774
+ started_at TEXT,
775
+ status TEXT DEFAULT 'in_progress'
776
+ )
777
+ `);
778
+ }
779
+ start(table, total, direction) {
780
+ const resumed = this.canResume(table);
781
+ const now = Date.now();
782
+ this.startTimes.set(table, now);
783
+ const status = resumed ? "resumed" : "in_progress";
784
+ const info = {
785
+ table,
786
+ total,
787
+ done: 0,
788
+ percent: 0,
789
+ elapsed_ms: 0,
790
+ eta_ms: 0,
791
+ status
792
+ };
793
+ this.progress.set(table, info);
794
+ this.db.run(`INSERT INTO _sync_resume (table_name, last_row_id, direction, started_at, status)
795
+ VALUES (?, ?, ?, datetime('now'), ?)
796
+ ON CONFLICT (table_name) DO UPDATE SET
797
+ direction = excluded.direction,
798
+ started_at = datetime('now'),
799
+ status = excluded.status`, table, "", direction, status);
800
+ this.notify(table);
801
+ }
802
+ update(table, done, lastRowId) {
803
+ const info = this.progress.get(table);
804
+ if (!info)
805
+ return;
806
+ const startTime = this.startTimes.get(table) ?? Date.now();
807
+ const elapsed = Date.now() - startTime;
808
+ const rate = done > 0 ? elapsed / done : 0;
809
+ const remaining = info.total - done;
810
+ const eta = remaining > 0 ? Math.round(rate * remaining) : 0;
811
+ info.done = done;
812
+ info.percent = info.total > 0 ? Math.round(done / info.total * 100) : 0;
813
+ info.elapsed_ms = elapsed;
814
+ info.eta_ms = eta;
815
+ info.status = "in_progress";
816
+ this.db.run(`UPDATE _sync_resume SET last_row_id = ?, status = 'in_progress' WHERE table_name = ?`, lastRowId, table);
817
+ this.notify(table);
818
+ }
819
+ markComplete(table) {
820
+ const info = this.progress.get(table);
821
+ if (info) {
822
+ const startTime = this.startTimes.get(table) ?? Date.now();
823
+ info.elapsed_ms = Date.now() - startTime;
824
+ info.done = info.total;
825
+ info.percent = 100;
826
+ info.eta_ms = 0;
827
+ info.status = "completed";
828
+ this.notify(table);
829
+ }
830
+ this.db.run(`UPDATE _sync_resume SET status = 'completed' WHERE table_name = ?`, table);
831
+ }
832
+ markFailed(table, _error) {
833
+ const info = this.progress.get(table);
834
+ if (info) {
835
+ const startTime = this.startTimes.get(table) ?? Date.now();
836
+ info.elapsed_ms = Date.now() - startTime;
837
+ info.status = "failed";
838
+ this.notify(table);
839
+ }
840
+ this.db.run(`UPDATE _sync_resume SET status = 'failed' WHERE table_name = ?`, table);
841
+ }
842
+ canResume(table) {
843
+ const row = this.db.get(`SELECT status FROM _sync_resume WHERE table_name = ?`, table);
844
+ if (!row)
845
+ return false;
846
+ return row.status === "in_progress" || row.status === "resumed";
847
+ }
848
+ getResumePoint(table) {
849
+ const row = this.db.get(`SELECT table_name, last_row_id, direction, started_at, status FROM _sync_resume WHERE table_name = ?`, table);
850
+ if (!row)
851
+ return null;
852
+ if (row.status !== "in_progress" && row.status !== "resumed")
853
+ return null;
854
+ return row;
855
+ }
856
+ clearResume(table) {
857
+ this.db.run(`DELETE FROM _sync_resume WHERE table_name = ?`, table);
858
+ this.progress.delete(table);
859
+ this.startTimes.delete(table);
860
+ }
861
+ getProgress(table) {
862
+ return this.progress.get(table) ?? null;
863
+ }
864
+ getAllProgress() {
865
+ return Array.from(this.progress.values());
866
+ }
867
+ listResumeRecords() {
868
+ return this.db.all(`SELECT table_name, last_row_id, direction, started_at, status FROM _sync_resume ORDER BY started_at DESC`);
869
+ }
870
+ notify(table) {
871
+ const info = this.progress.get(table);
872
+ if (info && this.callback) {
873
+ this.callback({ ...info });
874
+ }
875
+ }
876
+ }
752
877
  var __create, __getProtoOf, __defProp2, __getOwnPropNames2, __hasOwnProp2, __toESMCache_node, __toESMCache_esm, __toESM = (mod, isNodeMode, target) => {
753
878
  var canCache = mod != null && typeof mod === "object";
754
879
  if (canCache) {
@@ -992,7 +1117,7 @@ var __create, __getProtoOf, __defProp2, __getOwnPropNames2, __hasOwnProp2, __toE
992
1117
  }
993
1118
  }, ZodDiscriminatedUnion2, ZodIntersection2, ZodTuple2, ZodRecord2, ZodMap2, ZodSet2, ZodFunction2, ZodLazy2, ZodLiteral2, ZodEnum2, ZodNativeEnum2, ZodPromise2, ZodEffects2, ZodOptional2, ZodNullable2, ZodDefault2, ZodCatch2, ZodNaN2, BRAND2, ZodBranded2, ZodPipeline2, ZodReadonly2, late2, ZodFirstPartyTypeKind2, instanceOfType2 = (cls, params = {
994
1119
  message: `Input not instance of ${cls.name}`
995
- }) => custom2((data) => data instanceof cls, params), stringType2, numberType2, nanType2, bigIntType2, booleanType2, dateType2, symbolType2, undefinedType2, nullType2, anyType2, unknownType2, neverType2, voidType2, arrayType2, objectType2, strictObjectType2, unionType2, discriminatedUnionType2, intersectionType2, tupleType2, recordType2, mapType2, setType2, functionType2, lazyType2, literalType2, enumType2, nativeEnumType2, promiseType2, effectsType2, optionalType2, nullableType2, preprocessType2, pipelineType2, ostring2 = () => stringType2().optional(), onumber2 = () => numberType2().optional(), oboolean2 = () => booleanType2().optional(), coerce2, NEVER2, HASNA_DIR, CloudConfigSchema, CONFIG_DIR, CONFIG_PATH;
1120
+ }) => custom2((data) => data instanceof cls, params), stringType2, numberType2, nanType2, bigIntType2, booleanType2, dateType2, symbolType2, undefinedType2, nullType2, anyType2, unknownType2, neverType2, voidType2, arrayType2, objectType2, strictObjectType2, unionType2, discriminatedUnionType2, intersectionType2, tupleType2, recordType2, mapType2, setType2, functionType2, lazyType2, literalType2, enumType2, nativeEnumType2, promiseType2, effectsType2, optionalType2, nullableType2, preprocessType2, pipelineType2, ostring2 = () => stringType2().optional(), onumber2 = () => numberType2().optional(), oboolean2 = () => booleanType2().optional(), coerce2, NEVER2, HASNA_DIR, CloudConfigSchema, CONFIG_DIR, CONFIG_PATH, AUTO_SYNC_CONFIG_PATH;
996
1121
  var init_dist = __esm(() => {
997
1122
  __create = Object.create;
998
1123
  __getProtoOf = Object.getPrototypeOf;
@@ -8935,6 +9060,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
8935
9060
  });
8936
9061
  CONFIG_DIR = join2(homedir2(), ".hasna", "cloud");
8937
9062
  CONFIG_PATH = join2(CONFIG_DIR, "config.json");
9063
+ AUTO_SYNC_CONFIG_PATH = join3(homedir3(), ".hasna", "cloud", "config.json");
8938
9064
  });
8939
9065
 
8940
9066
  // src/db/database.ts
@@ -8950,14 +9076,14 @@ __export(exports_database, {
8950
9076
  closeDatabase: () => closeDatabase
8951
9077
  });
8952
9078
  import { existsSync, mkdirSync, cpSync } from "fs";
8953
- import { dirname, join as join3, resolve } from "path";
9079
+ import { dirname, join as join4, resolve } from "path";
8954
9080
  function isInMemoryDb(path) {
8955
9081
  return path === ":memory:" || path.startsWith("file::memory:");
8956
9082
  }
8957
9083
  function findNearestMementosDb(startDir) {
8958
9084
  let dir = resolve(startDir);
8959
9085
  while (true) {
8960
- const candidate = join3(dir, ".mementos", "mementos.db");
9086
+ const candidate = join4(dir, ".mementos", "mementos.db");
8961
9087
  if (existsSync(candidate))
8962
9088
  return candidate;
8963
9089
  const parent = dirname(dir);
@@ -8970,7 +9096,7 @@ function findNearestMementosDb(startDir) {
8970
9096
  function findGitRoot(startDir) {
8971
9097
  let dir = resolve(startDir);
8972
9098
  while (true) {
8973
- if (existsSync(join3(dir, ".git")))
9099
+ if (existsSync(join4(dir, ".git")))
8974
9100
  return dir;
8975
9101
  const parent = dirname(dir);
8976
9102
  if (parent === dir)
@@ -8981,10 +9107,10 @@ function findGitRoot(startDir) {
8981
9107
  }
8982
9108
  function migrateGlobalDir() {
8983
9109
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
8984
- const newDir = join3(home, ".hasna", "mementos");
8985
- const oldDir = join3(home, ".mementos");
9110
+ const newDir = join4(home, ".hasna", "mementos");
9111
+ const oldDir = join4(home, ".mementos");
8986
9112
  if (!existsSync(newDir) && existsSync(oldDir)) {
8987
- mkdirSync(join3(home, ".hasna"), { recursive: true });
9113
+ mkdirSync(join4(home, ".hasna"), { recursive: true });
8988
9114
  cpSync(oldDir, newDir, { recursive: true });
8989
9115
  }
8990
9116
  }
@@ -9000,12 +9126,12 @@ function getDbPath() {
9000
9126
  if (process.env["MEMENTOS_DB_SCOPE"] === "project") {
9001
9127
  const gitRoot = findGitRoot(cwd);
9002
9128
  if (gitRoot) {
9003
- return join3(gitRoot, ".mementos", "mementos.db");
9129
+ return join4(gitRoot, ".mementos", "mementos.db");
9004
9130
  }
9005
9131
  }
9006
9132
  migrateGlobalDir();
9007
9133
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
9008
- return join3(home, ".hasna", "mementos", "mementos.db");
9134
+ return join4(home, ".hasna", "mementos", "mementos.db");
9009
9135
  }
9010
9136
  function ensureDir(filePath) {
9011
9137
  if (isInMemoryDb(filePath))
@@ -13902,8 +14028,8 @@ var init_export_v1 = __esm(() => {
13902
14028
 
13903
14029
  // src/lib/config.ts
13904
14030
  import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, readdirSync as readdirSync3, writeFileSync, unlinkSync, cpSync as cpSync2 } from "fs";
13905
- import { homedir as homedir3 } from "os";
13906
- import { basename as basename3, dirname as dirname5, join as join9, resolve as resolve4 } from "path";
14031
+ import { homedir as homedir4 } from "os";
14032
+ import { basename as basename3, dirname as dirname5, join as join10, resolve as resolve4 } from "path";
13907
14033
  function deepMerge(target, source) {
13908
14034
  const result = { ...target };
13909
14035
  for (const key of Object.keys(source)) {
@@ -13924,7 +14050,7 @@ function isValidCategory(value) {
13924
14050
  return VALID_CATEGORIES.includes(value);
13925
14051
  }
13926
14052
  function loadConfig() {
13927
- const configPath = join9(homedir3(), ".hasna", "mementos", "config.json");
14053
+ const configPath = join10(homedir4(), ".hasna", "mementos", "config.json");
13928
14054
  let fileConfig = {};
13929
14055
  if (existsSync6(configPath)) {
13930
14056
  try {
@@ -14976,7 +15102,7 @@ var require_package = __commonJS((exports, module) => {
14976
15102
  author: "Andrei Hasna <andrei@hasna.com>",
14977
15103
  license: "Apache-2.0",
14978
15104
  dependencies: {
14979
- "@hasna/cloud": "^0.1.0",
15105
+ "@hasna/cloud": "0.1.5",
14980
15106
  "@modelcontextprotocol/sdk": "^1.12.1",
14981
15107
  chalk: "^5.4.1",
14982
15108
  commander: "^13.1.0",
@@ -19362,11 +19488,11 @@ init_search();
19362
19488
  // src/lib/project-detect.ts
19363
19489
  init_database();
19364
19490
  import { existsSync as existsSync2 } from "fs";
19365
- import { basename, dirname as dirname2, join as join5, resolve as resolve2 } from "path";
19491
+ import { basename, dirname as dirname2, join as join6, resolve as resolve2 } from "path";
19366
19492
  function findGitRoot2(startDir) {
19367
19493
  let dir = resolve2(startDir);
19368
19494
  while (true) {
19369
- if (existsSync2(join5(dir, ".git")))
19495
+ if (existsSync2(join6(dir, ".git")))
19370
19496
  return dir;
19371
19497
  const parent = dirname2(dir);
19372
19498
  if (parent === dir)
@@ -19452,7 +19578,7 @@ init_database();
19452
19578
  init_entities();
19453
19579
  init_relations();
19454
19580
  import { readdirSync, readFileSync, statSync, existsSync as existsSync3 } from "fs";
19455
- import { join as join6, resolve as resolve3, relative as relative2, dirname as dirname3, extname, basename as basename2 } from "path";
19581
+ import { join as join7, resolve as resolve3, relative as relative2, dirname as dirname3, extname, basename as basename2 } from "path";
19456
19582
  var DEFAULT_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".py", ".go", ".rs"];
19457
19583
  var DEFAULT_EXCLUDES = ["node_modules", ".git", "dist", "build", ".next", "__pycache__", "target", "vendor"];
19458
19584
  function parseImports(_filePath, content) {
@@ -19489,7 +19615,7 @@ function resolveImport(fromFile, importPath, allFiles) {
19489
19615
  const withExt = base + ext;
19490
19616
  if (allFiles.has(withExt))
19491
19617
  return withExt;
19492
- const index = join6(base, `index${ext}`);
19618
+ const index = join7(base, `index${ext}`);
19493
19619
  if (allFiles.has(index))
19494
19620
  return index;
19495
19621
  }
@@ -19507,7 +19633,7 @@ function collectFiles(dir, extensions, excludes) {
19507
19633
  for (const entry of entries) {
19508
19634
  if (excludes.some((e) => entry === e || current.includes(`/${e}/`)))
19509
19635
  continue;
19510
- const full = join6(current, entry);
19636
+ const full = join7(current, entry);
19511
19637
  let stat;
19512
19638
  try {
19513
19639
  stat = statSync(full);
@@ -21073,22 +21199,22 @@ async function _processNext() {
21073
21199
 
21074
21200
  // src/lib/session-watcher.ts
21075
21201
  import { watch, existsSync as existsSync4, statSync as statSync2, readFileSync as readFileSync2 } from "fs";
21076
- import { join as join7 } from "path";
21202
+ import { join as join8 } from "path";
21077
21203
  import { readdirSync as readdirSync2 } from "fs";
21078
21204
  function encodeCwd(cwd) {
21079
21205
  return cwd.replace(/\//g, "-");
21080
21206
  }
21081
21207
  function getProjectsDir() {
21082
21208
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
21083
- return join7(home, ".claude", "projects");
21209
+ return join8(home, ".claude", "projects");
21084
21210
  }
21085
21211
  function findActiveSession(projectDir) {
21086
21212
  if (!existsSync4(projectDir))
21087
21213
  return null;
21088
21214
  const files = readdirSync2(projectDir).filter((f) => f.endsWith(".jsonl")).map((f) => ({
21089
21215
  name: f,
21090
- path: join7(projectDir, f),
21091
- mtime: statSync2(join7(projectDir, f)).mtimeMs
21216
+ path: join8(projectDir, f),
21217
+ mtime: statSync2(join8(projectDir, f)).mtimeMs
21092
21218
  })).sort((a, b) => b.mtime - a.mtime);
21093
21219
  return files[0]?.path || null;
21094
21220
  }
@@ -21131,7 +21257,7 @@ function processNewLines(filePath, callback) {
21131
21257
  }
21132
21258
  function startSessionWatcher(cwd, callback) {
21133
21259
  stopSessionWatcher();
21134
- const projectDir = join7(getProjectsDir(), encodeCwd(cwd));
21260
+ const projectDir = join8(getProjectsDir(), encodeCwd(cwd));
21135
21261
  const sessionFile = findActiveSession(projectDir);
21136
21262
  if (!sessionFile) {
21137
21263
  return { sessionFile: null };
@@ -21364,8 +21490,8 @@ function getRecentlyPushedCount() {
21364
21490
  // src/lib/session-registry.ts
21365
21491
  import { Database as Database2 } from "bun:sqlite";
21366
21492
  import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
21367
- import { dirname as dirname4, join as join8 } from "path";
21368
- var DB_PATH = join8(process.env["HOME"] || process.env["USERPROFILE"] || "~", ".open-sessions-registry.db");
21493
+ import { dirname as dirname4, join as join9 } from "path";
21494
+ var DB_PATH = join9(process.env["HOME"] || process.env["USERPROFILE"] || "~", ".open-sessions-registry.db");
21369
21495
  var _db2 = null;
21370
21496
  function getDb() {
21371
21497
  if (_db2)