claude-memory-explorer 0.1.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.
Files changed (80) hide show
  1. package/.claude-plugin/plugin.json +19 -0
  2. package/LICENSE +21 -0
  3. package/README.md +177 -0
  4. package/dist/cli/commands/dedupe.d.ts +1 -0
  5. package/dist/cli/commands/dedupe.js +187 -0
  6. package/dist/cli/commands/dedupe.js.map +1 -0
  7. package/dist/cli/commands/doctor.d.ts +1 -0
  8. package/dist/cli/commands/doctor.js +177 -0
  9. package/dist/cli/commands/doctor.js.map +1 -0
  10. package/dist/cli/commands/lint.d.ts +1 -0
  11. package/dist/cli/commands/lint.js +139 -0
  12. package/dist/cli/commands/lint.js.map +1 -0
  13. package/dist/cli/commands/list.d.ts +1 -0
  14. package/dist/cli/commands/list.js +97 -0
  15. package/dist/cli/commands/list.js.map +1 -0
  16. package/dist/cli/commands/mcp.d.ts +1 -0
  17. package/dist/cli/commands/mcp.js +105 -0
  18. package/dist/cli/commands/mcp.js.map +1 -0
  19. package/dist/cli/commands/merge.d.ts +1 -0
  20. package/dist/cli/commands/merge.js +111 -0
  21. package/dist/cli/commands/merge.js.map +1 -0
  22. package/dist/cli/commands/promote.d.ts +1 -0
  23. package/dist/cli/commands/promote.js +157 -0
  24. package/dist/cli/commands/promote.js.map +1 -0
  25. package/dist/cli/commands/tui.d.ts +1 -0
  26. package/dist/cli/commands/tui.js +60 -0
  27. package/dist/cli/commands/tui.js.map +1 -0
  28. package/dist/cli/commands/undo.d.ts +1 -0
  29. package/dist/cli/commands/undo.js +157 -0
  30. package/dist/cli/commands/undo.js.map +1 -0
  31. package/dist/cli/index.d.ts +2 -0
  32. package/dist/cli/index.js +85 -0
  33. package/dist/cli/index.js.map +1 -0
  34. package/dist/cli/tui/App.d.ts +8 -0
  35. package/dist/cli/tui/App.js +333 -0
  36. package/dist/cli/tui/App.js.map +1 -0
  37. package/dist/core/apply.d.ts +27 -0
  38. package/dist/core/apply.js +191 -0
  39. package/dist/core/apply.js.map +1 -0
  40. package/dist/core/claudeMd.d.ts +27 -0
  41. package/dist/core/claudeMd.js +103 -0
  42. package/dist/core/claudeMd.js.map +1 -0
  43. package/dist/core/dedupe.d.ts +78 -0
  44. package/dist/core/dedupe.js +212 -0
  45. package/dist/core/dedupe.js.map +1 -0
  46. package/dist/core/doctor.d.ts +35 -0
  47. package/dist/core/doctor.js +106 -0
  48. package/dist/core/doctor.js.map +1 -0
  49. package/dist/core/journal.d.ts +31 -0
  50. package/dist/core/journal.js +64 -0
  51. package/dist/core/journal.js.map +1 -0
  52. package/dist/core/lint.d.ts +26 -0
  53. package/dist/core/lint.js +254 -0
  54. package/dist/core/lint.js.map +1 -0
  55. package/dist/core/memoryIndex.d.ts +42 -0
  56. package/dist/core/memoryIndex.js +81 -0
  57. package/dist/core/memoryIndex.js.map +1 -0
  58. package/dist/core/merge.d.ts +19 -0
  59. package/dist/core/merge.js +58 -0
  60. package/dist/core/merge.js.map +1 -0
  61. package/dist/core/parse.d.ts +2 -0
  62. package/dist/core/parse.js +84 -0
  63. package/dist/core/parse.js.map +1 -0
  64. package/dist/core/plan.d.ts +34 -0
  65. package/dist/core/plan.js +85 -0
  66. package/dist/core/plan.js.map +1 -0
  67. package/dist/core/promote.d.ts +29 -0
  68. package/dist/core/promote.js +103 -0
  69. package/dist/core/promote.js.map +1 -0
  70. package/dist/core/scan.d.ts +16 -0
  71. package/dist/core/scan.js +81 -0
  72. package/dist/core/scan.js.map +1 -0
  73. package/dist/core/types.d.ts +36 -0
  74. package/dist/core/types.js +4 -0
  75. package/dist/core/types.js.map +1 -0
  76. package/dist/mcp/server.d.ts +13 -0
  77. package/dist/mcp/server.js +211 -0
  78. package/dist/mcp/server.js.map +1 -0
  79. package/package.json +71 -0
  80. package/skills/curate-memory/SKILL.md +60 -0
@@ -0,0 +1,139 @@
1
+ // `memex lint` — report structural problems with memory files.
2
+ //
3
+ // Exit codes:
4
+ // 0 — no issues, or only `info`/`warn` (unless --strict is set)
5
+ // 1 — at least one `error` issue (or any issue if --strict)
6
+ // 2 — bad usage
7
+ import { lintAll } from "../../core/lint.js";
8
+ import { relative } from "node:path";
9
+ import { homedir } from "node:os";
10
+ function parseArgs(argv) {
11
+ const out = { json: false, strict: false, verbose: false, help: false };
12
+ for (let i = 0; i < argv.length; i++) {
13
+ const a = argv[i];
14
+ switch (a) {
15
+ case "--project":
16
+ out.project = argv[++i];
17
+ break;
18
+ case "--root":
19
+ out.root = argv[++i];
20
+ break;
21
+ case "--json":
22
+ out.json = true;
23
+ break;
24
+ case "--strict":
25
+ out.strict = true;
26
+ break;
27
+ case "--verbose":
28
+ case "-v":
29
+ out.verbose = true;
30
+ break;
31
+ case "--help":
32
+ case "-h":
33
+ out.help = true;
34
+ break;
35
+ default:
36
+ throw new Error(`unknown flag: ${a}`);
37
+ }
38
+ }
39
+ return out;
40
+ }
41
+ const HELP = `memex lint — find structural problems in your memory tree
42
+
43
+ Usage:
44
+ memex lint [--project SUBSTR] [--json] [--strict] [--verbose] [--root PATH]
45
+
46
+ Flags:
47
+ --project SUBSTR Filter projects whose slug contains SUBSTR
48
+ --json Output JSON instead of human-readable lines
49
+ --strict Exit 1 on any issue (default: only error issues)
50
+ --verbose, -v Show scan-level warnings on stderr
51
+ --root PATH Override projects root (default: ~/.claude/projects)
52
+
53
+ Severities:
54
+ error Confirmed problem (data loss, unusable file)
55
+ warn Likely problem (broken link, missing index)
56
+ info Informational (untyped file, orphan with pointer index)
57
+
58
+ Exit codes:
59
+ 0 no issues (or only warn/info without --strict)
60
+ 1 one or more error issues (or any issue with --strict)
61
+ 2 bad usage
62
+ `;
63
+ const SEV_LABEL = {
64
+ error: "ERROR",
65
+ warn: "WARN ",
66
+ info: "INFO ",
67
+ };
68
+ function shortPath(p) {
69
+ if (!p)
70
+ return "";
71
+ const home = homedir();
72
+ if (p.startsWith(home))
73
+ return "~" + p.slice(home.length);
74
+ try {
75
+ const rel = relative(process.cwd(), p);
76
+ return rel.length < p.length ? rel : p;
77
+ }
78
+ catch {
79
+ return p;
80
+ }
81
+ }
82
+ function formatIssue(issue) {
83
+ const lines = [
84
+ `[${SEV_LABEL[issue.severity]}] ${issue.code} (${issue.projectSlug})`,
85
+ ` ${issue.message}`,
86
+ ];
87
+ if (issue.filePath) {
88
+ lines.push(` at: ${shortPath(issue.filePath)}`);
89
+ }
90
+ if (issue.hint) {
91
+ lines.push(` hint: ${issue.hint}`);
92
+ }
93
+ return lines.join("\n");
94
+ }
95
+ export function runLint(argv) {
96
+ let args;
97
+ try {
98
+ args = parseArgs(argv);
99
+ }
100
+ catch (err) {
101
+ process.stderr.write(`memex lint: ${err instanceof Error ? err.message : String(err)}\n\n${HELP}`);
102
+ return 2;
103
+ }
104
+ if (args.help) {
105
+ process.stdout.write(HELP);
106
+ return 0;
107
+ }
108
+ const result = lintAll({
109
+ projectsRoot: args.root,
110
+ projectFilter: args.project,
111
+ onWarning: args.verbose ? (m) => process.stderr.write(`${m}\n`) : undefined,
112
+ });
113
+ if (args.json) {
114
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
115
+ }
116
+ else {
117
+ if (result.issues.length === 0) {
118
+ process.stdout.write(`✓ No issues across ${result.projectsScanned} projects (${result.filesScanned} memory files scanned).\n`);
119
+ }
120
+ else {
121
+ for (const issue of result.issues) {
122
+ process.stdout.write(`${formatIssue(issue)}\n\n`);
123
+ }
124
+ const counts = { error: 0, warn: 0, info: 0 };
125
+ for (const i of result.issues)
126
+ counts[i.severity]++;
127
+ process.stdout.write(`${result.issues.length} issue(s): ` +
128
+ `${counts.error} error, ${counts.warn} warn, ${counts.info} info ` +
129
+ `across ${result.projectsScanned} projects (${result.filesScanned} files).\n`);
130
+ }
131
+ }
132
+ const hasError = result.issues.some((i) => i.severity === "error");
133
+ if (hasError)
134
+ return 1;
135
+ if (args.strict && result.issues.length > 0)
136
+ return 1;
137
+ return 0;
138
+ }
139
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../../src/cli/commands/lint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runList(argv: string[]): number;
@@ -0,0 +1,97 @@
1
+ // `memex list` — read-only view of memories across all projects.
2
+ //
3
+ // Flags:
4
+ // --type <user|feedback|project|reference|untyped> filter by type
5
+ // --project <substring> filter by slug substring
6
+ // --json machine output
7
+ // --root <path> override projects root (testing)
8
+ import { scanAll, allMemories } from "../../core/scan.js";
9
+ import { MEMORY_TYPES } from "../../core/types.js";
10
+ const VALID_TYPES = new Set([...MEMORY_TYPES, "untyped"]);
11
+ function parseArgs(argv) {
12
+ const out = { json: false, verbose: false };
13
+ for (let i = 0; i < argv.length; i++) {
14
+ const a = argv[i];
15
+ switch (a) {
16
+ case "--type":
17
+ out.type = argv[++i];
18
+ break;
19
+ case "--project":
20
+ out.project = argv[++i];
21
+ break;
22
+ case "--root":
23
+ out.root = argv[++i];
24
+ break;
25
+ case "--json":
26
+ out.json = true;
27
+ break;
28
+ case "--verbose":
29
+ case "-v":
30
+ out.verbose = true;
31
+ break;
32
+ case "--help":
33
+ case "-h":
34
+ out.type = "__help__";
35
+ return out;
36
+ default:
37
+ throw new Error(`unknown flag: ${a}`);
38
+ }
39
+ }
40
+ return out;
41
+ }
42
+ const HELP = `memex list — list memories across projects
43
+
44
+ Usage:
45
+ memex list [--type TYPE] [--project SUBSTR] [--json] [--verbose] [--root PATH]
46
+
47
+ Flags:
48
+ --type TYPE Filter: user, feedback, project, reference, untyped
49
+ --project SUBSTR Filter projects whose slug contains SUBSTR
50
+ --json Output JSON instead of human-readable lines
51
+ --verbose, -v Show scan-level warnings on stderr (broken frontmatter, etc.)
52
+ --root PATH Override projects root (default: ~/.claude/projects)
53
+ `;
54
+ function formatLine(m) {
55
+ const desc = m.description ?? "(no description)";
56
+ return `[${m.type.padEnd(9)}] ${m.id}\n ${desc}\n`;
57
+ }
58
+ export function runList(argv) {
59
+ let args;
60
+ try {
61
+ args = parseArgs(argv);
62
+ }
63
+ catch (err) {
64
+ process.stderr.write(`memex list: ${err instanceof Error ? err.message : String(err)}\n\n${HELP}`);
65
+ return 2;
66
+ }
67
+ if (args.type === "__help__") {
68
+ process.stdout.write(HELP);
69
+ return 0;
70
+ }
71
+ if (args.type && !VALID_TYPES.has(args.type)) {
72
+ process.stderr.write(`memex list: --type must be one of: ${[...VALID_TYPES].join(", ")}\n`);
73
+ return 2;
74
+ }
75
+ const projects = scanAll({
76
+ projectsRoot: args.root,
77
+ onWarning: args.verbose ? (m) => process.stderr.write(`${m}\n`) : undefined,
78
+ });
79
+ const filteredProjects = args.project
80
+ ? projects.filter((p) => p.slug.includes(args.project))
81
+ : projects;
82
+ const memories = allMemories(filteredProjects).filter((m) => !args.type || m.type === args.type);
83
+ if (args.json) {
84
+ process.stdout.write(`${JSON.stringify(memories, null, 2)}\n`);
85
+ return 0;
86
+ }
87
+ if (memories.length === 0) {
88
+ process.stdout.write("(no memories found)\n");
89
+ return 0;
90
+ }
91
+ for (const m of memories) {
92
+ process.stdout.write(`${formatLine(m)}\n`);
93
+ }
94
+ process.stdout.write(`${memories.length} memories across ${filteredProjects.length} projects\n`);
95
+ return 0;
96
+ }
97
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/cli/commands/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runMcp(argv: string[]): Promise<number>;
@@ -0,0 +1,105 @@
1
+ // `memex mcp` — run as an MCP server over stdio.
2
+ //
3
+ // Wire-up in Claude Code:
4
+ // claude mcp add --transport stdio memex -- npx -y memex mcp
5
+ //
6
+ // Or in .mcp.json:
7
+ // {
8
+ // "mcpServers": {
9
+ // "memex": {
10
+ // "type": "stdio",
11
+ // "command": "npx",
12
+ // "args": ["-y", "memex", "mcp"]
13
+ // }
14
+ // }
15
+ // }
16
+ import { readFileSync } from "node:fs";
17
+ import { fileURLToPath } from "node:url";
18
+ import { dirname, join } from "node:path";
19
+ function parseArgs(argv) {
20
+ const out = { help: false };
21
+ for (let i = 0; i < argv.length; i++) {
22
+ const a = argv[i];
23
+ switch (a) {
24
+ case "--root":
25
+ out.root = argv[++i];
26
+ break;
27
+ case "--claude-md":
28
+ out.claudeMd = argv[++i];
29
+ break;
30
+ case "--journal-dir":
31
+ out.journalDir = argv[++i];
32
+ break;
33
+ case "--help":
34
+ case "-h":
35
+ out.help = true;
36
+ break;
37
+ default:
38
+ throw new Error(`unknown flag: ${a}`);
39
+ }
40
+ }
41
+ return out;
42
+ }
43
+ const HELP = `memex mcp — run as an MCP server over stdio
44
+
45
+ Usage:
46
+ memex mcp [--root PATH] [--claude-md PATH] [--journal-dir PATH]
47
+
48
+ This subcommand does not produce normal stdout — it implements the MCP
49
+ JSON-RPC protocol on stdin/stdout. Use it from Claude Code (or any
50
+ MCP client) by configuring:
51
+
52
+ claude mcp add --transport stdio memex -- npx -y memex mcp
53
+
54
+ Exposed tools:
55
+ list_memories — read-only, returns Memory[]
56
+ find_duplicates — read-only, returns cluster summary
57
+ lint — read-only, structural issues
58
+ doctor — read-only, full health report
59
+ plan_merge — build a Plan to collapse a duplicate cluster
60
+ plan_promote_memory — build a Plan to promote one memory to CLAUDE.md
61
+ plan_promote_cluster — build a Plan to promote whole cluster + delete copies
62
+ apply_plan — execute a previously-built Plan (journaled, undoable)
63
+ undo — reverse the most recent applied plan
64
+ journal_list — list all journal entries (newest first)
65
+ journal_latest — return the most recent journal entry
66
+
67
+ Flags (mainly for testing):
68
+ --root PATH Override projects root
69
+ --claude-md PATH Override CLAUDE.md target for promote
70
+ --journal-dir PATH Override journal dir
71
+ `;
72
+ const __dirname = dirname(fileURLToPath(import.meta.url));
73
+ function readVersion() {
74
+ try {
75
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "..", "..", "package.json"), "utf8"));
76
+ return pkg.version;
77
+ }
78
+ catch {
79
+ return "0.0.0";
80
+ }
81
+ }
82
+ export async function runMcp(argv) {
83
+ let args;
84
+ try {
85
+ args = parseArgs(argv);
86
+ }
87
+ catch (err) {
88
+ process.stderr.write(`memex mcp: ${err instanceof Error ? err.message : String(err)}\n\n${HELP}`);
89
+ return 2;
90
+ }
91
+ if (args.help) {
92
+ process.stdout.write(HELP);
93
+ return 0;
94
+ }
95
+ // Lazy-import so the rest of the CLI doesn't pay the MCP SDK startup cost.
96
+ const { runMcpServerStdio } = await import("../../mcp/server.js");
97
+ await runMcpServerStdio({
98
+ version: readVersion(),
99
+ projectsRoot: args.root,
100
+ claudeMdPath: args.claudeMd,
101
+ journalDir: args.journalDir,
102
+ });
103
+ return 0;
104
+ }
105
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../src/cli/commands/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runMerge(argv: string[]): number;
@@ -0,0 +1,111 @@
1
+ // `memex merge` — collapse a duplicate cluster down to its representative.
2
+ //
3
+ // Default is dry-run (prints the plan, writes nothing). `--apply` actually
4
+ // commits via Phase 5's applyPlan. The mutation is journaled and reversible
5
+ // via `memex undo`.
6
+ import { findDuplicates } from "../../core/dedupe.js";
7
+ import { buildMergePlan } from "../../core/merge.js";
8
+ import { applyPlan } from "../../core/apply.js";
9
+ import { describePlan } from "../../core/plan.js";
10
+ function parseArgs(argv) {
11
+ const out = { apply: false, skipIndexUpdate: false, help: false };
12
+ for (let i = 0; i < argv.length; i++) {
13
+ const a = argv[i];
14
+ switch (a) {
15
+ case "--cluster":
16
+ out.cluster = argv[++i];
17
+ break;
18
+ case "--keep":
19
+ out.keep = argv[++i];
20
+ break;
21
+ case "--apply":
22
+ out.apply = true;
23
+ break;
24
+ case "--skip-index-update":
25
+ out.skipIndexUpdate = true;
26
+ break;
27
+ case "--root":
28
+ out.root = argv[++i];
29
+ break;
30
+ case "--journal-dir":
31
+ out.journalDir = argv[++i];
32
+ break;
33
+ case "--help":
34
+ case "-h":
35
+ out.help = true;
36
+ break;
37
+ default:
38
+ throw new Error(`unknown flag: ${a}`);
39
+ }
40
+ }
41
+ return out;
42
+ }
43
+ const HELP = `memex merge — collapse a duplicate cluster down to its representative
44
+
45
+ Usage:
46
+ memex merge --cluster <id> [--apply] [--keep <memory-id>]
47
+ [--skip-index-update] [--root PATH]
48
+
49
+ Flags:
50
+ --cluster <id> Cluster id from \`memex dedupe\` (e.g. c1)
51
+ --keep <memory-id> Override which member to keep (default: cluster's
52
+ representative — longest body, most recent mtime)
53
+ --apply Actually execute the plan (default is dry-run)
54
+ --skip-index-update Don't modify MEMORY.md (leaves dangling refs;
55
+ \`memex lint\` will catch them)
56
+ --root PATH Override projects root
57
+ --journal-dir PATH Override journal dir (testing)
58
+
59
+ The plan is fully undoable via \`memex undo\`.
60
+ `;
61
+ export function runMerge(argv) {
62
+ let args;
63
+ try {
64
+ args = parseArgs(argv);
65
+ }
66
+ catch (err) {
67
+ process.stderr.write(`memex merge: ${err instanceof Error ? err.message : String(err)}\n\n${HELP}`);
68
+ return 2;
69
+ }
70
+ if (args.help) {
71
+ process.stdout.write(HELP);
72
+ return 0;
73
+ }
74
+ if (!args.cluster) {
75
+ process.stderr.write(`memex merge: --cluster <id> is required\n\n${HELP}`);
76
+ return 2;
77
+ }
78
+ const dedupeResult = findDuplicates({ projectsRoot: args.root });
79
+ const cluster = dedupeResult.clusters.find((c) => c.id === args.cluster);
80
+ if (!cluster) {
81
+ process.stderr.write(`memex merge: cluster "${args.cluster}" not found. Run \`memex dedupe\` to list current clusters.\n`);
82
+ return 2;
83
+ }
84
+ let plan;
85
+ try {
86
+ ({ plan } = buildMergePlan(cluster, {
87
+ keepId: args.keep,
88
+ skipIndexUpdate: args.skipIndexUpdate,
89
+ }));
90
+ }
91
+ catch (err) {
92
+ process.stderr.write(`memex merge: ${err instanceof Error ? err.message : String(err)}\n`);
93
+ return 2;
94
+ }
95
+ if (!args.apply) {
96
+ process.stdout.write(`${describePlan(plan)}\n\n(dry run — pass --apply to execute)\n`);
97
+ return 0;
98
+ }
99
+ const journalOpts = args.journalDir ? { journalDir: args.journalDir } : {};
100
+ const entry = applyPlan(plan, {
101
+ ...journalOpts,
102
+ onProgress: (m) => process.stdout.write(`${m}\n`),
103
+ });
104
+ if (entry.status === "complete") {
105
+ process.stdout.write(`\n✓ Merge complete (plan ${plan.id}). Run \`memex undo\` to reverse.\n`);
106
+ return 0;
107
+ }
108
+ process.stderr.write(`\n✗ Merge ${entry.status}. Some ops failed — \`memex undo --list\` shows state.\n`);
109
+ return 1;
110
+ }
111
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../src/cli/commands/merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runPromote(argv: string[]): number;
@@ -0,0 +1,157 @@
1
+ // `memex promote` — move a memory (or whole cluster) into
2
+ // `~/.claude/CLAUDE.md` as a managed block.
3
+ //
4
+ // Default is dry-run. `--apply` actually executes. All mutations go through
5
+ // Phase 5's plan/apply/journal and are reversible via `memex undo`.
6
+ import { readFileSync } from "node:fs";
7
+ import { findDuplicates } from "../../core/dedupe.js";
8
+ import { buildPromoteMemoryPlan, buildPromoteClusterPlan } from "../../core/promote.js";
9
+ import { applyPlan } from "../../core/apply.js";
10
+ import { describePlan } from "../../core/plan.js";
11
+ import { scanAll } from "../../core/scan.js";
12
+ function parseArgs(argv) {
13
+ const out = { apply: false, skipIndexUpdate: false, help: false };
14
+ for (let i = 0; i < argv.length; i++) {
15
+ const a = argv[i];
16
+ switch (a) {
17
+ case "--memory":
18
+ out.memory = argv[++i];
19
+ break;
20
+ case "--cluster":
21
+ out.cluster = argv[++i];
22
+ break;
23
+ case "--apply":
24
+ out.apply = true;
25
+ break;
26
+ case "--skip-index-update":
27
+ out.skipIndexUpdate = true;
28
+ break;
29
+ case "--claude-md":
30
+ out.claudeMd = argv[++i];
31
+ break;
32
+ case "--root":
33
+ out.root = argv[++i];
34
+ break;
35
+ case "--journal-dir":
36
+ out.journalDir = argv[++i];
37
+ break;
38
+ case "--help":
39
+ case "-h":
40
+ out.help = true;
41
+ break;
42
+ default:
43
+ throw new Error(`unknown flag: ${a}`);
44
+ }
45
+ }
46
+ return out;
47
+ }
48
+ const HELP = `memex promote — promote a memory to ~/.claude/CLAUDE.md
49
+
50
+ Usage:
51
+ memex promote --memory <id> [--apply]
52
+ memex promote --cluster <id> [--apply]
53
+
54
+ Either --memory or --cluster must be set.
55
+
56
+ --memory <id> Memory id from \`memex list --json\` (slug/filename)
57
+ --cluster <id> Cluster id from \`memex dedupe\` — promotes the
58
+ representative AND deletes every cluster member
59
+ (the global block replaces all copies)
60
+ --apply Actually execute the plan (default is dry-run)
61
+ --skip-index-update Don't modify MEMORY.md (leaves dangling refs)
62
+ --claude-md PATH Override destination (default: ~/.claude/CLAUDE.md)
63
+ --root PATH Override projects root
64
+ --journal-dir PATH Override journal dir (testing)
65
+
66
+ The destination uses memex-managed marker blocks:
67
+ <!-- memex:start:<slug> -->
68
+ ## <heading>
69
+ <body>
70
+ <!-- memex:end:<slug> -->
71
+
72
+ Content outside markers is never touched. Re-promoting the same slug
73
+ replaces the block in place (idempotent).
74
+ `;
75
+ export function runPromote(argv) {
76
+ let args;
77
+ try {
78
+ args = parseArgs(argv);
79
+ }
80
+ catch (err) {
81
+ process.stderr.write(`memex promote: ${err instanceof Error ? err.message : String(err)}\n\n${HELP}`);
82
+ return 2;
83
+ }
84
+ if (args.help) {
85
+ process.stdout.write(HELP);
86
+ return 0;
87
+ }
88
+ if (!args.memory && !args.cluster) {
89
+ process.stderr.write(`memex promote: one of --memory or --cluster is required\n\n${HELP}`);
90
+ return 2;
91
+ }
92
+ if (args.memory && args.cluster) {
93
+ process.stderr.write(`memex promote: --memory and --cluster are mutually exclusive\n`);
94
+ return 2;
95
+ }
96
+ let plan;
97
+ if (args.memory) {
98
+ const projects = scanAll({ projectsRoot: args.root });
99
+ const memory = projects.flatMap((p) => p.memories).find((m) => m.id === args.memory);
100
+ if (!memory) {
101
+ process.stderr.write(`memex promote: memory "${args.memory}" not found. Run \`memex list\` to see available ids.\n`);
102
+ return 2;
103
+ }
104
+ ({ plan } = buildPromoteMemoryPlan(memory, {
105
+ claudeMdPath: args.claudeMd,
106
+ skipIndexUpdate: args.skipIndexUpdate,
107
+ }));
108
+ }
109
+ else {
110
+ const dedupeResult = findDuplicates({ projectsRoot: args.root });
111
+ const cluster = dedupeResult.clusters.find((c) => c.id === args.cluster);
112
+ if (!cluster) {
113
+ process.stderr.write(`memex promote: cluster "${args.cluster}" not found. Run \`memex dedupe\` to list.\n`);
114
+ return 2;
115
+ }
116
+ const rep = cluster.members.find((m) => m.id === cluster.representative.id);
117
+ let repBody = "";
118
+ try {
119
+ const raw = readFileSync(rep.filePath, "utf8");
120
+ // Strip frontmatter if present — body is everything after the closing ---.
121
+ repBody = stripFrontmatter(raw).trim();
122
+ }
123
+ catch (err) {
124
+ process.stderr.write(`memex promote: cannot read representative ${rep.filePath}: ${err instanceof Error ? err.message : String(err)}\n`);
125
+ return 2;
126
+ }
127
+ ({ plan } = buildPromoteClusterPlan(cluster, repBody, {
128
+ claudeMdPath: args.claudeMd,
129
+ skipIndexUpdate: args.skipIndexUpdate,
130
+ }));
131
+ }
132
+ if (!args.apply) {
133
+ process.stdout.write(`${describePlan(plan)}\n\n(dry run — pass --apply to execute)\n`);
134
+ return 0;
135
+ }
136
+ const journalOpts = args.journalDir ? { journalDir: args.journalDir } : {};
137
+ const entry = applyPlan(plan, {
138
+ ...journalOpts,
139
+ onProgress: (m) => process.stdout.write(`${m}\n`),
140
+ });
141
+ if (entry.status === "complete") {
142
+ process.stdout.write(`\n✓ Promote complete (plan ${plan.id}). Run \`memex undo\` to reverse.\n`);
143
+ return 0;
144
+ }
145
+ process.stderr.write(`\n✗ Promote ${entry.status}. \`memex undo --list\` shows state.\n`);
146
+ return 1;
147
+ }
148
+ function stripFrontmatter(raw) {
149
+ if (!raw.startsWith("---"))
150
+ return raw;
151
+ // Find the closing --- on its own line after the opening.
152
+ const m = raw.match(/^---\n[\s\S]*?\n---\n?/);
153
+ if (!m)
154
+ return raw;
155
+ return raw.slice(m[0].length);
156
+ }
157
+ //# sourceMappingURL=promote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promote.js","sourceRoot":"","sources":["../../../src/cli/commands/promote.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runTui(argv: string[]): Promise<number>;