unforgit 0.8.4 → 0.9.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/dist/{chunk-VESJIIT2.js → chunk-JXSAAZ3I.js} +198 -1
- package/dist/chunk-JXSAAZ3I.js.map +1 -0
- package/dist/index.js +128 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-VESJIIT2.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,9 @@ import {
|
|
|
7
7
|
defaultConfig,
|
|
8
8
|
detectGitInfo,
|
|
9
9
|
executeConsolidation,
|
|
10
|
+
exportMarkdownMemories,
|
|
10
11
|
findConsolidationCandidates,
|
|
12
|
+
findUnsafeMarkdownMemoryFindings,
|
|
11
13
|
formatCandidatePreview,
|
|
12
14
|
formatTemplateList,
|
|
13
15
|
generateEmbedding,
|
|
@@ -21,6 +23,7 @@ import {
|
|
|
21
23
|
loadConfig,
|
|
22
24
|
mergeAndRank,
|
|
23
25
|
parseConfidence,
|
|
26
|
+
parseMarkdownMemories,
|
|
24
27
|
parsePositiveInt,
|
|
25
28
|
parseThreshold,
|
|
26
29
|
parseTtl,
|
|
@@ -30,11 +33,12 @@ import {
|
|
|
30
33
|
resolveVisibility,
|
|
31
34
|
runLocalLifecycleMaintenance,
|
|
32
35
|
saveConfig,
|
|
36
|
+
shouldImportMarkdownMemory,
|
|
33
37
|
validateMemoryType
|
|
34
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-JXSAAZ3I.js";
|
|
35
39
|
|
|
36
40
|
// src/index.ts
|
|
37
|
-
import { Command as
|
|
41
|
+
import { Command as Command32 } from "commander";
|
|
38
42
|
|
|
39
43
|
// src/commands/init.ts
|
|
40
44
|
import fs2 from "fs";
|
|
@@ -4005,6 +4009,126 @@ var suggestionsCommand = new Command30("suggestions").description("Reviewable cu
|
|
|
4005
4009
|
})
|
|
4006
4010
|
);
|
|
4007
4011
|
|
|
4012
|
+
// src/commands/md.ts
|
|
4013
|
+
import fs7 from "fs";
|
|
4014
|
+
import path5 from "path";
|
|
4015
|
+
import { Command as Command31 } from "commander";
|
|
4016
|
+
var mdCommand = new Command31("md").description("Import and export markdown memory files such as CLAUDE.md and MEMORY.md");
|
|
4017
|
+
function readMarkdownFile(file) {
|
|
4018
|
+
if (!fs7.existsSync(file)) {
|
|
4019
|
+
logger.error(`Markdown file not found: ${file}`);
|
|
4020
|
+
process.exit(EXIT_ERROR);
|
|
4021
|
+
}
|
|
4022
|
+
return fs7.readFileSync(file, "utf-8");
|
|
4023
|
+
}
|
|
4024
|
+
function importMarkdown(file, opts) {
|
|
4025
|
+
const config = loadConfig();
|
|
4026
|
+
const sourceFile = path5.resolve(file);
|
|
4027
|
+
const markdown = readMarkdownFile(sourceFile);
|
|
4028
|
+
const parsed = parseMarkdownMemories(markdown, { sourceFile });
|
|
4029
|
+
const findings = findUnsafeMarkdownMemoryFindings(parsed);
|
|
4030
|
+
const importable = parsed.filter((memory) => shouldImportMarkdownMemory(memory, findings));
|
|
4031
|
+
const dryRun = !opts.apply;
|
|
4032
|
+
const storedIds = [];
|
|
4033
|
+
if (!dryRun) {
|
|
4034
|
+
const store = new LocalStore(getDbPath());
|
|
4035
|
+
try {
|
|
4036
|
+
const existing = store.list({
|
|
4037
|
+
orgId: config.remote.orgId || "local",
|
|
4038
|
+
repoId: config.remote.repoId || "local",
|
|
4039
|
+
status: ["active"],
|
|
4040
|
+
limit: 1e4
|
|
4041
|
+
});
|
|
4042
|
+
const existingChecksums = new Set(
|
|
4043
|
+
existing.map((memory) => {
|
|
4044
|
+
const markdownSource = memory.sourceRefs?.markdown;
|
|
4045
|
+
return markdownSource?.checksum;
|
|
4046
|
+
}).filter((checksum) => Boolean(checksum))
|
|
4047
|
+
);
|
|
4048
|
+
const existingTexts = new Set(existing.map((memory) => memory.text.trim().toLowerCase()));
|
|
4049
|
+
for (const memory of importable) {
|
|
4050
|
+
if (existingChecksums.has(memory.checksum) || existingTexts.has(memory.text.trim().toLowerCase())) {
|
|
4051
|
+
continue;
|
|
4052
|
+
}
|
|
4053
|
+
const stored = store.store({
|
|
4054
|
+
orgId: config.remote.orgId || "local",
|
|
4055
|
+
repoId: config.remote.repoId || "local",
|
|
4056
|
+
memoryType: memory.memoryType,
|
|
4057
|
+
text: memory.text,
|
|
4058
|
+
tags: memory.tags,
|
|
4059
|
+
sourceRefs: {
|
|
4060
|
+
markdown: {
|
|
4061
|
+
sourceFile,
|
|
4062
|
+
sourceId: memory.id,
|
|
4063
|
+
lineStart: memory.lineStart,
|
|
4064
|
+
lineEnd: memory.lineEnd,
|
|
4065
|
+
checksum: memory.checksum,
|
|
4066
|
+
headingPath: memory.headingPath
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
});
|
|
4070
|
+
storedIds.push(stored.id);
|
|
4071
|
+
}
|
|
4072
|
+
} finally {
|
|
4073
|
+
store.close();
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
const payload = {
|
|
4077
|
+
file: sourceFile,
|
|
4078
|
+
parsed: parsed.length,
|
|
4079
|
+
importable: importable.length,
|
|
4080
|
+
skippedUnsafe: findings.length,
|
|
4081
|
+
stored: storedIds.length,
|
|
4082
|
+
dryRun,
|
|
4083
|
+
findings,
|
|
4084
|
+
storedIds
|
|
4085
|
+
};
|
|
4086
|
+
if (opts.json || isJsonMode()) {
|
|
4087
|
+
outputJson(payload);
|
|
4088
|
+
} else {
|
|
4089
|
+
logger.info(`${dryRun ? "Would import" : "Imported"}: ${payload.stored || importable.length} memories`);
|
|
4090
|
+
logger.info(`Parsed: ${parsed.length}`);
|
|
4091
|
+
logger.info(`Skipped unsafe: ${findings.length}`);
|
|
4092
|
+
for (const finding of findings) logger.warn(`- ${finding.message}`);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
mdCommand.command("import").description("Import a markdown memory file into Unforgit; dry-run by default").argument("<file>", "Markdown file to import, for example CLAUDE.md or MEMORY.md").option("--dry-run", "Preview import without writing memories").option("--apply", "Store safe, non-duplicate parsed memories").option("--json", "Output machine-readable JSON").action((file, opts) => importMarkdown(file, opts));
|
|
4096
|
+
mdCommand.command("scan").description("Parse and safety-check a markdown memory file without writing").argument("<file>", "Markdown file to scan").option("--json", "Output machine-readable JSON").action((file, opts) => importMarkdown(file, { ...opts, dryRun: true }));
|
|
4097
|
+
mdCommand.command("export").description("Export active Unforgit memories to a markdown memory file").option("--format <format>", "Markdown flavor (claude|generic)", "generic").option("--out <file>", "Output markdown path").option("--tags <tags>", "Comma-separated tag filter").option("--types <types>", "Comma-separated memory types").option("--json", "Output machine-readable JSON").action((opts) => {
|
|
4098
|
+
const config = loadConfig();
|
|
4099
|
+
const store = new LocalStore(getDbPath());
|
|
4100
|
+
const out = path5.resolve(opts.out ?? (opts.format === "claude" ? "CLAUDE.md" : "MEMORY.md"));
|
|
4101
|
+
try {
|
|
4102
|
+
const types = opts.types ? opts.types.split(",").map((type) => type.trim()).filter(Boolean) : void 0;
|
|
4103
|
+
const tags = opts.tags ? opts.tags.split(",").map((tag) => tag.trim()).filter(Boolean) : void 0;
|
|
4104
|
+
const memories = store.list({
|
|
4105
|
+
orgId: config.remote.orgId || "local",
|
|
4106
|
+
repoId: config.remote.repoId || "local",
|
|
4107
|
+
status: ["active"],
|
|
4108
|
+
types,
|
|
4109
|
+
tags,
|
|
4110
|
+
limit: 1e4
|
|
4111
|
+
});
|
|
4112
|
+
const markdown = exportMarkdownMemories(
|
|
4113
|
+
memories.map((memory) => ({
|
|
4114
|
+
id: memory.id,
|
|
4115
|
+
text: memory.text,
|
|
4116
|
+
memoryType: memory.memoryType,
|
|
4117
|
+
tags: memory.tags
|
|
4118
|
+
})),
|
|
4119
|
+
{ format: opts.format === "claude" ? "claude" : "generic", title: path5.basename(out) }
|
|
4120
|
+
);
|
|
4121
|
+
fs7.mkdirSync(path5.dirname(out), { recursive: true });
|
|
4122
|
+
fs7.writeFileSync(out, markdown, "utf-8");
|
|
4123
|
+
const payload = { exported: memories.length, out, format: opts.format };
|
|
4124
|
+
if (opts.json || isJsonMode()) outputJson(payload);
|
|
4125
|
+
else logger.info(`Exported ${memories.length} memories to ${out}`);
|
|
4126
|
+
} finally {
|
|
4127
|
+
store.close();
|
|
4128
|
+
}
|
|
4129
|
+
});
|
|
4130
|
+
mdCommand.command("doctor").description("Check a markdown memory file for unsafe entries and importability").argument("<file>", "Markdown file to inspect").option("--json", "Output machine-readable JSON").action((file, opts) => importMarkdown(file, { ...opts, dryRun: true }));
|
|
4131
|
+
|
|
4008
4132
|
// src/index.ts
|
|
4009
4133
|
import { createRequire } from "module";
|
|
4010
4134
|
var require2 = createRequire(import.meta.url);
|
|
@@ -4043,7 +4167,7 @@ process.on("unhandledRejection", (err) => {
|
|
|
4043
4167
|
runCleanup();
|
|
4044
4168
|
process.exit(EXIT_ERROR);
|
|
4045
4169
|
});
|
|
4046
|
-
var program = new
|
|
4170
|
+
var program = new Command32();
|
|
4047
4171
|
program.name("unforgit").description("Unforgit \u2014 repository memory for agents and developers").version(pkg.version).option("--verbose", "Enable verbose output").option("--quiet", "Suppress non-essential output").option("--json", "Output results as JSON (for scripting)").hook("preAction", () => {
|
|
4048
4172
|
const opts = program.opts();
|
|
4049
4173
|
if (opts.quiet) setVerbosity(0);
|
|
@@ -4085,6 +4209,7 @@ program.addCommand(dashboardCommand);
|
|
|
4085
4209
|
program.addCommand(doctorCommand);
|
|
4086
4210
|
program.addCommand(curateCommand);
|
|
4087
4211
|
program.addCommand(suggestionsCommand);
|
|
4212
|
+
program.addCommand(mdCommand);
|
|
4088
4213
|
program.addCommand(completionCommand);
|
|
4089
4214
|
program.parseAsync().catch((err) => {
|
|
4090
4215
|
console.error(`fatal: ${err instanceof Error ? err.message : err}`);
|