@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/README.md +17 -219
- package/dist/cli/index.js +174 -48
- package/dist/index.js +151 -25
- package/dist/mcp/index.js +154 -27
- package/dist/server/index.js +158 -32
- package/package.json +5 -4
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
10975
|
-
const oldDir =
|
|
11100
|
+
const newDir = join4(home, ".hasna", "mementos");
|
|
11101
|
+
const oldDir = join4(home, ".mementos");
|
|
10976
11102
|
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
10977
|
-
mkdirSync(
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
17343
|
-
import { homedir as
|
|
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
|
|
17565
|
-
import { basename, dirname as dirname2, join as
|
|
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 =
|
|
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
|
|
17775
|
+
return join6(homedir4(), ".hasna", "mementos", "profiles");
|
|
17650
17776
|
}
|
|
17651
17777
|
function globalConfigPath() {
|
|
17652
|
-
return
|
|
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 =
|
|
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
|
|
17835
|
-
import { join as
|
|
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
|
|
17914
|
-
import { join as
|
|
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 =
|
|
17917
|
-
var CONFIG_PATH2 =
|
|
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 ??
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
18407
|
-
const hookDest =
|
|
18408
|
-
const settingsPath =
|
|
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
|
-
|
|
18434
|
-
|
|
18435
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
20878
|
+
return join10(homedir8(), ".hasna", "mementos", "config.json");
|
|
20753
20879
|
}
|
|
20754
20880
|
function readFileConfig() {
|
|
20755
20881
|
const configPath = getConfigPath();
|