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/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-VESJIIT2.js";
38
+ } from "./chunk-JXSAAZ3I.js";
35
39
 
36
40
  // src/index.ts
37
- import { Command as Command31 } from "commander";
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 Command31();
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}`);