@hasna/mementos 0.14.58 → 0.14.59
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/commands/info-report.d.ts.map +1 -1
- package/dist/cli/index.js +266 -113
- package/dist/db/api-mode.d.ts.map +1 -1
- package/dist/db/memories.d.ts +32 -0
- package/dist/db/memories.d.ts.map +1 -1
- package/dist/index.js +110 -65
- package/dist/lib/asmr/recall.d.ts +3 -0
- package/dist/lib/asmr/recall.d.ts.map +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +239 -267
- package/dist/mcp/tools/graph-utils.d.ts.map +1 -1
- package/dist/mcp/tools/memory-crud.d.ts.map +1 -1
- package/dist/mcp/tools/memory-search.d.ts.map +1 -1
- package/dist/mcp/tools/storage-tools.d.ts.map +1 -1
- package/dist/mcp/tools/system-tools-memory-admin.d.ts +1 -1
- package/dist/mcp/tools/system-tools-memory-admin.d.ts.map +1 -1
- package/dist/mcp/tools/system-tools-shared.d.ts.map +1 -1
- package/dist/mcp/tools/utility-tools.d.ts.map +1 -1
- package/dist/server/index.js +722 -53
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/lib/remote-sync.d.ts +0 -49
- package/dist/lib/remote-sync.d.ts.map +0 -1
- package/dist/mcp/tools/memory-sync.d.ts +0 -3
- package/dist/mcp/tools/memory-sync.d.ts.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -2703,6 +2703,10 @@ var init_storage = __esm(() => {
|
|
|
2703
2703
|
});
|
|
2704
2704
|
|
|
2705
2705
|
// src/db/api-mode.ts
|
|
2706
|
+
import { tmpdir } from "os";
|
|
2707
|
+
import { join as join3 } from "path";
|
|
2708
|
+
import { writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
2709
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
2706
2710
|
function firstEnv(...keys) {
|
|
2707
2711
|
for (const k of keys) {
|
|
2708
2712
|
const v = process.env[k]?.trim();
|
|
@@ -2738,33 +2742,60 @@ function apiRequestRaw(method, path, body) {
|
|
|
2738
2742
|
throw new Error("api-mode: not configured (HASNA_MEMENTOS_API_URL / HASNA_MEMENTOS_API_KEY)");
|
|
2739
2743
|
const url = `${cfg.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
2740
2744
|
const hasBody = body !== undefined && body !== null;
|
|
2741
|
-
const
|
|
2742
|
-
const
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2745
|
+
const timeout = process.env["HASNA_MEMENTOS_API_TIMEOUT"] || DEFAULT_TIMEOUT_S;
|
|
2746
|
+
const headerLines = `Authorization: Bearer ${cfg.apiKey}
|
|
2747
|
+
x-api-key: ${cfg.apiKey}
|
|
2748
|
+
`;
|
|
2749
|
+
const args = [
|
|
2750
|
+
"curl",
|
|
2751
|
+
"-sS",
|
|
2752
|
+
"--fail-with-body",
|
|
2753
|
+
"-m",
|
|
2754
|
+
timeout,
|
|
2755
|
+
"-X",
|
|
2756
|
+
method,
|
|
2757
|
+
"-H",
|
|
2758
|
+
"@-",
|
|
2759
|
+
"-H",
|
|
2760
|
+
"Content-Type: application/json",
|
|
2761
|
+
"-H",
|
|
2762
|
+
"Accept: application/json",
|
|
2763
|
+
"-w",
|
|
2764
|
+
"\\n%{http_code}"
|
|
2765
|
+
];
|
|
2766
|
+
let bodyFile;
|
|
2767
|
+
if (hasBody) {
|
|
2768
|
+
bodyFile = join3(tmpdir(), `mem-req-${process.pid}-${randomUUID3()}.json`);
|
|
2769
|
+
writeFileSync2(bodyFile, JSON.stringify(body), { mode: 384 });
|
|
2770
|
+
args.push("--data-binary", `@${bodyFile}`);
|
|
2771
|
+
}
|
|
2772
|
+
args.push(url);
|
|
2773
|
+
const childEnv = {};
|
|
2774
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
2775
|
+
if (v === undefined)
|
|
2776
|
+
continue;
|
|
2777
|
+
if (k === "HASNA_MEMENTOS_API_KEY" || k === "MEMENTOS_API_KEY")
|
|
2778
|
+
continue;
|
|
2779
|
+
childEnv[k] = v;
|
|
2780
|
+
}
|
|
2781
|
+
let out = "";
|
|
2782
|
+
let err = "";
|
|
2783
|
+
try {
|
|
2784
|
+
const proc = Bun.spawnSync(args, {
|
|
2785
|
+
stdin: Buffer.from(headerLines),
|
|
2786
|
+
stdout: "pipe",
|
|
2787
|
+
stderr: "pipe",
|
|
2788
|
+
env: childEnv
|
|
2789
|
+
});
|
|
2790
|
+
out = proc.stdout ? new TextDecoder().decode(proc.stdout) : "";
|
|
2791
|
+
err = proc.stderr ? new TextDecoder().decode(proc.stderr) : "";
|
|
2792
|
+
} finally {
|
|
2793
|
+
if (bodyFile) {
|
|
2794
|
+
try {
|
|
2795
|
+
unlinkSync(bodyFile);
|
|
2796
|
+
} catch {}
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2768
2799
|
const nl = out.lastIndexOf(`
|
|
2769
2800
|
`);
|
|
2770
2801
|
const codeStr = nl >= 0 ? out.slice(nl + 1).trim() : "";
|
|
@@ -3743,7 +3774,7 @@ __export(exports_database, {
|
|
|
3743
3774
|
closeDatabase: () => closeDatabase
|
|
3744
3775
|
});
|
|
3745
3776
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, cpSync } from "fs";
|
|
3746
|
-
import { dirname, join as
|
|
3777
|
+
import { dirname, join as join4, resolve } from "path";
|
|
3747
3778
|
function isInMemoryDb(path) {
|
|
3748
3779
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
3749
3780
|
}
|
|
@@ -3752,7 +3783,7 @@ function findNearestMementosDb(startDir) {
|
|
|
3752
3783
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
3753
3784
|
const legacyHomeDb = resolve(home, ".mementos", "mementos.db");
|
|
3754
3785
|
while (true) {
|
|
3755
|
-
const candidate =
|
|
3786
|
+
const candidate = join4(dir, ".mementos", "mementos.db");
|
|
3756
3787
|
if (existsSync3(candidate) && resolve(candidate) !== legacyHomeDb)
|
|
3757
3788
|
return candidate;
|
|
3758
3789
|
const parent = dirname(dir);
|
|
@@ -3765,7 +3796,7 @@ function findNearestMementosDb(startDir) {
|
|
|
3765
3796
|
function findGitRoot(startDir) {
|
|
3766
3797
|
let dir = resolve(startDir);
|
|
3767
3798
|
while (true) {
|
|
3768
|
-
if (existsSync3(
|
|
3799
|
+
if (existsSync3(join4(dir, ".git")))
|
|
3769
3800
|
return dir;
|
|
3770
3801
|
const parent = dirname(dir);
|
|
3771
3802
|
if (parent === dir)
|
|
@@ -3776,10 +3807,10 @@ function findGitRoot(startDir) {
|
|
|
3776
3807
|
}
|
|
3777
3808
|
function migrateGlobalDir() {
|
|
3778
3809
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
3779
|
-
const newDir =
|
|
3780
|
-
const oldDir =
|
|
3810
|
+
const newDir = join4(home, ".hasna", "mementos");
|
|
3811
|
+
const oldDir = join4(home, ".mementos");
|
|
3781
3812
|
if (!existsSync3(newDir) && existsSync3(oldDir)) {
|
|
3782
|
-
mkdirSync2(
|
|
3813
|
+
mkdirSync2(join4(home, ".hasna"), { recursive: true });
|
|
3783
3814
|
cpSync(oldDir, newDir, { recursive: true });
|
|
3784
3815
|
}
|
|
3785
3816
|
}
|
|
@@ -3795,12 +3826,12 @@ function getDbPath() {
|
|
|
3795
3826
|
if (process.env["MEMENTOS_DB_SCOPE"] === "project") {
|
|
3796
3827
|
const gitRoot = findGitRoot(cwd);
|
|
3797
3828
|
if (gitRoot) {
|
|
3798
|
-
return
|
|
3829
|
+
return join4(gitRoot, ".mementos", "mementos.db");
|
|
3799
3830
|
}
|
|
3800
3831
|
}
|
|
3801
3832
|
migrateGlobalDir();
|
|
3802
3833
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
3803
|
-
return
|
|
3834
|
+
return join4(home, ".hasna", "mementos", "mementos.db");
|
|
3804
3835
|
}
|
|
3805
3836
|
function ensureDir(filePath) {
|
|
3806
3837
|
if (isInMemoryDb(filePath))
|
|
@@ -4341,12 +4372,14 @@ __export(exports_memories, {
|
|
|
4341
4372
|
parseMemoryRow: () => parseMemoryRow,
|
|
4342
4373
|
listMemoryHistory: () => listMemoryHistory,
|
|
4343
4374
|
listMemories: () => listMemories,
|
|
4375
|
+
listLowTrustMemories: () => listLowTrustMemories,
|
|
4344
4376
|
indexMemoryEmbedding: () => indexMemoryEmbedding,
|
|
4345
4377
|
incrementRecallCount: () => incrementRecallCount,
|
|
4346
4378
|
getMemoryVersions: () => getMemoryVersions,
|
|
4347
4379
|
getMemoryEmbeddings: () => getMemoryEmbeddings,
|
|
4348
4380
|
getMemoryChain: () => getMemoryChain,
|
|
4349
4381
|
getMemoryByKey: () => getMemoryByKey,
|
|
4382
|
+
getMemoryBriefing: () => getMemoryBriefing,
|
|
4350
4383
|
getMemory: () => getMemory,
|
|
4351
4384
|
getMemoriesByKey: () => getMemoriesByKey,
|
|
4352
4385
|
deleteMemory: () => deleteMemory,
|
|
@@ -4356,6 +4389,14 @@ __export(exports_memories, {
|
|
|
4356
4389
|
bulkDeleteMemories: () => bulkDeleteMemories
|
|
4357
4390
|
});
|
|
4358
4391
|
function runEntityExtraction(_memory, _projectId, _d) {}
|
|
4392
|
+
function applyContentType(d, id, memory, contentType) {
|
|
4393
|
+
if (!contentType || contentType === "text")
|
|
4394
|
+
return;
|
|
4395
|
+
try {
|
|
4396
|
+
d.run("UPDATE memories SET content_type = ? WHERE id = ?", [contentType, id]);
|
|
4397
|
+
memory.content_type = contentType;
|
|
4398
|
+
} catch {}
|
|
4399
|
+
}
|
|
4359
4400
|
function parseMemoryRow(row) {
|
|
4360
4401
|
return {
|
|
4361
4402
|
id: row["id"],
|
|
@@ -4460,6 +4501,7 @@ function createMemory(input, dedupeMode = "merge", db) {
|
|
|
4460
4501
|
insertTag2.run(existing.id, tag);
|
|
4461
4502
|
}
|
|
4462
4503
|
const merged = getMemory(existing.id, d);
|
|
4504
|
+
applyContentType(d, existing.id, merged, input.content_type);
|
|
4463
4505
|
try {
|
|
4464
4506
|
const existingMemories = listMemoriesByKey(input.key, d);
|
|
4465
4507
|
const trustScore = computeTrustScore(safeValue, input.key, existingMemories, input.importance);
|
|
@@ -4509,6 +4551,7 @@ function createMemory(input, dedupeMode = "merge", db) {
|
|
|
4509
4551
|
insertTag.run(id, tag);
|
|
4510
4552
|
}
|
|
4511
4553
|
const memory = getMemory(id, d);
|
|
4554
|
+
applyContentType(d, id, memory, input.content_type);
|
|
4512
4555
|
try {
|
|
4513
4556
|
const existingMemories = listMemoriesByKey(input.key, d);
|
|
4514
4557
|
const trustScore = computeTrustScore(safeValue, input.key, existingMemories, input.importance);
|
|
@@ -4843,6 +4886,66 @@ function listMemories(filter, db) {
|
|
|
4843
4886
|
const rows = d.query(sql).all(...params);
|
|
4844
4887
|
return rows.map(parseMemoryRow);
|
|
4845
4888
|
}
|
|
4889
|
+
function getMemoryBriefing(opts, db) {
|
|
4890
|
+
const limit = opts.limit ?? 20;
|
|
4891
|
+
if (!db && isApiMode()) {
|
|
4892
|
+
const q = toQuery({
|
|
4893
|
+
since: opts.since,
|
|
4894
|
+
scope: opts.scope,
|
|
4895
|
+
project_id: opts.project_id,
|
|
4896
|
+
machine_agnostic: opts.visible_machine_id === null || opts.visible_machine_id === undefined ? true : undefined,
|
|
4897
|
+
visible_machine_id: typeof opts.visible_machine_id === "string" ? opts.visible_machine_id : undefined,
|
|
4898
|
+
limit
|
|
4899
|
+
});
|
|
4900
|
+
const { data } = apiJson("GET", `/memories/briefing${q}`);
|
|
4901
|
+
return data ?? { new: [], updated: [], expired: [] };
|
|
4902
|
+
}
|
|
4903
|
+
const d = db || getDatabase();
|
|
4904
|
+
const visibleMachineId = opts.visible_machine_id;
|
|
4905
|
+
const scopeClause = opts.scope ? "AND scope = ?" : "";
|
|
4906
|
+
const projectClause = opts.project_id ? "AND project_id = ?" : "";
|
|
4907
|
+
const machineClause = typeof visibleMachineId === "string" ? "AND (machine_id IS NULL OR machine_id = ?)" : "AND machine_id IS NULL";
|
|
4908
|
+
const extraParams = [
|
|
4909
|
+
...opts.scope ? [opts.scope] : [],
|
|
4910
|
+
...opts.project_id ? [opts.project_id] : [],
|
|
4911
|
+
...typeof visibleMachineId === "string" ? [visibleMachineId] : []
|
|
4912
|
+
];
|
|
4913
|
+
const newRows = d.prepare(`SELECT * FROM memories
|
|
4914
|
+
WHERE status = 'active' AND created_at > ? ${scopeClause} ${projectClause} ${machineClause}
|
|
4915
|
+
ORDER BY importance DESC, created_at DESC LIMIT ?`).all(opts.since, ...extraParams, limit);
|
|
4916
|
+
const updatedRows = d.prepare(`SELECT * FROM memories
|
|
4917
|
+
WHERE status = 'active' AND updated_at > ? AND created_at <= ? ${scopeClause} ${projectClause} ${machineClause}
|
|
4918
|
+
ORDER BY importance DESC, updated_at DESC LIMIT ?`).all(opts.since, opts.since, ...extraParams, limit);
|
|
4919
|
+
const expiredRows = d.prepare(`SELECT * FROM memories
|
|
4920
|
+
WHERE status != 'active' AND updated_at > ? ${scopeClause} ${projectClause} ${machineClause}
|
|
4921
|
+
ORDER BY updated_at DESC LIMIT ?`).all(opts.since, ...extraParams, Math.min(limit, 10));
|
|
4922
|
+
return {
|
|
4923
|
+
new: newRows.map(parseMemoryRow),
|
|
4924
|
+
updated: updatedRows.map(parseMemoryRow),
|
|
4925
|
+
expired: expiredRows.map(parseMemoryRow)
|
|
4926
|
+
};
|
|
4927
|
+
}
|
|
4928
|
+
function listLowTrustMemories(opts = {}, db) {
|
|
4929
|
+
const threshold = opts.threshold ?? 0.8;
|
|
4930
|
+
const limit = opts.limit ?? 20;
|
|
4931
|
+
const offset = opts.offset ?? 0;
|
|
4932
|
+
if (!db && isApiMode()) {
|
|
4933
|
+
const q = toQuery({ threshold, project_id: opts.project_id, limit, offset });
|
|
4934
|
+
const { data } = apiJson("GET", `/memories/audit${q}`);
|
|
4935
|
+
return data?.memories ?? [];
|
|
4936
|
+
}
|
|
4937
|
+
const d = db || getDatabase();
|
|
4938
|
+
const conditions = ["trust_score < ?", "status = 'active'"];
|
|
4939
|
+
const params = [threshold];
|
|
4940
|
+
if (opts.project_id) {
|
|
4941
|
+
const resolved = resolvePartialId(d, "projects", opts.project_id);
|
|
4942
|
+
conditions.push("project_id = ?");
|
|
4943
|
+
params.push(resolved ?? opts.project_id);
|
|
4944
|
+
}
|
|
4945
|
+
params.push(limit, offset);
|
|
4946
|
+
const rows = d.prepare(`SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY trust_score ASC LIMIT ? OFFSET ?`).all(...params);
|
|
4947
|
+
return rows.map(parseMemoryRow);
|
|
4948
|
+
}
|
|
4846
4949
|
function listMemoryHistory(opts = {}, db) {
|
|
4847
4950
|
const limit = opts.limit ?? 20;
|
|
4848
4951
|
const offset = opts.offset ?? 0;
|
|
@@ -5054,6 +5157,10 @@ function incrementRecallCount(id, db) {
|
|
|
5054
5157
|
} catch {}
|
|
5055
5158
|
}
|
|
5056
5159
|
function cleanExpiredMemories(db) {
|
|
5160
|
+
if (!db && isApiMode()) {
|
|
5161
|
+
const { data } = apiJson("POST", "/memories/clean");
|
|
5162
|
+
return data?.cleaned ?? 0;
|
|
5163
|
+
}
|
|
5057
5164
|
const d = db || getDatabase();
|
|
5058
5165
|
const timestamp = now2();
|
|
5059
5166
|
const countRow = d.query("SELECT COUNT(*) as c FROM memories WHERE expires_at IS NOT NULL AND expires_at < ?").get(timestamp);
|
|
@@ -5106,6 +5213,12 @@ async function semanticSearch(queryText, options = {}, db) {
|
|
|
5106
5213
|
}
|
|
5107
5214
|
const d = db || getDatabase();
|
|
5108
5215
|
const { threshold = 0.5, limit = 10, scope, agent_id, project_id } = options;
|
|
5216
|
+
if (options.index_missing) {
|
|
5217
|
+
const unindexed = d.prepare(`SELECT id, value, summary, when_to_use FROM memories
|
|
5218
|
+
WHERE status = 'active' AND id NOT IN (SELECT memory_id FROM memory_embeddings)
|
|
5219
|
+
LIMIT 100`).all();
|
|
5220
|
+
await Promise.all(unindexed.map((m) => indexMemoryEmbedding(m.id, m.when_to_use || [m.value, m.summary].filter(Boolean).join(" "), d)));
|
|
5221
|
+
}
|
|
5109
5222
|
const { embedding: queryEmbedding } = await generateEmbedding(queryText);
|
|
5110
5223
|
const conditions = ["m.status = 'active'", "e.embedding IS NOT NULL"];
|
|
5111
5224
|
const params = [];
|
|
@@ -5452,11 +5565,11 @@ __export(exports_helpers, {
|
|
|
5452
5565
|
});
|
|
5453
5566
|
import chalk from "chalk";
|
|
5454
5567
|
import { readFileSync as readFileSync2 } from "fs";
|
|
5455
|
-
import { dirname as dirname2, join as
|
|
5568
|
+
import { dirname as dirname2, join as join5, resolve as resolve2 } from "path";
|
|
5456
5569
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5457
5570
|
function getPackageVersion() {
|
|
5458
5571
|
try {
|
|
5459
|
-
const pkgPath =
|
|
5572
|
+
const pkgPath = join5(dirname2(fileURLToPath2(import.meta.url)), "..", "..", "package.json");
|
|
5460
5573
|
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
5461
5574
|
return pkg.version || "0.0.0";
|
|
5462
5575
|
} catch {
|
|
@@ -5965,7 +6078,7 @@ function validateConfigKeyValue(key, value, DEFAULT_CONFIG) {
|
|
|
5965
6078
|
}
|
|
5966
6079
|
function getConfigPath() {
|
|
5967
6080
|
const { homedir: homedir3 } = __require("os");
|
|
5968
|
-
return
|
|
6081
|
+
return join5(homedir3(), ".hasna", "mementos", "config.json");
|
|
5969
6082
|
}
|
|
5970
6083
|
function readFileConfig() {
|
|
5971
6084
|
const { existsSync: existsSync4 } = __require("fs");
|
|
@@ -5979,12 +6092,12 @@ function readFileConfig() {
|
|
|
5979
6092
|
}
|
|
5980
6093
|
}
|
|
5981
6094
|
function writeFileConfig(data) {
|
|
5982
|
-
const { existsSync: existsSync4, writeFileSync:
|
|
6095
|
+
const { existsSync: existsSync4, writeFileSync: writeFileSync3, mkdirSync: mkdirSync3 } = __require("fs");
|
|
5983
6096
|
const configPath = getConfigPath();
|
|
5984
6097
|
const dir = dirname2(configPath);
|
|
5985
6098
|
if (!existsSync4(dir))
|
|
5986
6099
|
mkdirSync3(dir, { recursive: true });
|
|
5987
|
-
|
|
6100
|
+
writeFileSync3(configPath, JSON.stringify(data, null, 2) + `
|
|
5988
6101
|
`, "utf-8");
|
|
5989
6102
|
}
|
|
5990
6103
|
var scopeColor, categoryColor, entityTypeColor, DEFAULT_COMPACT_LIMIT = 20, DEFAULT_SEARCH_LIMIT = 10, DEFAULT_SNIPPET_LENGTH = 72, VALID_SCOPES, VALID_CATEGORIES;
|
|
@@ -10553,7 +10666,7 @@ __export(exports_session_registry, {
|
|
|
10553
10666
|
cleanStaleSessions: () => cleanStaleSessions
|
|
10554
10667
|
});
|
|
10555
10668
|
import { existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
|
|
10556
|
-
import { dirname as dirname5, join as
|
|
10669
|
+
import { dirname as dirname5, join as join8 } from "path";
|
|
10557
10670
|
function getDb() {
|
|
10558
10671
|
if (_db2)
|
|
10559
10672
|
return _db2;
|
|
@@ -10733,7 +10846,7 @@ function closeRegistry() {
|
|
|
10733
10846
|
var DB_PATH, _db2 = null;
|
|
10734
10847
|
var init_session_registry = __esm(() => {
|
|
10735
10848
|
init_storage();
|
|
10736
|
-
DB_PATH =
|
|
10849
|
+
DB_PATH = join8(process.env["HOME"] || process.env["USERPROFILE"] || "~", ".open-sessions-registry.db");
|
|
10737
10850
|
});
|
|
10738
10851
|
|
|
10739
10852
|
// src/db/pg-migrations.ts
|
|
@@ -58795,7 +58908,7 @@ function collectValues(value, previous) {
|
|
|
58795
58908
|
// src/cli/index.tsx
|
|
58796
58909
|
init_database();
|
|
58797
58910
|
import { readFileSync as readFileSync8 } from "fs";
|
|
58798
|
-
import { dirname as dirname7, join as
|
|
58911
|
+
import { dirname as dirname7, join as join12 } from "path";
|
|
58799
58912
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
58800
58913
|
|
|
58801
58914
|
// src/db/machines.ts
|
|
@@ -59884,6 +59997,56 @@ function normalizeStats(data) {
|
|
|
59884
59997
|
expired_count: data?.expired_count ?? 0
|
|
59885
59998
|
};
|
|
59886
59999
|
}
|
|
60000
|
+
function getMemoryReport(filter = {}, db) {
|
|
60001
|
+
const days = Math.min(filter.days || 7, 365);
|
|
60002
|
+
if (!db && isApiMode()) {
|
|
60003
|
+
const q = toQuery({ days, project_id: filter.project_id, agent_id: filter.agent_id });
|
|
60004
|
+
const { data } = apiJson("GET", `/report${q}`);
|
|
60005
|
+
return {
|
|
60006
|
+
total: data?.total ?? 0,
|
|
60007
|
+
pinned: data?.pinned ?? 0,
|
|
60008
|
+
days: data?.days ?? days,
|
|
60009
|
+
recent: data?.recent ?? { total: 0, activity: [] },
|
|
60010
|
+
by_scope: data?.by_scope ?? {},
|
|
60011
|
+
by_category: data?.by_category ?? {},
|
|
60012
|
+
top_memories: data?.top_memories ?? [],
|
|
60013
|
+
top_agents: data?.top_agents ?? []
|
|
60014
|
+
};
|
|
60015
|
+
}
|
|
60016
|
+
const d = db || getDatabase();
|
|
60017
|
+
const cutoffDate = new Date(Date.now() - days * 86400000).toISOString().slice(0, 10);
|
|
60018
|
+
const scopedCond = [
|
|
60019
|
+
filter.project_id ? "AND project_id = ?" : "",
|
|
60020
|
+
filter.agent_id ? "AND agent_id = ?" : ""
|
|
60021
|
+
].filter(Boolean).join(" ");
|
|
60022
|
+
const scopedParams = [
|
|
60023
|
+
...filter.project_id ? [filter.project_id] : [],
|
|
60024
|
+
...filter.agent_id ? [filter.agent_id] : []
|
|
60025
|
+
];
|
|
60026
|
+
const recentParams = [cutoffDate, ...scopedParams];
|
|
60027
|
+
const total = d.query(`SELECT COUNT(*) as c FROM memories WHERE status = 'active' ${scopedCond}`).get(...scopedParams).c;
|
|
60028
|
+
const pinned = d.query(`SELECT COUNT(*) as c FROM memories WHERE status = 'active' AND pinned = 1 ${scopedCond}`).get(...scopedParams).c;
|
|
60029
|
+
const actRows = d.query(`
|
|
60030
|
+
SELECT date(created_at) AS date, COUNT(*) AS memories_created
|
|
60031
|
+
FROM memories WHERE status = 'active' AND date(created_at) >= ? ${scopedCond}
|
|
60032
|
+
GROUP BY date(created_at) ORDER BY date(created_at) ASC
|
|
60033
|
+
`).all(...recentParams);
|
|
60034
|
+
const recentTotal = actRows.reduce((s, r) => s + r.memories_created, 0);
|
|
60035
|
+
const byScopeRows = d.query(`SELECT scope, COUNT(*) as c FROM memories WHERE status = 'active' ${scopedCond} GROUP BY scope`).all(...scopedParams);
|
|
60036
|
+
const byCatRows = d.query(`SELECT category, COUNT(*) as c FROM memories WHERE status = 'active' ${scopedCond} GROUP BY category`).all(...scopedParams);
|
|
60037
|
+
const topMems = d.query(`SELECT id, key, value, importance, scope, category FROM memories WHERE status = 'active' ${scopedCond} ORDER BY importance DESC, access_count DESC LIMIT 5`).all(...scopedParams);
|
|
60038
|
+
const topAgents = d.query(`SELECT agent_id, COUNT(*) as c FROM memories WHERE status = 'active' AND agent_id IS NOT NULL ${scopedCond} GROUP BY agent_id ORDER BY c DESC LIMIT 5`).all(...scopedParams);
|
|
60039
|
+
return {
|
|
60040
|
+
total,
|
|
60041
|
+
pinned,
|
|
60042
|
+
days,
|
|
60043
|
+
recent: { total: recentTotal, activity: actRows },
|
|
60044
|
+
by_scope: Object.fromEntries(byScopeRows.map((r) => [r.scope, r.c])),
|
|
60045
|
+
by_category: Object.fromEntries(byCatRows.map((r) => [r.category, r.c])),
|
|
60046
|
+
top_memories: topMems,
|
|
60047
|
+
top_agents: topAgents
|
|
60048
|
+
};
|
|
60049
|
+
}
|
|
59887
60050
|
function getStaleMemories(filter = {}, db) {
|
|
59888
60051
|
const days = Math.min(filter.days || 30, 365);
|
|
59889
60052
|
const limit = filter.limit ?? 20;
|
|
@@ -59974,10 +60137,9 @@ function registerStatsCommand(program2) {
|
|
|
59974
60137
|
}
|
|
59975
60138
|
|
|
59976
60139
|
// src/cli/commands/info-report.ts
|
|
59977
|
-
init_database();
|
|
59978
|
-
init_projects();
|
|
59979
60140
|
import chalk14 from "chalk";
|
|
59980
60141
|
import { resolve as resolve8 } from "path";
|
|
60142
|
+
init_projects();
|
|
59981
60143
|
function registerReportCommand(program2) {
|
|
59982
60144
|
program2.command("report").description("Rich summary of memory activity and top memories").option("--days <n>", "Activity window in days (default: 7)", "7").option("--project <path>", "Filter by project path").option("--markdown", "Output as Markdown (for PRs, docs, etc.)").option("--json", "Output as JSON").action((opts) => {
|
|
59983
60145
|
try {
|
|
@@ -59992,24 +60154,15 @@ function registerReportCommand(program2) {
|
|
|
59992
60154
|
if (project)
|
|
59993
60155
|
projectId = project.id;
|
|
59994
60156
|
}
|
|
59995
|
-
const
|
|
59996
|
-
const
|
|
59997
|
-
const
|
|
59998
|
-
const
|
|
59999
|
-
const pinned = db.query(`SELECT COUNT(*) as c FROM memories WHERE status = 'active' AND pinned = 1 ${conditions}`).get(...params).c;
|
|
60000
|
-
const activityRows = db.query(`
|
|
60001
|
-
SELECT date(created_at) AS d, COUNT(*) AS cnt
|
|
60002
|
-
FROM memories WHERE status = 'active' AND date(created_at) >= date('now', '-${days} days') ${conditions}
|
|
60003
|
-
GROUP BY d ORDER BY d ASC
|
|
60004
|
-
`).all(...params);
|
|
60005
|
-
const recentTotal = activityRows.reduce((s, r) => s + r.cnt, 0);
|
|
60157
|
+
const report = getMemoryReport({ days, project_id: projectId });
|
|
60158
|
+
const { total, pinned } = report;
|
|
60159
|
+
const activityRows = report.recent.activity;
|
|
60160
|
+
const recentTotal = report.recent.total;
|
|
60006
60161
|
const avgPerDay = activityRows.length > 0 ? (recentTotal / activityRows.length).toFixed(1) : "0";
|
|
60007
|
-
const
|
|
60008
|
-
const
|
|
60009
|
-
const
|
|
60010
|
-
const
|
|
60011
|
-
const topMems = db.query(`SELECT key, value, importance, scope, category FROM memories WHERE status = 'active' ${conditions} ORDER BY importance DESC, access_count DESC LIMIT 5`).all(...params);
|
|
60012
|
-
const topAgents = db.query(`SELECT agent_id, COUNT(*) as c FROM memories WHERE status = 'active' AND agent_id IS NOT NULL ${conditions} GROUP BY agent_id ORDER BY c DESC LIMIT 5`).all(...params);
|
|
60162
|
+
const byScope = report.by_scope;
|
|
60163
|
+
const byCat = report.by_category;
|
|
60164
|
+
const topMems = report.top_memories;
|
|
60165
|
+
const topAgents = report.top_agents;
|
|
60013
60166
|
if (isJson) {
|
|
60014
60167
|
console.log(JSON.stringify({ total, pinned, recent: { days, total: recentTotal, avg_per_day: parseFloat(avgPerDay) }, by_scope: byScope, by_category: byCat, top_memories: topMems, top_agents: topAgents }, null, 2));
|
|
60015
60168
|
return;
|
|
@@ -60035,8 +60188,8 @@ function registerReportCommand(program2) {
|
|
|
60035
60188
|
}
|
|
60036
60189
|
const sparkline = activityRows.map((r) => {
|
|
60037
60190
|
const bars = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
60038
|
-
const maxC = Math.max(...activityRows.map((x) => x.
|
|
60039
|
-
return bars[Math.round(r.
|
|
60191
|
+
const maxC = Math.max(...activityRows.map((x) => x.memories_created), 1);
|
|
60192
|
+
return bars[Math.round(r.memories_created / maxC * 7)] || "\u2581";
|
|
60040
60193
|
}).join("");
|
|
60041
60194
|
console.log(chalk14.bold(`
|
|
60042
60195
|
mementos report \u2014 last ${days} days
|
|
@@ -60418,9 +60571,9 @@ function registerImportCommand(program2) {
|
|
|
60418
60571
|
import chalk19 from "chalk";
|
|
60419
60572
|
|
|
60420
60573
|
// src/lib/config.ts
|
|
60421
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync, writeFileSync as
|
|
60574
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, cpSync as cpSync2 } from "fs";
|
|
60422
60575
|
import { homedir as homedir3 } from "os";
|
|
60423
|
-
import { basename, dirname as dirname3, join as
|
|
60576
|
+
import { basename, dirname as dirname3, join as join6, resolve as resolve13 } from "path";
|
|
60424
60577
|
function isInMemoryDb2(path) {
|
|
60425
60578
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
60426
60579
|
}
|
|
@@ -60483,7 +60636,7 @@ function isValidCategory(value) {
|
|
|
60483
60636
|
return VALID_CATEGORIES2.includes(value);
|
|
60484
60637
|
}
|
|
60485
60638
|
function loadConfig() {
|
|
60486
|
-
const configPath =
|
|
60639
|
+
const configPath = join6(homeDir(), ".hasna", "mementos", "config.json");
|
|
60487
60640
|
let fileConfig = {};
|
|
60488
60641
|
if (existsSync4(configPath)) {
|
|
60489
60642
|
try {
|
|
@@ -60513,7 +60666,7 @@ function findFileWalkingUp(filename) {
|
|
|
60513
60666
|
let dir = process.cwd();
|
|
60514
60667
|
const legacyHomeMementosDb = resolve13(homeDir(), ".mementos", "mementos.db");
|
|
60515
60668
|
while (true) {
|
|
60516
|
-
const candidate =
|
|
60669
|
+
const candidate = join6(dir, filename);
|
|
60517
60670
|
if (existsSync4(candidate) && resolve13(candidate) !== legacyHomeMementosDb) {
|
|
60518
60671
|
return candidate;
|
|
60519
60672
|
}
|
|
@@ -60527,7 +60680,7 @@ function findFileWalkingUp(filename) {
|
|
|
60527
60680
|
function findGitRoot2() {
|
|
60528
60681
|
let dir = process.cwd();
|
|
60529
60682
|
while (true) {
|
|
60530
|
-
if (existsSync4(
|
|
60683
|
+
if (existsSync4(join6(dir, ".git"))) {
|
|
60531
60684
|
return dir;
|
|
60532
60685
|
}
|
|
60533
60686
|
const parent = dirname3(dir);
|
|
@@ -60538,10 +60691,10 @@ function findGitRoot2() {
|
|
|
60538
60691
|
}
|
|
60539
60692
|
}
|
|
60540
60693
|
function profilesDir() {
|
|
60541
|
-
return
|
|
60694
|
+
return join6(homeDir(), ".hasna", "mementos", "profiles");
|
|
60542
60695
|
}
|
|
60543
60696
|
function globalConfigPath() {
|
|
60544
|
-
return
|
|
60697
|
+
return join6(homeDir(), ".hasna", "mementos", "config.json");
|
|
60545
60698
|
}
|
|
60546
60699
|
function readGlobalConfig() {
|
|
60547
60700
|
const p = globalConfigPath();
|
|
@@ -60556,7 +60709,7 @@ function readGlobalConfig() {
|
|
|
60556
60709
|
function writeGlobalConfig(data) {
|
|
60557
60710
|
const p = globalConfigPath();
|
|
60558
60711
|
ensureDir2(dirname3(p));
|
|
60559
|
-
|
|
60712
|
+
writeFileSync3(p, JSON.stringify(data, null, 2), "utf-8");
|
|
60560
60713
|
}
|
|
60561
60714
|
function getActiveProfile() {
|
|
60562
60715
|
const envProfile = process.env["MEMENTOS_PROFILE"];
|
|
@@ -60581,20 +60734,20 @@ function listProfiles() {
|
|
|
60581
60734
|
return readdirSync(dir).filter((f) => f.endsWith(".db")).map((f) => basename(f, ".db")).sort();
|
|
60582
60735
|
}
|
|
60583
60736
|
function deleteProfile(name) {
|
|
60584
|
-
const dbPath =
|
|
60737
|
+
const dbPath = join6(profilesDir(), `${name}.db`);
|
|
60585
60738
|
if (!existsSync4(dbPath))
|
|
60586
60739
|
return false;
|
|
60587
|
-
|
|
60740
|
+
unlinkSync2(dbPath);
|
|
60588
60741
|
if (getActiveProfile() === name)
|
|
60589
60742
|
setActiveProfile(null);
|
|
60590
60743
|
return true;
|
|
60591
60744
|
}
|
|
60592
60745
|
function getDbPath2() {
|
|
60593
60746
|
const _home = homeDir();
|
|
60594
|
-
const _newDir =
|
|
60595
|
-
const _oldDir =
|
|
60747
|
+
const _newDir = join6(_home, ".hasna", "mementos");
|
|
60748
|
+
const _oldDir = join6(_home, ".mementos");
|
|
60596
60749
|
if (!existsSync4(_newDir) && existsSync4(_oldDir)) {
|
|
60597
|
-
mkdirSync3(
|
|
60750
|
+
mkdirSync3(join6(_home, ".hasna"), { recursive: true });
|
|
60598
60751
|
cpSync2(_oldDir, _newDir, { recursive: true });
|
|
60599
60752
|
}
|
|
60600
60753
|
const envDbPath = process.env["HASNA_MEMENTOS_DB_PATH"] ?? process.env["MEMENTOS_DB_PATH"];
|
|
@@ -60608,7 +60761,7 @@ function getDbPath2() {
|
|
|
60608
60761
|
}
|
|
60609
60762
|
const profile = getActiveProfile();
|
|
60610
60763
|
if (profile) {
|
|
60611
|
-
const profilePath =
|
|
60764
|
+
const profilePath = join6(profilesDir(), `${profile}.db`);
|
|
60612
60765
|
ensureDir2(dirname3(profilePath));
|
|
60613
60766
|
return profilePath;
|
|
60614
60767
|
}
|
|
@@ -60616,16 +60769,16 @@ function getDbPath2() {
|
|
|
60616
60769
|
if (dbScope === "project") {
|
|
60617
60770
|
const gitRoot = findGitRoot2();
|
|
60618
60771
|
if (gitRoot) {
|
|
60619
|
-
const dbPath =
|
|
60772
|
+
const dbPath = join6(gitRoot, ".mementos", "mementos.db");
|
|
60620
60773
|
ensureDir2(dirname3(dbPath));
|
|
60621
60774
|
return dbPath;
|
|
60622
60775
|
}
|
|
60623
60776
|
}
|
|
60624
|
-
const found = findFileWalkingUp(
|
|
60777
|
+
const found = findFileWalkingUp(join6(".mementos", "mementos.db"));
|
|
60625
60778
|
if (found) {
|
|
60626
60779
|
return found;
|
|
60627
60780
|
}
|
|
60628
|
-
const fallback =
|
|
60781
|
+
const fallback = join6(homeDir(), ".hasna", "mementos", "mementos.db");
|
|
60629
60782
|
ensureDir2(dirname3(fallback));
|
|
60630
60783
|
return fallback;
|
|
60631
60784
|
}
|
|
@@ -62004,7 +62157,7 @@ init_memories();
|
|
|
62004
62157
|
init_agents();
|
|
62005
62158
|
init_projects();
|
|
62006
62159
|
import chalk27 from "chalk";
|
|
62007
|
-
import { join as
|
|
62160
|
+
import { join as join7 } from "path";
|
|
62008
62161
|
import { homedir as homedir4 } from "os";
|
|
62009
62162
|
import {
|
|
62010
62163
|
readFileSync as readFileSync5,
|
|
@@ -62190,7 +62343,7 @@ function registerDoctorCommand(program2) {
|
|
|
62190
62343
|
checks.push({ name: "MCP server", status: "warn", detail: "could not check (is claude CLI installed?)" });
|
|
62191
62344
|
}
|
|
62192
62345
|
try {
|
|
62193
|
-
const settingsFilePath =
|
|
62346
|
+
const settingsFilePath = join7(homedir4(), ".claude", "settings.json");
|
|
62194
62347
|
if (existsSync7(settingsFilePath)) {
|
|
62195
62348
|
const settings = JSON.parse(readFileSync5(settingsFilePath, "utf-8"));
|
|
62196
62349
|
const hooksObj = settings["hooks"] || {};
|
|
@@ -62208,7 +62361,7 @@ function registerDoctorCommand(program2) {
|
|
|
62208
62361
|
checks.push({ name: "Stop hook", status: "warn", detail: "could not check stop hook" });
|
|
62209
62362
|
}
|
|
62210
62363
|
if (process.platform === "darwin") {
|
|
62211
|
-
const plistFilePath =
|
|
62364
|
+
const plistFilePath = join7(homedir4(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
|
|
62212
62365
|
checks.push({
|
|
62213
62366
|
name: "Auto-start",
|
|
62214
62367
|
status: existsSync7(plistFilePath) ? "ok" : "warn",
|
|
@@ -62335,9 +62488,9 @@ function registerConfigCommand(program2) {
|
|
|
62335
62488
|
}
|
|
62336
62489
|
} else {
|
|
62337
62490
|
const configPath = getConfigPath();
|
|
62338
|
-
const { unlinkSync:
|
|
62491
|
+
const { unlinkSync: unlinkSync3, existsSync: _existsSync } = __require("fs");
|
|
62339
62492
|
if (_existsSync(configPath)) {
|
|
62340
|
-
|
|
62493
|
+
unlinkSync3(configPath);
|
|
62341
62494
|
}
|
|
62342
62495
|
if (useJson) {
|
|
62343
62496
|
outputJson({ reset: true, all: true });
|
|
@@ -64027,12 +64180,12 @@ function registerStorageCommands(program2) {
|
|
|
64027
64180
|
import chalk41 from "chalk";
|
|
64028
64181
|
import {
|
|
64029
64182
|
readFileSync as readFileSync6,
|
|
64030
|
-
writeFileSync as
|
|
64183
|
+
writeFileSync as writeFileSync4,
|
|
64031
64184
|
existsSync as existsSync9,
|
|
64032
64185
|
copyFileSync as copyFileSync3,
|
|
64033
64186
|
mkdirSync as mkdirSync6
|
|
64034
64187
|
} from "fs";
|
|
64035
|
-
import { dirname as dirname6, join as
|
|
64188
|
+
import { dirname as dirname6, join as join9 } from "path";
|
|
64036
64189
|
import { homedir as homedir5 } from "os";
|
|
64037
64190
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
64038
64191
|
function registerInitCommand(program2) {
|
|
@@ -64093,9 +64246,9 @@ function registerInitCommand(program2) {
|
|
|
64093
64246
|
} else {
|
|
64094
64247
|
console.log(chalk41.green(" \u2713 MCP server registered with Claude Code"));
|
|
64095
64248
|
}
|
|
64096
|
-
const hooksDir =
|
|
64097
|
-
const hookDest =
|
|
64098
|
-
const settingsPath =
|
|
64249
|
+
const hooksDir = join9(home, ".claude", "hooks");
|
|
64250
|
+
const hookDest = join9(hooksDir, "mementos-stop-hook.ts");
|
|
64251
|
+
const settingsPath = join9(home, ".claude", "settings.json");
|
|
64099
64252
|
const hookCommand = `bun ${hookDest}`;
|
|
64100
64253
|
let hookAlreadyInstalled = false;
|
|
64101
64254
|
let hookError = null;
|
|
@@ -64120,9 +64273,9 @@ function registerInitCommand(program2) {
|
|
|
64120
64273
|
if (!existsSync9(hookDest)) {
|
|
64121
64274
|
const packageDir = dirname6(dirname6(fileURLToPath3(import.meta.url)));
|
|
64122
64275
|
const candidatePaths = [
|
|
64123
|
-
|
|
64124
|
-
|
|
64125
|
-
|
|
64276
|
+
join9(packageDir, "scripts", "hooks", "claude-stop-hook.ts"),
|
|
64277
|
+
join9(packageDir, "..", "scripts", "hooks", "claude-stop-hook.ts"),
|
|
64278
|
+
join9(home, ".bun", "install", "global", "node_modules", "@hasna", "mementos", "scripts", "hooks", "claude-stop-hook.ts")
|
|
64126
64279
|
];
|
|
64127
64280
|
let hookSourceFound = false;
|
|
64128
64281
|
for (const src of candidatePaths) {
|
|
@@ -64166,7 +64319,7 @@ async function main() {
|
|
|
64166
64319
|
|
|
64167
64320
|
main().catch(() => {});
|
|
64168
64321
|
`;
|
|
64169
|
-
|
|
64322
|
+
writeFileSync4(hookDest, inlineHook, "utf-8");
|
|
64170
64323
|
}
|
|
64171
64324
|
}
|
|
64172
64325
|
const newStopEntry = {
|
|
@@ -64175,7 +64328,7 @@ main().catch(() => {});
|
|
|
64175
64328
|
};
|
|
64176
64329
|
hooksObj["Stop"] = [...stopHooks, newStopEntry];
|
|
64177
64330
|
settings["hooks"] = hooksObj;
|
|
64178
|
-
|
|
64331
|
+
writeFileSync4(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
64179
64332
|
}
|
|
64180
64333
|
} catch (e) {
|
|
64181
64334
|
hookError = e instanceof Error ? e.message : String(e);
|
|
@@ -64192,7 +64345,7 @@ main().catch(() => {});
|
|
|
64192
64345
|
if (!isMac) {
|
|
64193
64346
|
console.log(chalk41.dim(` \xB7 Auto-start skipped (not macOS \u2014 platform: ${platform2})`));
|
|
64194
64347
|
} else {
|
|
64195
|
-
const plistPath =
|
|
64348
|
+
const plistPath = join9(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
|
|
64196
64349
|
const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
64197
64350
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
64198
64351
|
<plist version="1.0">
|
|
@@ -64220,11 +64373,11 @@ main().catch(() => {});
|
|
|
64220
64373
|
if (existsSync9(plistPath)) {
|
|
64221
64374
|
autoStartAlreadyInstalled = true;
|
|
64222
64375
|
} else {
|
|
64223
|
-
const launchAgentsDir =
|
|
64376
|
+
const launchAgentsDir = join9(home, "Library", "LaunchAgents");
|
|
64224
64377
|
if (!existsSync9(launchAgentsDir)) {
|
|
64225
64378
|
mkdirSync6(launchAgentsDir, { recursive: true });
|
|
64226
64379
|
}
|
|
64227
|
-
|
|
64380
|
+
writeFileSync4(plistPath, plistContent, "utf-8");
|
|
64228
64381
|
}
|
|
64229
64382
|
} catch (e) {
|
|
64230
64383
|
autoStartError = e instanceof Error ? e.message : String(e);
|
|
@@ -64237,7 +64390,7 @@ main().catch(() => {});
|
|
|
64237
64390
|
console.log(chalk41.green(" \u2713 Auto-start configured (starts on login)"));
|
|
64238
64391
|
}
|
|
64239
64392
|
if (!autoStartAlreadyInstalled && !autoStartError) {
|
|
64240
|
-
const plistPath2 =
|
|
64393
|
+
const plistPath2 = join9(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
|
|
64241
64394
|
const loadResult = await run(["launchctl", "load", plistPath2]);
|
|
64242
64395
|
if (!loadResult.ok) {
|
|
64243
64396
|
console.log(chalk41.dim(` \xB7 launchctl load: ${loadResult.output || "already loaded"}`));
|
|
@@ -65323,11 +65476,11 @@ function lessonTagForCli(kind) {
|
|
|
65323
65476
|
import {
|
|
65324
65477
|
existsSync as existsSync11,
|
|
65325
65478
|
mkdirSync as mkdirSync8,
|
|
65326
|
-
writeFileSync as
|
|
65479
|
+
writeFileSync as writeFileSync6,
|
|
65327
65480
|
readdirSync as readdirSync4
|
|
65328
65481
|
} from "fs";
|
|
65329
65482
|
import { homedir as homedir7 } from "os";
|
|
65330
|
-
import { join as
|
|
65483
|
+
import { join as join11 } from "path";
|
|
65331
65484
|
import chalk43 from "chalk";
|
|
65332
65485
|
|
|
65333
65486
|
// src/lib/gatherer.ts
|
|
@@ -65404,12 +65557,12 @@ var gatherTrainingData = async (options = {}) => {
|
|
|
65404
65557
|
};
|
|
65405
65558
|
|
|
65406
65559
|
// src/lib/model-config.ts
|
|
65407
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as
|
|
65560
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
65408
65561
|
import { homedir as homedir6 } from "os";
|
|
65409
|
-
import { join as
|
|
65562
|
+
import { join as join10 } from "path";
|
|
65410
65563
|
var DEFAULT_MODEL = "gpt-4o-mini";
|
|
65411
|
-
var CONFIG_DIR =
|
|
65412
|
-
var CONFIG_PATH =
|
|
65564
|
+
var CONFIG_DIR = join10(homedir6(), ".hasna", "mementos");
|
|
65565
|
+
var CONFIG_PATH = join10(CONFIG_DIR, "config.json");
|
|
65413
65566
|
function readConfig() {
|
|
65414
65567
|
if (!existsSync10(CONFIG_PATH))
|
|
65415
65568
|
return {};
|
|
@@ -65424,7 +65577,7 @@ function writeConfig(config2) {
|
|
|
65424
65577
|
if (!existsSync10(CONFIG_DIR)) {
|
|
65425
65578
|
mkdirSync7(CONFIG_DIR, { recursive: true });
|
|
65426
65579
|
}
|
|
65427
|
-
|
|
65580
|
+
writeFileSync5(CONFIG_PATH, JSON.stringify(config2, null, 2) + `
|
|
65428
65581
|
`, "utf-8");
|
|
65429
65582
|
}
|
|
65430
65583
|
function getActiveModel() {
|
|
@@ -65469,15 +65622,15 @@ function makeBrainsCommand() {
|
|
|
65469
65622
|
limit: opts.limit,
|
|
65470
65623
|
since
|
|
65471
65624
|
});
|
|
65472
|
-
const outputDir = opts.output ??
|
|
65625
|
+
const outputDir = opts.output ?? join11(homedir7(), ".hasna", "mementos", "training");
|
|
65473
65626
|
if (!existsSync11(outputDir)) {
|
|
65474
65627
|
mkdirSync8(outputDir, { recursive: true });
|
|
65475
65628
|
}
|
|
65476
65629
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
65477
|
-
const outputPath =
|
|
65630
|
+
const outputPath = join11(outputDir, `mementos-training-${timestamp}.jsonl`);
|
|
65478
65631
|
const jsonl = result.examples.map((ex) => JSON.stringify(ex)).join(`
|
|
65479
65632
|
`);
|
|
65480
|
-
|
|
65633
|
+
writeFileSync6(outputPath, jsonl + `
|
|
65481
65634
|
`, "utf-8");
|
|
65482
65635
|
if (opts.json) {
|
|
65483
65636
|
console.log(JSON.stringify({
|
|
@@ -65498,7 +65651,7 @@ function makeBrainsCommand() {
|
|
|
65498
65651
|
try {
|
|
65499
65652
|
let datasetPath = opts.dataset;
|
|
65500
65653
|
if (!datasetPath) {
|
|
65501
|
-
const trainingDir =
|
|
65654
|
+
const trainingDir = join11(homedir7(), ".hasna", "mementos", "training");
|
|
65502
65655
|
if (!existsSync11(trainingDir)) {
|
|
65503
65656
|
printError("No training data found. Run `mementos brains gather` first.");
|
|
65504
65657
|
process.exit(1);
|
|
@@ -65509,7 +65662,7 @@ function makeBrainsCommand() {
|
|
|
65509
65662
|
printError("No JSONL training files found. Run `mementos brains gather` first.");
|
|
65510
65663
|
process.exit(1);
|
|
65511
65664
|
}
|
|
65512
|
-
datasetPath =
|
|
65665
|
+
datasetPath = join11(trainingDir, latestFile);
|
|
65513
65666
|
}
|
|
65514
65667
|
if (!datasetPath || !existsSync11(datasetPath)) {
|
|
65515
65668
|
printError(`Dataset file not found: ${datasetPath ?? "(unresolved)"}`);
|
|
@@ -65615,7 +65768,7 @@ function makeBrainsCommand() {
|
|
|
65615
65768
|
// src/cli/index.tsx
|
|
65616
65769
|
function getPackageVersion2() {
|
|
65617
65770
|
try {
|
|
65618
|
-
const pkgPath =
|
|
65771
|
+
const pkgPath = join12(dirname7(fileURLToPath4(import.meta.url)), "..", "..", "package.json");
|
|
65619
65772
|
const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
65620
65773
|
return pkg.version || "0.0.0";
|
|
65621
65774
|
} catch {
|