musememory 1.9.0 → 1.10.0
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 +1 -0
- package/dist/index.js +474 -154
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -431,6 +431,7 @@ memory <command> [arguments] [flags] # alias: musememory
|
|
|
431
431
|
| `context` | `[query] [--token-budget N] [--limit N]` | Retrieve Top-$K$ ranked active context for prompt injection. |
|
|
432
432
|
| `search` | `<query> [--limit N] [--token-budget N] [--type T]` | Ranked multi-factor token search with score breakdown. |
|
|
433
433
|
| `search-transcript` | `<query> [file.jsonl] [--window N]` | Full-text search past transcripts with dialogue context windows. |
|
|
434
|
+
| `learn` / `sync-chats` | `[--confirm] [--force] [--max N]` | **Universal auto-learner**: auto-discovers and distills memories from all agent chats across host machine. |
|
|
434
435
|
| `harvest` | `<text\|file> --project P [--confirmed]` | Distill conversation turns into structured fix/decision memory units. |
|
|
435
436
|
| `import-transcript` | `<file.jsonl> [--project P] [--confirmed]` | Ingest raw `.jsonl` session transcripts from coding agents. |
|
|
436
437
|
| `capture` / `propose` | `<text> --project P [--title T] [--type T]` | Propose a memory entry with inline Vibeguard secret inspection. |
|
package/dist/index.js
CHANGED
|
@@ -4857,7 +4857,24 @@ function extractHarvestUnits(text) {
|
|
|
4857
4857
|
continue;
|
|
4858
4858
|
}
|
|
4859
4859
|
const speakerStripped = trimmed.replace(/^(?:user|assistant|human|system|agent|client|developer)\s*[:\-\u2013]\s*/i, "");
|
|
4860
|
-
const typeMatch = speakerStripped.match(/^(?:#{1,6}\s+|[-*]\s+)?\*{0,2}(fix|failure|decision|architecture|constraint|operation|preference|discovery|outcome|root cause|learned|rule)\*{0,2}\s*[:\-\u2013]\s*(.*)$/i);
|
|
4860
|
+
const typeMatch = speakerStripped.match(/^(?:#{1,6}\s+|[-*]\s+)?\*{0,2}(fix|failure|decision|architecture|constraint|operation|preference|discovery|outcome|root cause|learned|rule|solution|resolution|workaround|hard rule|policy)\*{0,2}\s*[:\-\u2013]\s*(.*)$/i);
|
|
4861
|
+
let naturalType = null;
|
|
4862
|
+
let naturalContent = "";
|
|
4863
|
+
if (!typeMatch) {
|
|
4864
|
+
if (/\b(?:resolved|fixed|patched|worked around)\s+(?:the\s+)?([^.\n]+)/i.test(speakerStripped)) {
|
|
4865
|
+
naturalType = "fix";
|
|
4866
|
+
naturalContent = speakerStripped;
|
|
4867
|
+
} else if (/\b(?:decided|chose|selected|agreed)\s+to\s+([^.\n]+)/i.test(speakerStripped)) {
|
|
4868
|
+
naturalType = "decision";
|
|
4869
|
+
naturalContent = speakerStripped;
|
|
4870
|
+
} else if (/\b(?:must\s+always|must\s+never|never\s+commit|you\s+must\s+never|do\s+not\s+allow)\s+([^.\n]+)/i.test(speakerStripped)) {
|
|
4871
|
+
naturalType = "constraint";
|
|
4872
|
+
naturalContent = speakerStripped;
|
|
4873
|
+
} else if (/\b(?:user\s+prefers|prefers\s+using|prefers\s+to)\s+([^.\n]+)/i.test(speakerStripped)) {
|
|
4874
|
+
naturalType = "preference";
|
|
4875
|
+
naturalContent = speakerStripped;
|
|
4876
|
+
}
|
|
4877
|
+
}
|
|
4861
4878
|
if (typeMatch) {
|
|
4862
4879
|
flush();
|
|
4863
4880
|
const rawTag = typeMatch[1].toLowerCase();
|
|
@@ -4866,6 +4883,11 @@ function extractHarvestUnits(text) {
|
|
|
4866
4883
|
if (currentTitle) {
|
|
4867
4884
|
currentBuffer.push(currentTitle);
|
|
4868
4885
|
}
|
|
4886
|
+
} else if (naturalType && naturalContent) {
|
|
4887
|
+
flush();
|
|
4888
|
+
currentType = naturalType;
|
|
4889
|
+
currentTitle = naturalContent.slice(0, 80);
|
|
4890
|
+
currentBuffer.push(naturalContent);
|
|
4869
4891
|
} else if (trimmed.match(/^(?:user|assistant|human|system|agent|client|developer)\s*[:\-\u2013]/i)) {
|
|
4870
4892
|
flush();
|
|
4871
4893
|
} else if (currentType !== null) {
|
|
@@ -4879,16 +4901,21 @@ function normalizeHarvestType(raw) {
|
|
|
4879
4901
|
switch (raw) {
|
|
4880
4902
|
case "fix":
|
|
4881
4903
|
case "root cause":
|
|
4904
|
+
case "solution":
|
|
4905
|
+
case "resolution":
|
|
4906
|
+
case "workaround":
|
|
4882
4907
|
return "fix";
|
|
4883
4908
|
case "failure":
|
|
4884
4909
|
return "failure";
|
|
4885
4910
|
case "decision":
|
|
4886
4911
|
case "outcome":
|
|
4887
4912
|
case "rule":
|
|
4913
|
+
case "policy":
|
|
4888
4914
|
return "decision";
|
|
4889
4915
|
case "architecture":
|
|
4890
4916
|
return "architecture";
|
|
4891
4917
|
case "constraint":
|
|
4918
|
+
case "hard rule":
|
|
4892
4919
|
return "constraint";
|
|
4893
4920
|
case "operation":
|
|
4894
4921
|
return "operation";
|
|
@@ -15746,19 +15773,265 @@ var init_schema = __esm(() => {
|
|
|
15746
15773
|
import_ajv = __toESM(require_ajv(), 1);
|
|
15747
15774
|
});
|
|
15748
15775
|
|
|
15776
|
+
// src/harvester.ts
|
|
15777
|
+
var exports_harvester = {};
|
|
15778
|
+
__export(exports_harvester, {
|
|
15779
|
+
discoverAgentTranscripts: () => discoverAgentTranscripts,
|
|
15780
|
+
getHarvestedTranscriptLedger: () => getHarvestedTranscriptLedger,
|
|
15781
|
+
getStandardAgentTranscriptDirs: () => getStandardAgentTranscriptDirs,
|
|
15782
|
+
handleLearnCommand: () => handleLearnCommand,
|
|
15783
|
+
harvestAllAgentTranscripts: () => harvestAllAgentTranscripts,
|
|
15784
|
+
saveHarvestedTranscriptLedger: () => saveHarvestedTranscriptLedger
|
|
15785
|
+
});
|
|
15786
|
+
import {
|
|
15787
|
+
existsSync as existsSync24,
|
|
15788
|
+
readFileSync as readFileSync20,
|
|
15789
|
+
writeFileSync as writeFileSync12,
|
|
15790
|
+
readdirSync as readdirSync8,
|
|
15791
|
+
statSync as statSync8,
|
|
15792
|
+
mkdirSync as mkdirSync14,
|
|
15793
|
+
openSync,
|
|
15794
|
+
readSync,
|
|
15795
|
+
closeSync
|
|
15796
|
+
} from "node:fs";
|
|
15797
|
+
import { join as join21, dirname as dirname5 } from "node:path";
|
|
15798
|
+
import { homedir as homedir5 } from "node:os";
|
|
15799
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
15800
|
+
function getStandardAgentTranscriptDirs(home = homedir5()) {
|
|
15801
|
+
return [
|
|
15802
|
+
join21(home, ".gemini", "antigravity-cli", "brain"),
|
|
15803
|
+
join21(home, ".config", "opencode", "transcripts"),
|
|
15804
|
+
join21(home, ".local", "share", "opencode", "transcripts"),
|
|
15805
|
+
join21(home, ".claude", "transcripts"),
|
|
15806
|
+
join21(home, ".claude", "projects"),
|
|
15807
|
+
join21(home, ".config", "LIFEOS", "runtime", "transcripts"),
|
|
15808
|
+
join21(home, ".hermes", "sessions"),
|
|
15809
|
+
join21(home, ".hermes", "transcripts"),
|
|
15810
|
+
join21(home, ".config", "goose", "sessions"),
|
|
15811
|
+
join21(home, ".codex", "sessions"),
|
|
15812
|
+
join21(home, ".config", "Cursor", "User", "workspaceStorage"),
|
|
15813
|
+
join21(process.cwd(), ".memory", "inbox"),
|
|
15814
|
+
join21(process.cwd(), ".logs")
|
|
15815
|
+
];
|
|
15816
|
+
}
|
|
15817
|
+
function findJsonlFilesInDir(dir, maxDepth = 4, currentDepth = 0, out = []) {
|
|
15818
|
+
if (currentDepth > maxDepth || !existsSync24(dir))
|
|
15819
|
+
return out;
|
|
15820
|
+
let entries;
|
|
15821
|
+
try {
|
|
15822
|
+
entries = readdirSync8(dir, { withFileTypes: true });
|
|
15823
|
+
} catch {
|
|
15824
|
+
return out;
|
|
15825
|
+
}
|
|
15826
|
+
for (const e of entries) {
|
|
15827
|
+
if (e.name === "node_modules" || e.name === ".git" || e.name === "dist" || e.name === "processed" || e.name === "chunks" || e.name === ".cache" || e.name === ".tmp" || e.name.startsWith("tmp")) {
|
|
15828
|
+
continue;
|
|
15829
|
+
}
|
|
15830
|
+
const full = join21(dir, e.name);
|
|
15831
|
+
if (e.isDirectory()) {
|
|
15832
|
+
findJsonlFilesInDir(full, maxDepth, currentDepth + 1, out);
|
|
15833
|
+
} else if (e.isFile() && e.name.endsWith(".jsonl")) {
|
|
15834
|
+
if (!e.name.match(/^\d{8}\.jsonl$/) && e.name !== "transcript_full.jsonl") {
|
|
15835
|
+
out.push(full);
|
|
15836
|
+
}
|
|
15837
|
+
}
|
|
15838
|
+
}
|
|
15839
|
+
return out;
|
|
15840
|
+
}
|
|
15841
|
+
function discoverAgentTranscripts(options = {}) {
|
|
15842
|
+
const dirs = options.searchRoots && options.searchRoots.length > 0 ? options.searchRoots : getStandardAgentTranscriptDirs();
|
|
15843
|
+
const found = new Set;
|
|
15844
|
+
for (const d of dirs) {
|
|
15845
|
+
if (existsSync24(d)) {
|
|
15846
|
+
try {
|
|
15847
|
+
const stat = statSync8(d);
|
|
15848
|
+
if (stat.isDirectory()) {
|
|
15849
|
+
const files = findJsonlFilesInDir(d);
|
|
15850
|
+
for (const f of files)
|
|
15851
|
+
found.add(f);
|
|
15852
|
+
} else if (stat.isFile() && d.endsWith(".jsonl")) {
|
|
15853
|
+
found.add(d);
|
|
15854
|
+
}
|
|
15855
|
+
} catch {}
|
|
15856
|
+
}
|
|
15857
|
+
}
|
|
15858
|
+
const sorted = Array.from(found).sort((a, b) => {
|
|
15859
|
+
try {
|
|
15860
|
+
return statSync8(b).mtimeMs - statSync8(a).mtimeMs;
|
|
15861
|
+
} catch {
|
|
15862
|
+
return 0;
|
|
15863
|
+
}
|
|
15864
|
+
});
|
|
15865
|
+
if (options.maxFiles && options.maxFiles > 0) {
|
|
15866
|
+
return sorted.slice(0, options.maxFiles);
|
|
15867
|
+
}
|
|
15868
|
+
return sorted;
|
|
15869
|
+
}
|
|
15870
|
+
function getHarvestedTranscriptLedger(memoryDir) {
|
|
15871
|
+
const ledgerPath = join21(memoryDir, "harvested-transcripts.json");
|
|
15872
|
+
if (!existsSync24(ledgerPath))
|
|
15873
|
+
return {};
|
|
15874
|
+
try {
|
|
15875
|
+
const raw = readFileSync20(ledgerPath, "utf8");
|
|
15876
|
+
return JSON.parse(raw);
|
|
15877
|
+
} catch {
|
|
15878
|
+
return {};
|
|
15879
|
+
}
|
|
15880
|
+
}
|
|
15881
|
+
function saveHarvestedTranscriptLedger(memoryDir, ledger) {
|
|
15882
|
+
const ledgerPath = join21(memoryDir, "harvested-transcripts.json");
|
|
15883
|
+
const dir = dirname5(ledgerPath);
|
|
15884
|
+
if (!existsSync24(dir))
|
|
15885
|
+
mkdirSync14(dir, { recursive: true });
|
|
15886
|
+
writeFileSync12(ledgerPath, JSON.stringify(ledger, null, 2) + `
|
|
15887
|
+
`, "utf8");
|
|
15888
|
+
}
|
|
15889
|
+
function harvestAllAgentTranscripts(store, options = {}) {
|
|
15890
|
+
const memoryDir = options.memoryDir || join21(process.cwd(), ".memory");
|
|
15891
|
+
const ledger = getHarvestedTranscriptLedger(memoryDir);
|
|
15892
|
+
const files = discoverAgentTranscripts({
|
|
15893
|
+
searchRoots: options.searchRoots,
|
|
15894
|
+
maxFiles: options.maxFiles || 50
|
|
15895
|
+
});
|
|
15896
|
+
const result = {
|
|
15897
|
+
harvestedFilesCount: 0,
|
|
15898
|
+
totalFilesScanned: files.length,
|
|
15899
|
+
memoriesImported: 0,
|
|
15900
|
+
openLoopsDetected: 0,
|
|
15901
|
+
processedFiles: [],
|
|
15902
|
+
errors: []
|
|
15903
|
+
};
|
|
15904
|
+
for (const filePath of files) {
|
|
15905
|
+
try {
|
|
15906
|
+
const stat = statSync8(filePath);
|
|
15907
|
+
const prevEntry = ledger[filePath];
|
|
15908
|
+
if (!options.force && prevEntry && prevEntry.mtimeMs === stat.mtimeMs) {
|
|
15909
|
+
continue;
|
|
15910
|
+
}
|
|
15911
|
+
let content = "";
|
|
15912
|
+
if (stat.size > 2 * 1024 * 1024) {
|
|
15913
|
+
const fd = openSync(filePath, "r");
|
|
15914
|
+
const bufferSize = 512 * 1024;
|
|
15915
|
+
const buffer = Buffer.alloc(bufferSize);
|
|
15916
|
+
const position = Math.max(0, stat.size - bufferSize);
|
|
15917
|
+
const bytesRead = readSync(fd, buffer, 0, bufferSize, position);
|
|
15918
|
+
closeSync(fd);
|
|
15919
|
+
content = buffer.toString("utf8", 0, bytesRead);
|
|
15920
|
+
} else {
|
|
15921
|
+
content = readFileSync20(filePath, "utf8");
|
|
15922
|
+
}
|
|
15923
|
+
const contentHash = createHash2("sha256").update(content).digest("hex").slice(0, 16);
|
|
15924
|
+
if (!options.force && prevEntry && prevEntry.hash === contentHash) {
|
|
15925
|
+
continue;
|
|
15926
|
+
}
|
|
15927
|
+
let inferredProject = options.project;
|
|
15928
|
+
if (!inferredProject) {
|
|
15929
|
+
if (filePath.includes("/Projects/github/") || filePath.includes("/Projects/")) {
|
|
15930
|
+
const m = filePath.match(/\/Projects\/(?:github\/)?([^/]+)/);
|
|
15931
|
+
if (m)
|
|
15932
|
+
inferredProject = m[1];
|
|
15933
|
+
}
|
|
15934
|
+
}
|
|
15935
|
+
if (!inferredProject)
|
|
15936
|
+
inferredProject = "default";
|
|
15937
|
+
const importRes = importTranscript(store, content, {
|
|
15938
|
+
project: inferredProject,
|
|
15939
|
+
confirmed: options.confirmed === true,
|
|
15940
|
+
source: `auto_harvester:${filePath}`
|
|
15941
|
+
});
|
|
15942
|
+
ledger[filePath] = {
|
|
15943
|
+
mtimeMs: stat.mtimeMs,
|
|
15944
|
+
hash: contentHash,
|
|
15945
|
+
importedCount: importRes.imported,
|
|
15946
|
+
openLoopsCount: importRes.openLoops.length,
|
|
15947
|
+
harvestedAt: new Date().toISOString()
|
|
15948
|
+
};
|
|
15949
|
+
if (importRes.imported > 0 || importRes.openLoops.length > 0) {
|
|
15950
|
+
result.harvestedFilesCount++;
|
|
15951
|
+
result.memoriesImported += importRes.imported;
|
|
15952
|
+
result.openLoopsDetected += importRes.openLoops.length;
|
|
15953
|
+
result.processedFiles.push({
|
|
15954
|
+
path: filePath,
|
|
15955
|
+
imported: importRes.imported,
|
|
15956
|
+
openLoops: importRes.openLoops.length
|
|
15957
|
+
});
|
|
15958
|
+
recordAuditEvent(memoryDir, {
|
|
15959
|
+
operation: "transcript_import",
|
|
15960
|
+
entry_id: filePath,
|
|
15961
|
+
actor: "auto-harvester",
|
|
15962
|
+
details: {
|
|
15963
|
+
imported: importRes.imported,
|
|
15964
|
+
open_loops: importRes.openLoops.length,
|
|
15965
|
+
inferred_project: inferredProject
|
|
15966
|
+
}
|
|
15967
|
+
});
|
|
15968
|
+
}
|
|
15969
|
+
if (importRes.errors.length > 0) {
|
|
15970
|
+
result.errors.push(...importRes.errors.map((e) => `${filePath}: ${e}`));
|
|
15971
|
+
}
|
|
15972
|
+
} catch (err) {
|
|
15973
|
+
result.errors.push(`${filePath}: ${err.message || err}`);
|
|
15974
|
+
}
|
|
15975
|
+
}
|
|
15976
|
+
saveHarvestedTranscriptLedger(memoryDir, ledger);
|
|
15977
|
+
return result;
|
|
15978
|
+
}
|
|
15979
|
+
async function handleLearnCommand({ flags }) {
|
|
15980
|
+
const ctx = requireRoot(flags);
|
|
15981
|
+
if (!ctx)
|
|
15982
|
+
return 1;
|
|
15983
|
+
const isConfirmed = flags["confirmed"] === "true" || flags["confirm"] === "true";
|
|
15984
|
+
const force = flags["force"] === "true";
|
|
15985
|
+
const project = flags["project"];
|
|
15986
|
+
const maxFiles = flags["max"] ? parseInt(flags["max"], 10) : 50;
|
|
15987
|
+
console.log(`[Auto-Learner] Probing workstation for active AI agent transcripts...`);
|
|
15988
|
+
const res = harvestAllAgentTranscripts(ctx.store, {
|
|
15989
|
+
memoryDir: ctx.memoryDir,
|
|
15990
|
+
confirmed: isConfirmed,
|
|
15991
|
+
force,
|
|
15992
|
+
project,
|
|
15993
|
+
maxFiles
|
|
15994
|
+
});
|
|
15995
|
+
console.log(`[Auto-Learner] Scanned ${res.totalFilesScanned} agent transcript files.`);
|
|
15996
|
+
if (res.harvestedFilesCount === 0) {
|
|
15997
|
+
console.log(`✓ Up to date. 0 new un-harvested turns found (all transcripts indexed).`);
|
|
15998
|
+
return 0;
|
|
15999
|
+
}
|
|
16000
|
+
console.log(`
|
|
16001
|
+
\uD83C\uDF89 Distilled ${res.memoriesImported} new memories and ${res.openLoopsDetected} open loops from ${res.harvestedFilesCount} transcript(s):`);
|
|
16002
|
+
for (const p of res.processedFiles) {
|
|
16003
|
+
console.log(` * ${p.path} -> +${p.imported} memories, +${p.openLoops} loops`);
|
|
16004
|
+
}
|
|
16005
|
+
if (res.errors.length > 0) {
|
|
16006
|
+
console.log(`
|
|
16007
|
+
⚠️ Warnings / Redactions during harvest:`);
|
|
16008
|
+
for (const err of res.errors.slice(0, 5)) {
|
|
16009
|
+
console.log(` - ${err}`);
|
|
16010
|
+
}
|
|
16011
|
+
}
|
|
16012
|
+
console.log(`
|
|
16013
|
+
\uD83D\uDCA1 Open 'memory ui' or run 'memory stats' to view your newly indexed cognitive graph.`);
|
|
16014
|
+
return 0;
|
|
16015
|
+
}
|
|
16016
|
+
var init_harvester = __esm(() => {
|
|
16017
|
+
init_harvest();
|
|
16018
|
+
init_audit();
|
|
16019
|
+
init_shared();
|
|
16020
|
+
});
|
|
16021
|
+
|
|
15749
16022
|
// src/doctor.ts
|
|
15750
16023
|
var exports_doctor = {};
|
|
15751
16024
|
__export(exports_doctor, {
|
|
15752
16025
|
printDoctorReport: () => printDoctorReport,
|
|
15753
16026
|
runDoctor: () => runDoctor
|
|
15754
16027
|
});
|
|
15755
|
-
import { existsSync as
|
|
15756
|
-
import { join as
|
|
15757
|
-
import { homedir as
|
|
16028
|
+
import { existsSync as existsSync25, statSync as statSync9, readFileSync as readFileSync21 } from "node:fs";
|
|
16029
|
+
import { join as join22 } from "node:path";
|
|
16030
|
+
import { homedir as homedir6 } from "node:os";
|
|
15758
16031
|
async function runDoctor(targetDir, options = {}) {
|
|
15759
|
-
const home =
|
|
15760
|
-
const storagePath = options.global ? getGlobalMemoryDir() : findOrCreateProjectRoot(targetDir || process.cwd())?.memoryDir ||
|
|
15761
|
-
const isInitialized =
|
|
16032
|
+
const home = homedir6();
|
|
16033
|
+
const storagePath = options.global ? getGlobalMemoryDir() : findOrCreateProjectRoot(targetDir || process.cwd())?.memoryDir || join22(home, ".memory");
|
|
16034
|
+
const isInitialized = existsSync25(storagePath);
|
|
15762
16035
|
let currentMdExists = false;
|
|
15763
16036
|
let currentMdLines = 0;
|
|
15764
16037
|
let totalEntries = 0;
|
|
@@ -15776,10 +16049,10 @@ async function runDoctor(targetDir, options = {}) {
|
|
|
15776
16049
|
let secretLeaksCount = 0;
|
|
15777
16050
|
let brokenLinksCount = 0;
|
|
15778
16051
|
if (isInitialized) {
|
|
15779
|
-
const currentPath =
|
|
15780
|
-
if (
|
|
16052
|
+
const currentPath = join22(storagePath, "CURRENT.md");
|
|
16053
|
+
if (existsSync25(currentPath)) {
|
|
15781
16054
|
currentMdExists = true;
|
|
15782
|
-
const content =
|
|
16055
|
+
const content = readFileSync21(currentPath, "utf8");
|
|
15783
16056
|
currentMdLines = content.split(`
|
|
15784
16057
|
`).filter((l) => l.trim().length > 0).length;
|
|
15785
16058
|
}
|
|
@@ -15800,21 +16073,21 @@ async function runDoctor(targetDir, options = {}) {
|
|
|
15800
16073
|
valid = false;
|
|
15801
16074
|
}
|
|
15802
16075
|
}
|
|
15803
|
-
const auditPath =
|
|
16076
|
+
const auditPath = join22(storagePath, "audit.jsonl");
|
|
15804
16077
|
let auditExists = false;
|
|
15805
16078
|
let auditCount = 0;
|
|
15806
16079
|
let auditSize = 0;
|
|
15807
16080
|
let lastEvent;
|
|
15808
|
-
if (
|
|
16081
|
+
if (existsSync25(auditPath)) {
|
|
15809
16082
|
auditExists = true;
|
|
15810
16083
|
try {
|
|
15811
|
-
const stat =
|
|
16084
|
+
const stat = statSync9(auditPath);
|
|
15812
16085
|
auditSize = stat.size;
|
|
15813
16086
|
const trail = getAuditTrail(storagePath, { limit: 1 });
|
|
15814
16087
|
if (trail.length > 0) {
|
|
15815
16088
|
lastEvent = `${trail[0].operation} on ${trail[0].entry_id} (${trail[0].timestamp})`;
|
|
15816
16089
|
}
|
|
15817
|
-
const raw =
|
|
16090
|
+
const raw = readFileSync21(auditPath, "utf8");
|
|
15818
16091
|
auditCount = raw.split(`
|
|
15819
16092
|
`).filter((l) => l.trim().length > 0).length;
|
|
15820
16093
|
} catch {}
|
|
@@ -15823,6 +16096,11 @@ async function runDoctor(targetDir, options = {}) {
|
|
|
15823
16096
|
const installed = agents.filter((a) => a.installed);
|
|
15824
16097
|
const connected = installed.filter((a) => a.connected);
|
|
15825
16098
|
const unwired = installed.filter((a) => !a.connected);
|
|
16099
|
+
const { discoverAgentTranscripts: discoverAgentTranscripts2, getHarvestedTranscriptLedger: getHarvestedTranscriptLedger2 } = await Promise.resolve().then(() => (init_harvester(), exports_harvester));
|
|
16100
|
+
const discoveredFiles = discoverAgentTranscripts2();
|
|
16101
|
+
const ledger = getHarvestedTranscriptLedger2(storagePath);
|
|
16102
|
+
const harvestedFiles = Object.keys(ledger);
|
|
16103
|
+
const unharvestedCount = discoveredFiles.filter((f) => !ledger[f]).length;
|
|
15826
16104
|
const memBin = findBinary("memory", home) || findBinary("musememory", home);
|
|
15827
16105
|
const bunVer = typeof globalThis.Bun !== "undefined" ? globalThis.Bun.version : undefined;
|
|
15828
16106
|
return {
|
|
@@ -15856,6 +16134,11 @@ async function runDoctor(targetDir, options = {}) {
|
|
|
15856
16134
|
connectedList: connected.map((a) => a.name),
|
|
15857
16135
|
unwiredList: unwired.map((a) => a.name)
|
|
15858
16136
|
},
|
|
16137
|
+
transcripts: {
|
|
16138
|
+
discoveredCount: discoveredFiles.length,
|
|
16139
|
+
harvestedCount: harvestedFiles.length,
|
|
16140
|
+
unharvestedCount
|
|
16141
|
+
},
|
|
15859
16142
|
runtime: {
|
|
15860
16143
|
nodeVersion: process.version,
|
|
15861
16144
|
bunVersion: bunVer,
|
|
@@ -15913,6 +16196,16 @@ function printDoctorReport(report) {
|
|
|
15913
16196
|
console.log(` -> Run 'memory connect --all' or 'npx musememory connect --all' to wire them.`);
|
|
15914
16197
|
}
|
|
15915
16198
|
console.log(`
|
|
16199
|
+
[AUTO-LEARNER] Agent Chat Transcripts & Distillation:`);
|
|
16200
|
+
console.log(` Discovered Transcripts on Disk: ${report.transcripts.discoveredCount}`);
|
|
16201
|
+
console.log(` Harvested / Indexed: ${report.transcripts.harvestedCount}`);
|
|
16202
|
+
if (report.transcripts.unharvestedCount > 0) {
|
|
16203
|
+
console.log(` [!] New Un-Harvested Chats: ${report.transcripts.unharvestedCount}`);
|
|
16204
|
+
console.log(` -> Run 'memory learn' or 'memory sync-chats' to auto-distill learnings from recent AI interactions.`);
|
|
16205
|
+
} else {
|
|
16206
|
+
console.log(` [OK] All discovered chat transcripts are synchronized.`);
|
|
16207
|
+
}
|
|
16208
|
+
console.log(`
|
|
15916
16209
|
[RUNTIME] Runtime & CLI Execution:`);
|
|
15917
16210
|
console.log(` Node.js: ${report.runtime.nodeVersion}${report.runtime.bunVersion ? ` | Bun: v${report.runtime.bunVersion}` : ""}`);
|
|
15918
16211
|
if (report.runtime.globalBinaryFound) {
|
|
@@ -15940,27 +16233,27 @@ var init_doctor = __esm(() => {
|
|
|
15940
16233
|
});
|
|
15941
16234
|
|
|
15942
16235
|
// src/retrieval/tree-index.ts
|
|
15943
|
-
import { existsSync as
|
|
15944
|
-
import { join as
|
|
16236
|
+
import { existsSync as existsSync26, readFileSync as readFileSync22, writeFileSync as writeFileSync13, mkdirSync as mkdirSync15, rmSync } from "node:fs";
|
|
16237
|
+
import { join as join23 } from "node:path";
|
|
15945
16238
|
function tokenize2(text) {
|
|
15946
16239
|
if (!text || typeof text !== "string")
|
|
15947
16240
|
return [];
|
|
15948
16241
|
return text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
15949
16242
|
}
|
|
15950
16243
|
function indexDir(memoryDir) {
|
|
15951
|
-
return
|
|
16244
|
+
return join23(memoryDir, "tree-index");
|
|
15952
16245
|
}
|
|
15953
16246
|
function partitionDir(idxDir, project, type2) {
|
|
15954
|
-
return
|
|
16247
|
+
return join23(idxDir, project, type2);
|
|
15955
16248
|
}
|
|
15956
16249
|
function shardFilePath(pDir, shardId) {
|
|
15957
|
-
return
|
|
16250
|
+
return join23(pDir, `${shardId}.json`);
|
|
15958
16251
|
}
|
|
15959
16252
|
function partitionIndexFilePath(pDir) {
|
|
15960
|
-
return
|
|
16253
|
+
return join23(pDir, "index.json");
|
|
15961
16254
|
}
|
|
15962
16255
|
function globalIndexFilePath(idxDir) {
|
|
15963
|
-
return
|
|
16256
|
+
return join23(idxDir, "index.json");
|
|
15964
16257
|
}
|
|
15965
16258
|
function nowIso3() {
|
|
15966
16259
|
return new Date().toISOString();
|
|
@@ -16050,7 +16343,7 @@ function countNodes(node) {
|
|
|
16050
16343
|
function buildTreeIndex(store, memoryDir, config = {}) {
|
|
16051
16344
|
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
16052
16345
|
const allMemories = list(store).filter((e) => e.status === "confirmed");
|
|
16053
|
-
|
|
16346
|
+
mkdirSync15(indexDir(memoryDir), { recursive: true });
|
|
16054
16347
|
if (allMemories.length === 0) {
|
|
16055
16348
|
const emptyIndex = {
|
|
16056
16349
|
version: 1,
|
|
@@ -16059,7 +16352,7 @@ function buildTreeIndex(store, memoryDir, config = {}) {
|
|
|
16059
16352
|
totalMemories: 0,
|
|
16060
16353
|
builtAt: nowIso3()
|
|
16061
16354
|
};
|
|
16062
|
-
|
|
16355
|
+
writeFileSync13(globalIndexFilePath(indexDir(memoryDir)), JSON.stringify(emptyIndex, null, 2), "utf8");
|
|
16063
16356
|
return emptyIndex;
|
|
16064
16357
|
}
|
|
16065
16358
|
const groups = new Map;
|
|
@@ -16077,7 +16370,7 @@ function buildTreeIndex(store, memoryDir, config = {}) {
|
|
|
16077
16370
|
for (const [key, memories] of groups) {
|
|
16078
16371
|
const [project, type2] = key.split("|");
|
|
16079
16372
|
const pDir = partitionDir(indexDir(memoryDir), project, type2);
|
|
16080
|
-
|
|
16373
|
+
mkdirSync15(pDir, { recursive: true });
|
|
16081
16374
|
const maxShardSize = cfg.shardThreshold || 1e4;
|
|
16082
16375
|
const finalShards = [];
|
|
16083
16376
|
const memoryChunks = [];
|
|
@@ -16138,9 +16431,9 @@ function buildTreeIndex(store, memoryDir, config = {}) {
|
|
|
16138
16431
|
partitions[`${project}|${type2}`] = partition;
|
|
16139
16432
|
totalIndexNodes += partitionNodes;
|
|
16140
16433
|
totalIndexMemories += partitionMemories;
|
|
16141
|
-
|
|
16434
|
+
writeFileSync13(partitionIndexFilePath(pDir), JSON.stringify(partition, null, 2), "utf8");
|
|
16142
16435
|
for (const shard of finalShards) {
|
|
16143
|
-
|
|
16436
|
+
writeFileSync13(shardFilePath(pDir, shard.id), JSON.stringify(shard, null, 2), "utf8");
|
|
16144
16437
|
}
|
|
16145
16438
|
}
|
|
16146
16439
|
const index = {
|
|
@@ -16150,15 +16443,15 @@ function buildTreeIndex(store, memoryDir, config = {}) {
|
|
|
16150
16443
|
totalMemories: totalIndexMemories,
|
|
16151
16444
|
builtAt: nowIso3()
|
|
16152
16445
|
};
|
|
16153
|
-
|
|
16446
|
+
writeFileSync13(globalIndexFilePath(indexDir(memoryDir)), JSON.stringify(index, null, 2), "utf8");
|
|
16154
16447
|
return index;
|
|
16155
16448
|
}
|
|
16156
16449
|
function loadTreeIndex(memoryDir) {
|
|
16157
16450
|
const path = globalIndexFilePath(indexDir(memoryDir));
|
|
16158
|
-
if (!
|
|
16451
|
+
if (!existsSync26(path))
|
|
16159
16452
|
return null;
|
|
16160
16453
|
try {
|
|
16161
|
-
const data = JSON.parse(
|
|
16454
|
+
const data = JSON.parse(readFileSync22(path, "utf8"));
|
|
16162
16455
|
return data.version === 1 ? data : null;
|
|
16163
16456
|
} catch {
|
|
16164
16457
|
return null;
|
|
@@ -16303,10 +16596,10 @@ __export(exports_vector, {
|
|
|
16303
16596
|
saveIndex: () => saveIndex,
|
|
16304
16597
|
termFrequencies: () => termFrequencies
|
|
16305
16598
|
});
|
|
16306
|
-
import { existsSync as
|
|
16307
|
-
import { join as
|
|
16599
|
+
import { existsSync as existsSync27, readFileSync as readFileSync23, writeFileSync as writeFileSync14, mkdirSync as mkdirSync16 } from "node:fs";
|
|
16600
|
+
import { join as join24 } from "node:path";
|
|
16308
16601
|
function indexFilePath(memoryDir) {
|
|
16309
|
-
return
|
|
16602
|
+
return join24(memoryDir, "index.json");
|
|
16310
16603
|
}
|
|
16311
16604
|
function hashTrigram(tri) {
|
|
16312
16605
|
let h = 2166136261;
|
|
@@ -16353,16 +16646,16 @@ function rebuildIndex(store) {
|
|
|
16353
16646
|
return index;
|
|
16354
16647
|
}
|
|
16355
16648
|
function saveIndex(index, memoryDir) {
|
|
16356
|
-
if (!
|
|
16357
|
-
|
|
16358
|
-
|
|
16649
|
+
if (!existsSync27(memoryDir))
|
|
16650
|
+
mkdirSync16(memoryDir, { recursive: true });
|
|
16651
|
+
writeFileSync14(indexFilePath(memoryDir), JSON.stringify(index), "utf8");
|
|
16359
16652
|
}
|
|
16360
16653
|
function loadIndex(memoryDir) {
|
|
16361
16654
|
const p = indexFilePath(memoryDir);
|
|
16362
|
-
if (!
|
|
16655
|
+
if (!existsSync27(p))
|
|
16363
16656
|
return null;
|
|
16364
16657
|
try {
|
|
16365
|
-
const parsed = JSON.parse(
|
|
16658
|
+
const parsed = JSON.parse(readFileSync23(p, "utf8"));
|
|
16366
16659
|
return parsed.version === 1 ? parsed : null;
|
|
16367
16660
|
} catch {
|
|
16368
16661
|
return null;
|
|
@@ -16434,8 +16727,8 @@ var init_vector = __esm(() => {
|
|
|
16434
16727
|
});
|
|
16435
16728
|
|
|
16436
16729
|
// src/pageindex/engine.ts
|
|
16437
|
-
import { existsSync as
|
|
16438
|
-
import { join as
|
|
16730
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync24, writeFileSync as writeFileSync15, rmSync as rmSync2, readdirSync as readdirSync10 } from "node:fs";
|
|
16731
|
+
import { join as join25 } from "node:path";
|
|
16439
16732
|
function slugify2(text) {
|
|
16440
16733
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 50);
|
|
16441
16734
|
}
|
|
@@ -16512,9 +16805,9 @@ function buildPageIndex(content, options) {
|
|
|
16512
16805
|
root: rootNode
|
|
16513
16806
|
};
|
|
16514
16807
|
if (options.memoryDir && !options.dryRun) {
|
|
16515
|
-
const dir =
|
|
16516
|
-
|
|
16517
|
-
|
|
16808
|
+
const dir = join25(options.memoryDir, "pageindex", project);
|
|
16809
|
+
mkdirSync17(dir, { recursive: true });
|
|
16810
|
+
writeFileSync15(join25(dir, `${indexId}.json`), JSON.stringify(doc, null, 2), "utf8");
|
|
16518
16811
|
}
|
|
16519
16812
|
return doc;
|
|
16520
16813
|
}
|
|
@@ -16578,29 +16871,29 @@ function searchPageIndex(doc, options) {
|
|
|
16578
16871
|
};
|
|
16579
16872
|
}
|
|
16580
16873
|
function loadPageIndex(memoryDir, project, indexId) {
|
|
16581
|
-
const filePath =
|
|
16582
|
-
if (!
|
|
16874
|
+
const filePath = join25(memoryDir, "pageindex", project, `${indexId}.json`);
|
|
16875
|
+
if (!existsSync28(filePath))
|
|
16583
16876
|
return null;
|
|
16584
16877
|
try {
|
|
16585
|
-
return JSON.parse(
|
|
16878
|
+
return JSON.parse(readFileSync24(filePath, "utf8"));
|
|
16586
16879
|
} catch {
|
|
16587
16880
|
return null;
|
|
16588
16881
|
}
|
|
16589
16882
|
}
|
|
16590
16883
|
function listPageIndexes(memoryDir, project) {
|
|
16591
|
-
const base =
|
|
16592
|
-
if (!
|
|
16884
|
+
const base = join25(memoryDir, "pageindex");
|
|
16885
|
+
if (!existsSync28(base))
|
|
16593
16886
|
return [];
|
|
16594
16887
|
const results = [];
|
|
16595
|
-
const projects = project ? [project] :
|
|
16888
|
+
const projects = project ? [project] : readdirSync10(base);
|
|
16596
16889
|
for (const p of projects) {
|
|
16597
|
-
const pDir =
|
|
16598
|
-
if (!
|
|
16890
|
+
const pDir = join25(base, p);
|
|
16891
|
+
if (!existsSync28(pDir))
|
|
16599
16892
|
continue;
|
|
16600
|
-
for (const f of
|
|
16893
|
+
for (const f of readdirSync10(pDir)) {
|
|
16601
16894
|
if (f.endsWith(".json")) {
|
|
16602
16895
|
try {
|
|
16603
|
-
results.push(JSON.parse(
|
|
16896
|
+
results.push(JSON.parse(readFileSync24(join25(pDir, f), "utf8")));
|
|
16604
16897
|
} catch {}
|
|
16605
16898
|
}
|
|
16606
16899
|
}
|
|
@@ -16608,8 +16901,8 @@ function listPageIndexes(memoryDir, project) {
|
|
|
16608
16901
|
return results;
|
|
16609
16902
|
}
|
|
16610
16903
|
function deletePageIndex(memoryDir, project, indexId) {
|
|
16611
|
-
const base =
|
|
16612
|
-
if (!
|
|
16904
|
+
const base = join25(memoryDir, "pageindex");
|
|
16905
|
+
if (!existsSync28(base))
|
|
16613
16906
|
return { deletedCount: 0 };
|
|
16614
16907
|
let count = 0;
|
|
16615
16908
|
if (!project && !indexId) {
|
|
@@ -16617,14 +16910,14 @@ function deletePageIndex(memoryDir, project, indexId) {
|
|
|
16617
16910
|
return { deletedCount: 1 };
|
|
16618
16911
|
}
|
|
16619
16912
|
if (project && !indexId) {
|
|
16620
|
-
const pDir =
|
|
16621
|
-
if (
|
|
16913
|
+
const pDir = join25(base, project);
|
|
16914
|
+
if (existsSync28(pDir)) {
|
|
16622
16915
|
rmSync2(pDir, { recursive: true, force: true });
|
|
16623
16916
|
count++;
|
|
16624
16917
|
}
|
|
16625
16918
|
} else if (project && indexId) {
|
|
16626
|
-
const file =
|
|
16627
|
-
if (
|
|
16919
|
+
const file = join25(base, project, `${indexId}.json`);
|
|
16920
|
+
if (existsSync28(file)) {
|
|
16628
16921
|
rmSync2(file, { force: true });
|
|
16629
16922
|
count++;
|
|
16630
16923
|
}
|
|
@@ -16637,13 +16930,13 @@ var init_engine2 = __esm(() => {
|
|
|
16637
16930
|
});
|
|
16638
16931
|
|
|
16639
16932
|
// src/retrieval/engine.ts
|
|
16640
|
-
import { existsSync as
|
|
16641
|
-
import { join as
|
|
16933
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
16934
|
+
import { join as join26 } from "node:path";
|
|
16642
16935
|
|
|
16643
16936
|
class RetrievalEngine {
|
|
16644
16937
|
static search(store, memoryDir, query, options = {}) {
|
|
16645
16938
|
const mode = options.mode ?? "auto";
|
|
16646
|
-
if (mode === "pageindex" || options.docPath &&
|
|
16939
|
+
if (mode === "pageindex" || options.docPath && existsSync29(options.docPath)) {
|
|
16647
16940
|
try {
|
|
16648
16941
|
const docs = listPageIndexes(memoryDir, options.project);
|
|
16649
16942
|
if (docs.length > 0) {
|
|
@@ -16670,8 +16963,8 @@ class RetrievalEngine {
|
|
|
16670
16963
|
}
|
|
16671
16964
|
} catch {}
|
|
16672
16965
|
}
|
|
16673
|
-
const treeDir =
|
|
16674
|
-
const hasTree =
|
|
16966
|
+
const treeDir = join26(memoryDir, "tree");
|
|
16967
|
+
const hasTree = existsSync29(treeDir);
|
|
16675
16968
|
const allEntries = list(store);
|
|
16676
16969
|
if (mode === "tree" || mode === "auto" && hasTree && allEntries.length >= 500) {
|
|
16677
16970
|
try {
|
|
@@ -16709,7 +17002,7 @@ class RetrievalEngine {
|
|
|
16709
17002
|
} catch {}
|
|
16710
17003
|
}
|
|
16711
17004
|
const vecPath = indexFilePath(memoryDir);
|
|
16712
|
-
const hasVec =
|
|
17005
|
+
const hasVec = existsSync29(vecPath);
|
|
16713
17006
|
if (mode === "hybrid" || mode === "auto" && hasVec && allEntries.length > 100) {
|
|
16714
17007
|
try {
|
|
16715
17008
|
const hybridResults = hybridSearch(store, memoryDir, query, {
|
|
@@ -26405,8 +26698,8 @@ var init_loops = __esm(() => {
|
|
|
26405
26698
|
});
|
|
26406
26699
|
|
|
26407
26700
|
// src/distill.ts
|
|
26408
|
-
import { existsSync as
|
|
26409
|
-
import { join as
|
|
26701
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "node:fs";
|
|
26702
|
+
import { join as join27 } from "node:path";
|
|
26410
26703
|
function fixTokens(e) {
|
|
26411
26704
|
const bag = tokenBag(e.title, 2);
|
|
26412
26705
|
mergeBag(bag, tokenBag((e.tags ?? []).join(" "), 2));
|
|
@@ -26417,7 +26710,7 @@ function distillSkills(store, workspaceRoot, options = {}) {
|
|
|
26417
26710
|
const report = { created: [], skippedExisting: [], clustersBelowThreshold: 0 };
|
|
26418
26711
|
const fixes = list(store).filter((e) => e.status === "confirmed" && e.type === "fix").sort((a, b) => Date.parse(a.created_at) - Date.parse(b.created_at));
|
|
26419
26712
|
const clusters = clusterByTokenOverlap(fixes, fixTokens, 0.5);
|
|
26420
|
-
const skillsDir = options.skillsDir ??
|
|
26713
|
+
const skillsDir = options.skillsDir ?? join27(workspaceRoot, ".agents", "skills");
|
|
26421
26714
|
for (const cluster of clusters) {
|
|
26422
26715
|
if (cluster.length < minCount) {
|
|
26423
26716
|
report.clustersBelowThreshold++;
|
|
@@ -26425,9 +26718,9 @@ function distillSkills(store, workspaceRoot, options = {}) {
|
|
|
26425
26718
|
}
|
|
26426
26719
|
const topic = dominantTopicTokens(cluster.map((e) => e.title));
|
|
26427
26720
|
const slug = slugifyId(topic.join("-") || "skill");
|
|
26428
|
-
const dir =
|
|
26721
|
+
const dir = join27(skillsDir, slug);
|
|
26429
26722
|
const memberIds = cluster.map((e) => e.id);
|
|
26430
|
-
if (
|
|
26723
|
+
if (existsSync30(dir)) {
|
|
26431
26724
|
report.skippedExisting.push({ slug, members: memberIds });
|
|
26432
26725
|
continue;
|
|
26433
26726
|
}
|
|
@@ -26437,10 +26730,10 @@ function distillSkills(store, workspaceRoot, options = {}) {
|
|
|
26437
26730
|
throw new Error(`Secret detected in generated SKILL.md for '${slug}': ${secrets.join(", ")}`);
|
|
26438
26731
|
}
|
|
26439
26732
|
if (!options.dryRun) {
|
|
26440
|
-
|
|
26441
|
-
|
|
26733
|
+
mkdirSync18(dir, { recursive: true });
|
|
26734
|
+
writeFileSync16(join27(dir, "SKILL.md"), md, "utf8");
|
|
26442
26735
|
}
|
|
26443
|
-
report.created.push({ slug, path:
|
|
26736
|
+
report.created.push({ slug, path: join27(dir, "SKILL.md"), members: memberIds });
|
|
26444
26737
|
}
|
|
26445
26738
|
return report;
|
|
26446
26739
|
}
|
|
@@ -26778,14 +27071,14 @@ var init_schema2 = __esm(() => {
|
|
|
26778
27071
|
});
|
|
26779
27072
|
|
|
26780
27073
|
// src/settings/loader.ts
|
|
26781
|
-
import { existsSync as
|
|
26782
|
-
import { join as
|
|
27074
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync19, readFileSync as readFileSync25, writeFileSync as writeFileSync17 } from "node:fs";
|
|
27075
|
+
import { join as join28 } from "node:path";
|
|
26783
27076
|
function getSettingsFilePath(memoryDir) {
|
|
26784
|
-
return
|
|
27077
|
+
return join28(memoryDir, "settings.json");
|
|
26785
27078
|
}
|
|
26786
27079
|
function loadSettings(memoryDir) {
|
|
26787
27080
|
const filePath = getSettingsFilePath(memoryDir);
|
|
26788
|
-
if (!
|
|
27081
|
+
if (!existsSync31(filePath)) {
|
|
26789
27082
|
return {
|
|
26790
27083
|
version: 1,
|
|
26791
27084
|
global: JSON.parse(JSON.stringify(DEFAULT_SETTINGS)),
|
|
@@ -26793,7 +27086,7 @@ function loadSettings(memoryDir) {
|
|
|
26793
27086
|
};
|
|
26794
27087
|
}
|
|
26795
27088
|
try {
|
|
26796
|
-
const raw =
|
|
27089
|
+
const raw = readFileSync25(filePath, "utf8");
|
|
26797
27090
|
const parsed = JSON.parse(raw);
|
|
26798
27091
|
return {
|
|
26799
27092
|
version: parsed.version || 1,
|
|
@@ -26809,9 +27102,9 @@ function loadSettings(memoryDir) {
|
|
|
26809
27102
|
}
|
|
26810
27103
|
}
|
|
26811
27104
|
function saveSettings(store, memoryDir) {
|
|
26812
|
-
|
|
27105
|
+
mkdirSync19(memoryDir, { recursive: true });
|
|
26813
27106
|
const filePath = getSettingsFilePath(memoryDir);
|
|
26814
|
-
|
|
27107
|
+
writeFileSync17(filePath, JSON.stringify(store, null, 2), "utf8");
|
|
26815
27108
|
}
|
|
26816
27109
|
function getSettings(memoryDir) {
|
|
26817
27110
|
return loadSettings(memoryDir).global;
|
|
@@ -26927,17 +27220,17 @@ __export(exports_plasticity, {
|
|
|
26927
27220
|
recordCoActivation: () => recordCoActivation,
|
|
26928
27221
|
saveHebbianGraph: () => saveHebbianGraph
|
|
26929
27222
|
});
|
|
26930
|
-
import { existsSync as
|
|
26931
|
-
import { join as
|
|
27223
|
+
import { existsSync as existsSync32, readFileSync as readFileSync26, writeFileSync as writeFileSync18 } from "node:fs";
|
|
27224
|
+
import { join as join29 } from "node:path";
|
|
26932
27225
|
function getPlasticityPath(memoryDir) {
|
|
26933
|
-
return
|
|
27226
|
+
return join29(memoryDir, "hebbian-plasticity.json");
|
|
26934
27227
|
}
|
|
26935
27228
|
function loadHebbianGraph(memoryDir) {
|
|
26936
27229
|
const p = getPlasticityPath(memoryDir);
|
|
26937
|
-
if (!
|
|
27230
|
+
if (!existsSync32(p))
|
|
26938
27231
|
return {};
|
|
26939
27232
|
try {
|
|
26940
|
-
return JSON.parse(
|
|
27233
|
+
return JSON.parse(readFileSync26(p, "utf8"));
|
|
26941
27234
|
} catch {
|
|
26942
27235
|
return {};
|
|
26943
27236
|
}
|
|
@@ -26945,7 +27238,7 @@ function loadHebbianGraph(memoryDir) {
|
|
|
26945
27238
|
function saveHebbianGraph(memoryDir, graph) {
|
|
26946
27239
|
const p = getPlasticityPath(memoryDir);
|
|
26947
27240
|
try {
|
|
26948
|
-
|
|
27241
|
+
writeFileSync18(p, JSON.stringify(graph, null, 2), "utf8");
|
|
26949
27242
|
} catch {}
|
|
26950
27243
|
}
|
|
26951
27244
|
function recordCoActivation(memoryIds, memoryDir) {
|
|
@@ -27036,8 +27329,8 @@ __export(exports_drift, {
|
|
|
27036
27329
|
scanCodeDriftFromDiff: () => scanCodeDriftFromDiff
|
|
27037
27330
|
});
|
|
27038
27331
|
import { execSync as execSync3 } from "node:child_process";
|
|
27039
|
-
import { existsSync as
|
|
27040
|
-
import { join as
|
|
27332
|
+
import { existsSync as existsSync33 } from "node:fs";
|
|
27333
|
+
import { join as join30, isAbsolute as isAbsolute2 } from "node:path";
|
|
27041
27334
|
function scanCodeDriftFromDiff(entries, changedFiles, workspaceRoot) {
|
|
27042
27335
|
const root = workspaceRoot || process.cwd();
|
|
27043
27336
|
const normalizedChanged = new Set(changedFiles.map((f) => f.trim().replace(/^[\.\/]+/, "")).filter(Boolean));
|
|
@@ -27051,8 +27344,8 @@ function scanCodeDriftFromDiff(entries, changedFiles, workspaceRoot) {
|
|
|
27051
27344
|
const norm = p.trim().replace(/^[\.\/]+/, "");
|
|
27052
27345
|
const matched = Array.from(normalizedChanged).find((cf) => cf === norm || cf.endsWith(`/${norm}`) || norm.endsWith(`/${cf}`));
|
|
27053
27346
|
if (matched) {
|
|
27054
|
-
const fullPath = isAbsolute2(p) ? p :
|
|
27055
|
-
const exists =
|
|
27347
|
+
const fullPath = isAbsolute2(p) ? p : join30(root, p);
|
|
27348
|
+
const exists = existsSync33(fullPath);
|
|
27056
27349
|
drifted.push({
|
|
27057
27350
|
memoryId: entry.id,
|
|
27058
27351
|
title: entry.title,
|
|
@@ -27798,6 +28091,12 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
27798
28091
|
recordCoActivation2(formatted.entries.map((e) => e.entry.id), activeMemoryDir);
|
|
27799
28092
|
} catch {}
|
|
27800
28093
|
}
|
|
28094
|
+
if (activeMemoryDir) {
|
|
28095
|
+
try {
|
|
28096
|
+
const { harvestAllAgentTranscripts: harvestAllAgentTranscripts2 } = await Promise.resolve().then(() => (init_harvester(), exports_harvester));
|
|
28097
|
+
harvestAllAgentTranscripts2(activeStore, { memoryDir: activeMemoryDir, maxFiles: 3 });
|
|
28098
|
+
} catch {}
|
|
28099
|
+
}
|
|
27801
28100
|
let finalMarkdown = formatted.markdown;
|
|
27802
28101
|
if (a.compress === true) {
|
|
27803
28102
|
const { compressPromptContext: compressPromptContext2 } = await Promise.resolve().then(() => exports_compress);
|
|
@@ -27890,9 +28189,18 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
27890
28189
|
}
|
|
27891
28190
|
}
|
|
27892
28191
|
case "memory_harvest": {
|
|
28192
|
+
if (a.all === true || a.auto === true || !a.text) {
|
|
28193
|
+
const { harvestAllAgentTranscripts: harvestAllAgentTranscripts2 } = await Promise.resolve().then(() => (init_harvester(), exports_harvester));
|
|
28194
|
+
const harvestRes = harvestAllAgentTranscripts2(activeStore, {
|
|
28195
|
+
memoryDir: activeMemoryDir,
|
|
28196
|
+
confirmed: a.confirmed === true,
|
|
28197
|
+
project: a.project ? String(a.project) : undefined
|
|
28198
|
+
});
|
|
28199
|
+
return toolResult(harvestRes);
|
|
28200
|
+
}
|
|
27893
28201
|
const created = harvestMemories(activeStore, {
|
|
27894
28202
|
text: String(a.text),
|
|
27895
|
-
project: String(a.project),
|
|
28203
|
+
project: String(a.project || "default"),
|
|
27896
28204
|
confirmed: a.confirmed === true
|
|
27897
28205
|
});
|
|
27898
28206
|
return toolResult({ harvested_count: created.length, entries: created });
|
|
@@ -28314,8 +28622,8 @@ __export(exports_daemon, {
|
|
|
28314
28622
|
startHub: () => startHub
|
|
28315
28623
|
});
|
|
28316
28624
|
import { createServer as createServer2 } from "node:http";
|
|
28317
|
-
import { existsSync as
|
|
28318
|
-
import { join as
|
|
28625
|
+
import { existsSync as existsSync34 } from "node:fs";
|
|
28626
|
+
import { join as join31 } from "node:path";
|
|
28319
28627
|
import { watch } from "node:fs";
|
|
28320
28628
|
function startHub(port, memoryDir) {
|
|
28321
28629
|
const clients = new Set;
|
|
@@ -28381,7 +28689,7 @@ data: ${JSON.stringify(event)}
|
|
|
28381
28689
|
return clients.size;
|
|
28382
28690
|
}
|
|
28383
28691
|
if (memoryDir) {
|
|
28384
|
-
const memoriesDir =
|
|
28692
|
+
const memoriesDir = join31(memoryDir, "memories");
|
|
28385
28693
|
const armDebounced = (type2) => {
|
|
28386
28694
|
if (debounceTimer)
|
|
28387
28695
|
clearTimeout(debounceTimer);
|
|
@@ -28390,11 +28698,11 @@ data: ${JSON.stringify(event)}
|
|
|
28390
28698
|
}, DEBOUNCE_MS);
|
|
28391
28699
|
};
|
|
28392
28700
|
try {
|
|
28393
|
-
if (
|
|
28701
|
+
if (existsSync34(memoriesDir)) {
|
|
28394
28702
|
watchers.push(watch(memoriesDir, () => armDebounced("memory.changed")));
|
|
28395
28703
|
}
|
|
28396
|
-
const currentMd =
|
|
28397
|
-
if (
|
|
28704
|
+
const currentMd = join31(memoryDir, "CURRENT.md");
|
|
28705
|
+
if (existsSync34(currentMd)) {
|
|
28398
28706
|
watchers.push(watch(currentMd, () => armDebounced("constraints.changed")));
|
|
28399
28707
|
}
|
|
28400
28708
|
} catch {}
|
|
@@ -28427,19 +28735,19 @@ var DEBOUNCE_MS = 300;
|
|
|
28427
28735
|
var init_daemon = () => {};
|
|
28428
28736
|
|
|
28429
28737
|
// src/cli/ecosystem.ts
|
|
28430
|
-
import { join as
|
|
28431
|
-
import { existsSync as
|
|
28432
|
-
import { homedir as
|
|
28738
|
+
import { join as join32 } from "node:path";
|
|
28739
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync20, writeFileSync as writeFileSync19, readFileSync as readFileSync27 } from "node:fs";
|
|
28740
|
+
import { homedir as homedir7 } from "node:os";
|
|
28433
28741
|
function ensureProjectAgentInstructions(targetDir) {
|
|
28434
|
-
const agentsMdPath =
|
|
28435
|
-
if (
|
|
28742
|
+
const agentsMdPath = join32(targetDir, "AGENTS.md");
|
|
28743
|
+
if (existsSync35(agentsMdPath)) {
|
|
28436
28744
|
try {
|
|
28437
|
-
const existing =
|
|
28745
|
+
const existing = readFileSync27(agentsMdPath, "utf8");
|
|
28438
28746
|
if (existing.includes("<!-- agentmemory:start -->")) {
|
|
28439
28747
|
const updated = existing.replace(/<!-- agentmemory:start -->[\s\S]*?<!-- agentmemory:end -->/, MUSE_MEMORY_DIRECTIVE);
|
|
28440
|
-
|
|
28748
|
+
writeFileSync19(agentsMdPath, updated, "utf8");
|
|
28441
28749
|
} else if (!existing.includes("<!-- musememory:start -->") && !existing.includes("Muse Memory")) {
|
|
28442
|
-
|
|
28750
|
+
writeFileSync19(agentsMdPath, `${existing.trim()}
|
|
28443
28751
|
|
|
28444
28752
|
${MUSE_MEMORY_DIRECTIVE}
|
|
28445
28753
|
`, "utf8");
|
|
@@ -28450,23 +28758,23 @@ ${MUSE_MEMORY_DIRECTIVE}
|
|
|
28450
28758
|
|
|
28451
28759
|
${MUSE_MEMORY_DIRECTIVE}
|
|
28452
28760
|
`;
|
|
28453
|
-
|
|
28761
|
+
writeFileSync19(agentsMdPath, initialContent, "utf8");
|
|
28454
28762
|
}
|
|
28455
28763
|
}
|
|
28456
28764
|
async function handleInstallCommand({ positional, flags }) {
|
|
28457
28765
|
const isGlobal = flags["global"] === "true" || flags["g"] === "true";
|
|
28458
|
-
const targetDir = positional[0] ?
|
|
28459
|
-
const memoryDir = isGlobal ? getGlobalMemoryDir() :
|
|
28766
|
+
const targetDir = positional[0] ? join32(process.cwd(), positional[0]) : process.cwd();
|
|
28767
|
+
const memoryDir = isGlobal ? getGlobalMemoryDir() : join32(targetDir, ".memory");
|
|
28460
28768
|
const globalDir = getGlobalMemoryDir();
|
|
28461
|
-
|
|
28462
|
-
|
|
28463
|
-
const currentPath =
|
|
28464
|
-
if (!
|
|
28465
|
-
|
|
28769
|
+
mkdirSync20(join32(memoryDir, "memories"), { recursive: true });
|
|
28770
|
+
mkdirSync20(join32(globalDir, "memories"), { recursive: true });
|
|
28771
|
+
const currentPath = join32(memoryDir, "CURRENT.md");
|
|
28772
|
+
if (!existsSync35(currentPath)) {
|
|
28773
|
+
writeFileSync19(currentPath, `# Active Project Constraints
|
|
28466
28774
|
`, "utf8");
|
|
28467
28775
|
}
|
|
28468
28776
|
const globalUserPath = userFilePath(globalDir);
|
|
28469
|
-
if (!
|
|
28777
|
+
if (!existsSync35(globalUserPath)) {
|
|
28470
28778
|
const { promptSingleSelect: promptSingleSelect2 } = await Promise.resolve().then(() => (init_prompt(), exports_prompt));
|
|
28471
28779
|
const archetypeOptions = [
|
|
28472
28780
|
{ id: "developer", label: "Software Engineer / Developer", hint: "Code-first, direct, strict typing" },
|
|
@@ -28482,13 +28790,13 @@ async function handleInstallCommand({ positional, flags }) {
|
|
|
28482
28790
|
if (!isGlobal) {
|
|
28483
28791
|
ensureProjectAgentInstructions(targetDir);
|
|
28484
28792
|
}
|
|
28485
|
-
const globalAgentsMd =
|
|
28486
|
-
if (
|
|
28793
|
+
const globalAgentsMd = join32(homedir7(), ".agents", "AGENTS.md");
|
|
28794
|
+
if (existsSync35(globalAgentsMd)) {
|
|
28487
28795
|
try {
|
|
28488
|
-
const existing =
|
|
28796
|
+
const existing = readFileSync27(globalAgentsMd, "utf8");
|
|
28489
28797
|
if (existing.includes("<!-- agentmemory:start -->")) {
|
|
28490
28798
|
const updated = existing.replace(/<!-- agentmemory:start -->[\s\S]*?<!-- agentmemory:end -->/, MUSE_MEMORY_DIRECTIVE);
|
|
28491
|
-
|
|
28799
|
+
writeFileSync19(globalAgentsMd, updated, "utf8");
|
|
28492
28800
|
}
|
|
28493
28801
|
} catch {}
|
|
28494
28802
|
}
|
|
@@ -28549,11 +28857,11 @@ async function handleInstallCommand({ positional, flags }) {
|
|
|
28549
28857
|
return 0;
|
|
28550
28858
|
}
|
|
28551
28859
|
async function promptOrNotifyGitHook(targetDir, autoInstall = false) {
|
|
28552
|
-
const gitDir =
|
|
28553
|
-
if (!
|
|
28860
|
+
const gitDir = join32(targetDir, ".git");
|
|
28861
|
+
if (!existsSync35(gitDir))
|
|
28554
28862
|
return false;
|
|
28555
|
-
const hookPath =
|
|
28556
|
-
const isInstalled =
|
|
28863
|
+
const hookPath = join32(gitDir, "hooks", "pre-commit");
|
|
28864
|
+
const isInstalled = existsSync35(hookPath) && readFileSync27(hookPath, "utf8").includes("memory harvest-auto");
|
|
28557
28865
|
if (isInstalled)
|
|
28558
28866
|
return true;
|
|
28559
28867
|
if (autoInstall) {
|
|
@@ -28609,7 +28917,7 @@ async function handleUninstallCommand({ positional, flags }) {
|
|
|
28609
28917
|
action: async () => {
|
|
28610
28918
|
if (purge) {
|
|
28611
28919
|
const ctx = requireRoot(flags);
|
|
28612
|
-
if (ctx &&
|
|
28920
|
+
if (ctx && existsSync35(ctx.memoryDir) && !dryRun) {
|
|
28613
28921
|
const { rmSync: rmSync3 } = await import("node:fs");
|
|
28614
28922
|
rmSync3(ctx.memoryDir, { recursive: true, force: true });
|
|
28615
28923
|
}
|
|
@@ -28641,13 +28949,13 @@ async function handleUninstallCommand({ positional, flags }) {
|
|
|
28641
28949
|
}
|
|
28642
28950
|
async function handleInitCommand({ positional, flags }) {
|
|
28643
28951
|
const isGlobal = flags["global"] === "true";
|
|
28644
|
-
const targetDir = positional[0] ?
|
|
28952
|
+
const targetDir = positional[0] ? join32(process.cwd(), positional[0]) : process.cwd();
|
|
28645
28953
|
const memoryDirName = flags["legacy"] === "true" ? ".musememory" : ".memory";
|
|
28646
|
-
const memoryDir = isGlobal ? getGlobalMemoryDir() :
|
|
28647
|
-
|
|
28648
|
-
const currentPath =
|
|
28649
|
-
if (!
|
|
28650
|
-
|
|
28954
|
+
const memoryDir = isGlobal ? getGlobalMemoryDir() : join32(targetDir, memoryDirName);
|
|
28955
|
+
mkdirSync20(join32(memoryDir, "memories"), { recursive: true });
|
|
28956
|
+
const currentPath = join32(memoryDir, "CURRENT.md");
|
|
28957
|
+
if (!existsSync35(currentPath)) {
|
|
28958
|
+
writeFileSync19(currentPath, `# Active Project Constraints
|
|
28651
28959
|
`, "utf8");
|
|
28652
28960
|
}
|
|
28653
28961
|
if (!isGlobal) {
|
|
@@ -28823,6 +29131,13 @@ async function handleUiCommand({ flags }) {
|
|
|
28823
29131
|
if (!ctx)
|
|
28824
29132
|
return 1;
|
|
28825
29133
|
const port = flags["port"] ? parseInt(flags["port"], 10) : 2222;
|
|
29134
|
+
try {
|
|
29135
|
+
const { harvestAllAgentTranscripts: harvestAllAgentTranscripts2 } = await Promise.resolve().then(() => (init_harvester(), exports_harvester));
|
|
29136
|
+
const harvestRes = harvestAllAgentTranscripts2(ctx.store, { memoryDir: ctx.memoryDir });
|
|
29137
|
+
if (harvestRes.harvestedFilesCount > 0) {
|
|
29138
|
+
console.log(`[UI Auto-Sync] Distilled ${harvestRes.memoriesImported} new memories from ${harvestRes.harvestedFilesCount} agent transcript(s).`);
|
|
29139
|
+
}
|
|
29140
|
+
} catch {}
|
|
28826
29141
|
const { startUiServer: startUiServer2 } = await Promise.resolve().then(() => (init_ui(), exports_ui));
|
|
28827
29142
|
const srv = await startUiServer2({
|
|
28828
29143
|
port,
|
|
@@ -28931,8 +29246,8 @@ var init_ecosystem = __esm(() => {
|
|
|
28931
29246
|
});
|
|
28932
29247
|
|
|
28933
29248
|
// src/agentcontract.ts
|
|
28934
|
-
import { existsSync as
|
|
28935
|
-
import { join as
|
|
29249
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
29250
|
+
import { join as join33 } from "node:path";
|
|
28936
29251
|
function parseAgentMemoryContract(markdown) {
|
|
28937
29252
|
if (!markdown || !markdown.startsWith("---"))
|
|
28938
29253
|
return null;
|
|
@@ -28964,17 +29279,17 @@ function parseAgentMemoryContract(markdown) {
|
|
|
28964
29279
|
function resolveAgentFile(nameOrPath, workspaceRoot) {
|
|
28965
29280
|
if (!nameOrPath)
|
|
28966
29281
|
return null;
|
|
28967
|
-
if (
|
|
29282
|
+
if (existsSync36(nameOrPath))
|
|
28968
29283
|
return nameOrPath;
|
|
28969
29284
|
const candidates = [
|
|
28970
|
-
|
|
28971
|
-
|
|
29285
|
+
join33(workspaceRoot, ".agents", `${nameOrPath}.md`),
|
|
29286
|
+
join33(workspaceRoot, ".memory", "agents", `${nameOrPath}.md`)
|
|
28972
29287
|
];
|
|
28973
29288
|
const home = process.env.HOME;
|
|
28974
29289
|
if (home)
|
|
28975
|
-
candidates.push(
|
|
29290
|
+
candidates.push(join33(home, ".config", "opencode", "agents", `${nameOrPath}.md`));
|
|
28976
29291
|
for (const c of candidates) {
|
|
28977
|
-
if (
|
|
29292
|
+
if (existsSync36(c))
|
|
28978
29293
|
return c;
|
|
28979
29294
|
}
|
|
28980
29295
|
return null;
|
|
@@ -28984,8 +29299,8 @@ var init_agentcontract = __esm(() => {
|
|
|
28984
29299
|
});
|
|
28985
29300
|
|
|
28986
29301
|
// src/cli/retrieval.ts
|
|
28987
|
-
import { existsSync as
|
|
28988
|
-
import { join as
|
|
29302
|
+
import { existsSync as existsSync37, readFileSync as readFileSync28 } from "node:fs";
|
|
29303
|
+
import { join as join34 } from "node:path";
|
|
28989
29304
|
async function handleContextCommand({ positional, flags }) {
|
|
28990
29305
|
let agentTypes;
|
|
28991
29306
|
let agentTags;
|
|
@@ -28993,7 +29308,7 @@ async function handleContextCommand({ positional, flags }) {
|
|
|
28993
29308
|
const file = resolveAgentFile(flags["for-agent"], flags["dir"] ?? process.cwd());
|
|
28994
29309
|
if (!file)
|
|
28995
29310
|
return usageError(`--for-agent: cannot resolve agent '${flags["for-agent"]}'`);
|
|
28996
|
-
const contract = parseAgentMemoryContract(
|
|
29311
|
+
const contract = parseAgentMemoryContract(readFileSync28(file, "utf8"));
|
|
28997
29312
|
if (contract) {
|
|
28998
29313
|
agentTypes = contract.types;
|
|
28999
29314
|
agentTags = contract.tags;
|
|
@@ -29133,7 +29448,7 @@ async function handleHarvestCommand({ positional, flags }) {
|
|
|
29133
29448
|
const project = flags["project"];
|
|
29134
29449
|
if (!project)
|
|
29135
29450
|
return usageError("harvest requires --project");
|
|
29136
|
-
const rawText =
|
|
29451
|
+
const rawText = existsSync37(target) ? readFileSync28(target, "utf8") : target;
|
|
29137
29452
|
const created = harvestMemories(ctx.store, {
|
|
29138
29453
|
text: rawText,
|
|
29139
29454
|
project,
|
|
@@ -29169,8 +29484,8 @@ async function handleSearchTranscriptCommand({ positional, flags }) {
|
|
|
29169
29484
|
const filePath = positional[1];
|
|
29170
29485
|
if (!query)
|
|
29171
29486
|
return usageError("search-transcript requires <query> [file.jsonl]");
|
|
29172
|
-
const targetFile = filePath ? filePath.startsWith("/") ? filePath :
|
|
29173
|
-
if (!
|
|
29487
|
+
const targetFile = filePath ? filePath.startsWith("/") ? filePath : join34(process.cwd(), filePath) : join34(process.cwd(), "transcript.jsonl");
|
|
29488
|
+
if (!existsSync37(targetFile)) {
|
|
29174
29489
|
return fail(`error: transcript file not found: ${targetFile}`);
|
|
29175
29490
|
}
|
|
29176
29491
|
const windowSize = flags["window"] ? parseInt(flags["window"], 10) : 2;
|
|
@@ -29186,7 +29501,7 @@ async function handleReindexCommand({ flags }) {
|
|
|
29186
29501
|
const { rebuildIndex: rebuildIndex2, saveIndex: saveIndex2 } = await Promise.resolve().then(() => (init_vector(), exports_vector));
|
|
29187
29502
|
const index = rebuildIndex2(ctx.store);
|
|
29188
29503
|
saveIndex2(index, ctx.memoryDir);
|
|
29189
|
-
console.log(`indexed ${Object.keys(index.entries).length} entries -> ${
|
|
29504
|
+
console.log(`indexed ${Object.keys(index.entries).length} entries -> ${join34(ctx.memoryDir, "index.json")}`);
|
|
29190
29505
|
return 0;
|
|
29191
29506
|
}
|
|
29192
29507
|
async function handleHookCommand({ positional, flags }) {
|
|
@@ -29577,7 +29892,7 @@ var init_entities2 = __esm(() => {
|
|
|
29577
29892
|
});
|
|
29578
29893
|
|
|
29579
29894
|
// src/cli/settings.ts
|
|
29580
|
-
import { writeFileSync as
|
|
29895
|
+
import { writeFileSync as writeFileSync20, readFileSync as readFileSync29 } from "node:fs";
|
|
29581
29896
|
function handleSettingsCommand(parsed) {
|
|
29582
29897
|
const ctx = requireRoot(parsed.flags);
|
|
29583
29898
|
if (!ctx)
|
|
@@ -29659,7 +29974,7 @@ function handleSettingsCommand(parsed) {
|
|
|
29659
29974
|
const out = parsed.flags.out;
|
|
29660
29975
|
const json2 = exportSettings(memoryDir);
|
|
29661
29976
|
if (out) {
|
|
29662
|
-
|
|
29977
|
+
writeFileSync20(out, json2, "utf8");
|
|
29663
29978
|
console.log(`Exported settings to ${out}`);
|
|
29664
29979
|
} else {
|
|
29665
29980
|
console.log(json2);
|
|
@@ -29673,7 +29988,7 @@ function handleSettingsCommand(parsed) {
|
|
|
29673
29988
|
return 2;
|
|
29674
29989
|
}
|
|
29675
29990
|
try {
|
|
29676
|
-
const raw =
|
|
29991
|
+
const raw = readFileSync29(file, "utf8");
|
|
29677
29992
|
importSettings(memoryDir, raw);
|
|
29678
29993
|
console.log(`Successfully imported settings from ${file}`);
|
|
29679
29994
|
return 0;
|
|
@@ -29696,16 +30011,16 @@ var init_nudge = __esm(() => {
|
|
|
29696
30011
|
});
|
|
29697
30012
|
|
|
29698
30013
|
// src/routines.ts
|
|
29699
|
-
import { readFileSync as
|
|
29700
|
-
import { join as
|
|
30014
|
+
import { readFileSync as readFileSync30, existsSync as existsSync38 } from "node:fs";
|
|
30015
|
+
import { join as join35 } from "node:path";
|
|
29701
30016
|
function routinesPath(memoryDir) {
|
|
29702
|
-
return
|
|
30017
|
+
return join35(memoryDir, "routines.yaml");
|
|
29703
30018
|
}
|
|
29704
30019
|
function loadRoutines(memoryDir) {
|
|
29705
30020
|
const p = routinesPath(memoryDir);
|
|
29706
|
-
if (!
|
|
30021
|
+
if (!existsSync38(p))
|
|
29707
30022
|
return { routines: {} };
|
|
29708
|
-
const doc2 = yaml.load(
|
|
30023
|
+
const doc2 = yaml.load(readFileSync30(p, "utf8"), { schema: yaml.JSON_SCHEMA }) ?? {};
|
|
29709
30024
|
const routines = doc2.routines ?? {};
|
|
29710
30025
|
for (const [name, r] of Object.entries(routines)) {
|
|
29711
30026
|
if (!r || typeof r.schedule !== "string" || !r.schedule.trim()) {
|
|
@@ -29743,7 +30058,7 @@ var init_routines = __esm(() => {
|
|
|
29743
30058
|
});
|
|
29744
30059
|
|
|
29745
30060
|
// src/cli/lifecycle.ts
|
|
29746
|
-
import { writeFileSync as
|
|
30061
|
+
import { writeFileSync as writeFileSync21, readFileSync as readFileSync31, existsSync as existsSync39 } from "node:fs";
|
|
29747
30062
|
async function handleProposeCommand({ positional, flags }) {
|
|
29748
30063
|
const ctx = requireRoot(flags);
|
|
29749
30064
|
if (!ctx)
|
|
@@ -29892,7 +30207,7 @@ async function handleExportCommand({ flags }) {
|
|
|
29892
30207
|
const snapshot = exportSnapshot(ctx.store);
|
|
29893
30208
|
const outPath = flags["out"];
|
|
29894
30209
|
if (outPath) {
|
|
29895
|
-
|
|
30210
|
+
writeFileSync21(outPath, JSON.stringify(snapshot, null, 2), "utf8");
|
|
29896
30211
|
console.log(`exported ${snapshot.total} memories to ${outPath}`);
|
|
29897
30212
|
} else {
|
|
29898
30213
|
console.log(JSON.stringify(snapshot, null, 2));
|
|
@@ -29906,9 +30221,9 @@ async function handleImportCommand({ positional, flags }) {
|
|
|
29906
30221
|
const file = positional[0];
|
|
29907
30222
|
if (!file)
|
|
29908
30223
|
return usageError("import requires <file.json>");
|
|
29909
|
-
if (!
|
|
30224
|
+
if (!existsSync39(file))
|
|
29910
30225
|
return fail(`error: file ${file} does not exist`);
|
|
29911
|
-
const raw = JSON.parse(
|
|
30226
|
+
const raw = JSON.parse(readFileSync31(file, "utf8"));
|
|
29912
30227
|
const res = importSnapshot(ctx.store, raw, { overwrite: flags["overwrite"] === "true" });
|
|
29913
30228
|
if (res.errors.length > 0) {
|
|
29914
30229
|
console.error(`import encountered errors:`);
|
|
@@ -30316,6 +30631,9 @@ async function main(argv) {
|
|
|
30316
30631
|
return handleSearchTranscriptCommand(parsed);
|
|
30317
30632
|
case "harvest":
|
|
30318
30633
|
return handleHarvestCommand(parsed);
|
|
30634
|
+
case "learn":
|
|
30635
|
+
case "sync-chats":
|
|
30636
|
+
return handleLearnCommand(parsed);
|
|
30319
30637
|
case "harvest-auto":
|
|
30320
30638
|
return handleHarvestAutoCommand(parsed);
|
|
30321
30639
|
case "hook":
|
|
@@ -30449,6 +30767,7 @@ Ecosystem, Migration & Connectivity:
|
|
|
30449
30767
|
agents / detect-agents Scan workstation for 80+ coding agent platforms
|
|
30450
30768
|
detect Scan machine for 24+ external memory formats
|
|
30451
30769
|
migrate [--from P] [--all] Ingest external memories with state preservation & secret scrubbing
|
|
30770
|
+
learn / sync-chats [--confirm] Auto-discover and harvest memories from all agent chats across machine
|
|
30452
30771
|
harvest <file|text> --project P Distill conversation transcripts into structured memory units
|
|
30453
30772
|
harvest-auto [--from <glob>] [--project P] Harvest inbox transcripts as candidates and archive them
|
|
30454
30773
|
hook install --git Install the harvester as a git pre-commit hook (never clobbers)
|
|
@@ -30465,6 +30784,7 @@ var init_cli = __esm(() => {
|
|
|
30465
30784
|
init_shared();
|
|
30466
30785
|
init_ecosystem();
|
|
30467
30786
|
init_upgrade();
|
|
30787
|
+
init_harvester();
|
|
30468
30788
|
init_retrieval3();
|
|
30469
30789
|
init_persona();
|
|
30470
30790
|
init_wiki2();
|