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,333 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // memex TUI — three-pane browser.
3
+ //
4
+ // Read-only in v0.1. Mutating actions (merge, promote, undo) stay on the
5
+ // CLI, which already has the dry-run safety + journal. The TUI is the
6
+ // "find me what I want, then I'll run the CLI" workflow.
7
+ import { useEffect, useMemo, useState } from "react";
8
+ import { spawnSync } from "node:child_process";
9
+ import { Box, Text, useApp, useInput, useStdin } from "ink";
10
+ import { scanAll, allMemories } from "../../core/scan.js";
11
+ import { findDuplicates } from "../../core/dedupe.js";
12
+ import { lintAll } from "../../core/lint.js";
13
+ export function App({ projectsRoot, initialProjects }) {
14
+ const { exit } = useApp();
15
+ const { setRawMode, isRawModeSupported } = useStdin();
16
+ const [projects, setProjects] = useState(initialProjects ?? []);
17
+ const [mode, setMode] = useState("browse");
18
+ const [pane, setPane] = useState(0); // 0 = projects pane, 1 = memories pane
19
+ const [selectedProject, setSelectedProject] = useState(0);
20
+ const [selectedMemory, setSelectedMemory] = useState(0);
21
+ const [searchQuery, setSearchQuery] = useState("");
22
+ const [clusters, setClusters] = useState(null);
23
+ const [lintIssues, setLintIssues] = useState(null);
24
+ const [selectedClusterIdx, setSelectedClusterIdx] = useState(0);
25
+ const [selectedIssueIdx, setSelectedIssueIdx] = useState(0);
26
+ const [showEmptyProjects, setShowEmptyProjects] = useState(false);
27
+ const [previewScroll, setPreviewScroll] = useState(0);
28
+ // Initial load if no fixture data was injected.
29
+ useEffect(() => {
30
+ if (initialProjects)
31
+ return;
32
+ setProjects(scanAll({ projectsRoot }));
33
+ }, [projectsRoot, initialProjects]);
34
+ // Visible project list — collapses empty projects by default. Empty memory
35
+ // dirs are noisy on tree views (Claude Code creates them lazily on first
36
+ // open, even before any memory is written). Toggle with `a`.
37
+ const visibleProjects = useMemo(() => (showEmptyProjects ? projects : projects.filter((p) => p.memories.length > 0)), [projects, showEmptyProjects]);
38
+ // Derived: flat list of memories for search mode.
39
+ const allMems = useMemo(() => allMemories(projects), [projects]);
40
+ const searchResults = useMemo(() => {
41
+ if (!searchQuery)
42
+ return allMems;
43
+ const q = searchQuery.toLowerCase();
44
+ return allMems.filter((m) => {
45
+ return (m.fileName.toLowerCase().includes(q) ||
46
+ m.projectSlug.toLowerCase().includes(q) ||
47
+ (m.name?.toLowerCase().includes(q) ?? false) ||
48
+ (m.description?.toLowerCase().includes(q) ?? false) ||
49
+ m.body.toLowerCase().includes(q));
50
+ });
51
+ }, [allMems, searchQuery]);
52
+ const currentProject = visibleProjects[selectedProject];
53
+ const currentMemory = mode === "search"
54
+ ? searchResults[selectedMemory]
55
+ : currentProject?.memories[selectedMemory];
56
+ // Keep selection indices in bounds when underlying data changes.
57
+ useEffect(() => {
58
+ if (selectedProject >= visibleProjects.length)
59
+ setSelectedProject(0);
60
+ }, [visibleProjects, selectedProject]);
61
+ useEffect(() => {
62
+ const max = mode === "search"
63
+ ? searchResults.length
64
+ : (currentProject?.memories.length ?? 0);
65
+ if (selectedMemory >= max)
66
+ setSelectedMemory(0);
67
+ }, [searchResults, currentProject, selectedMemory, mode]);
68
+ useInput((input, key) => {
69
+ // Global quit
70
+ if (input === "q" && mode !== "search") {
71
+ exit();
72
+ return;
73
+ }
74
+ if (key.escape) {
75
+ if (mode === "search" || mode === "help" || mode === "dedupe" || mode === "lint" || mode === "preview") {
76
+ setMode("browse");
77
+ setSearchQuery("");
78
+ return;
79
+ }
80
+ }
81
+ // Open in $EDITOR (works from browse, search, preview — whenever a memory
82
+ // is selected).
83
+ if (input === "o" && currentMemory) {
84
+ const editor = process.env.VISUAL ?? process.env.EDITOR ?? "vi";
85
+ // Suspend ink so the editor takes over the terminal.
86
+ if (isRawModeSupported)
87
+ setRawMode(false);
88
+ try {
89
+ spawnSync(editor, [currentMemory.filePath], { stdio: "inherit" });
90
+ }
91
+ finally {
92
+ if (isRawModeSupported)
93
+ setRawMode(true);
94
+ }
95
+ return;
96
+ }
97
+ // Enter / v / right-arrow from browse opens full preview modal.
98
+ if ((key.return || input === "v") && mode === "browse" && pane === 1 && currentMemory) {
99
+ setPreviewScroll(0);
100
+ setMode("preview");
101
+ return;
102
+ }
103
+ if (input === "v" && mode === "search" && currentMemory) {
104
+ setPreviewScroll(0);
105
+ setMode("preview");
106
+ return;
107
+ }
108
+ // Scroll inside preview mode.
109
+ if (mode === "preview") {
110
+ const bodyLines = (currentMemory?.body ?? "").split("\n").length;
111
+ const visibleRows = 24;
112
+ if (key.downArrow) {
113
+ setPreviewScroll((s) => Math.min(s + 1, Math.max(0, bodyLines - visibleRows)));
114
+ return;
115
+ }
116
+ if (key.upArrow) {
117
+ setPreviewScroll((s) => Math.max(0, s - 1));
118
+ return;
119
+ }
120
+ if (key.pageDown || input === " ") {
121
+ setPreviewScroll((s) => Math.min(s + visibleRows, Math.max(0, bodyLines - visibleRows)));
122
+ return;
123
+ }
124
+ if (key.pageUp) {
125
+ setPreviewScroll((s) => Math.max(0, s - visibleRows));
126
+ return;
127
+ }
128
+ if (input === "g") {
129
+ setPreviewScroll(0);
130
+ return;
131
+ }
132
+ if (input === "G") {
133
+ setPreviewScroll(Math.max(0, bodyLines - visibleRows));
134
+ return;
135
+ }
136
+ return;
137
+ }
138
+ // Help
139
+ if (input === "?" && mode === "browse") {
140
+ setMode("help");
141
+ return;
142
+ }
143
+ // Dedupe view
144
+ if (input === "d" && mode === "browse") {
145
+ if (clusters === null)
146
+ setClusters(findDuplicates({ projectsRoot }).clusters);
147
+ setSelectedClusterIdx(0);
148
+ setMode("dedupe");
149
+ return;
150
+ }
151
+ // Lint view
152
+ if (input === "l" && mode === "browse") {
153
+ if (lintIssues === null)
154
+ setLintIssues(lintAll({ projectsRoot }).issues);
155
+ setSelectedIssueIdx(0);
156
+ setMode("lint");
157
+ return;
158
+ }
159
+ // Search trigger
160
+ if (input === "/" && mode === "browse") {
161
+ setMode("search");
162
+ setSearchQuery("");
163
+ return;
164
+ }
165
+ // Search mode keyboard
166
+ if (mode === "search") {
167
+ if (key.return) {
168
+ // Stay in search mode but freeze the query; user can navigate results.
169
+ return;
170
+ }
171
+ if (key.backspace || key.delete) {
172
+ setSearchQuery((q) => q.slice(0, -1));
173
+ return;
174
+ }
175
+ if (key.downArrow) {
176
+ setSelectedMemory((i) => Math.min(i + 1, Math.max(0, searchResults.length - 1)));
177
+ return;
178
+ }
179
+ if (key.upArrow) {
180
+ setSelectedMemory((i) => Math.max(0, i - 1));
181
+ return;
182
+ }
183
+ if (input && !key.ctrl && !key.meta) {
184
+ // Accept any length — terminals deliver char-by-char, but test
185
+ // harnesses (and paste events) deliver multi-char strings at once.
186
+ // We only filter out control sequences (ESC, arrows, etc.) which
187
+ // ink reports separately via the `key` object.
188
+ setSearchQuery((q) => q + input);
189
+ setSelectedMemory(0);
190
+ return;
191
+ }
192
+ return;
193
+ }
194
+ // Dedupe nav
195
+ if (mode === "dedupe") {
196
+ if (key.downArrow) {
197
+ setSelectedClusterIdx((i) => Math.min(i + 1, Math.max(0, (clusters?.length ?? 1) - 1)));
198
+ return;
199
+ }
200
+ if (key.upArrow) {
201
+ setSelectedClusterIdx((i) => Math.max(0, i - 1));
202
+ return;
203
+ }
204
+ return;
205
+ }
206
+ // Lint nav
207
+ if (mode === "lint") {
208
+ if (key.downArrow) {
209
+ setSelectedIssueIdx((i) => Math.min(i + 1, Math.max(0, (lintIssues?.length ?? 1) - 1)));
210
+ return;
211
+ }
212
+ if (key.upArrow) {
213
+ setSelectedIssueIdx((i) => Math.max(0, i - 1));
214
+ return;
215
+ }
216
+ return;
217
+ }
218
+ // Browse mode keys
219
+ if (mode === "browse") {
220
+ if (input === "a") {
221
+ setShowEmptyProjects((v) => !v);
222
+ return;
223
+ }
224
+ if (key.tab) {
225
+ setPane((p) => (p === 0 ? 1 : 0));
226
+ return;
227
+ }
228
+ if (key.downArrow) {
229
+ if (pane === 0) {
230
+ setSelectedProject((i) => Math.min(i + 1, Math.max(0, visibleProjects.length - 1)));
231
+ setSelectedMemory(0);
232
+ }
233
+ else {
234
+ const max = currentProject?.memories.length ?? 0;
235
+ setSelectedMemory((i) => Math.min(i + 1, Math.max(0, max - 1)));
236
+ }
237
+ return;
238
+ }
239
+ if (key.upArrow) {
240
+ if (pane === 0) {
241
+ setSelectedProject((i) => Math.max(0, i - 1));
242
+ setSelectedMemory(0);
243
+ }
244
+ else {
245
+ setSelectedMemory((i) => Math.max(0, i - 1));
246
+ }
247
+ return;
248
+ }
249
+ if (key.leftArrow) {
250
+ setPane(0);
251
+ return;
252
+ }
253
+ if (key.rightArrow) {
254
+ setPane(1);
255
+ return;
256
+ }
257
+ }
258
+ });
259
+ // ============================== rendering ===============================
260
+ if (mode === "help")
261
+ return _jsx(HelpScreen, {});
262
+ if (mode === "dedupe") {
263
+ return (_jsx(DedupeScreen, { clusters: clusters ?? [], selectedIdx: selectedClusterIdx }));
264
+ }
265
+ if (mode === "lint") {
266
+ return (_jsx(LintScreen, { issues: lintIssues ?? [], selectedIdx: selectedIssueIdx }));
267
+ }
268
+ if (mode === "preview" && currentMemory) {
269
+ return (_jsx(FullPreviewScreen, { memory: currentMemory, scroll: previewScroll, visibleRows: 24 }));
270
+ }
271
+ return (_jsxs(Box, { flexDirection: "column", height: 20, children: [_jsxs(Box, { flexGrow: 1, children: [_jsxs(Box, { width: "30%", flexDirection: "column", borderStyle: "round", borderColor: mode === "browse" && pane === 0 ? "cyan" : "gray", paddingX: 1, children: [_jsxs(Text, { bold: true, underline: true, children: ["Projects (", visibleProjects.length, showEmptyProjects ? "" : `/${projects.length}`, ")"] }), visibleProjects.length === 0 ? (_jsx(Text, { dimColor: true, children: showEmptyProjects ? "(no projects)" : "(no projects with memories — press 'a' to show all)" })) : (visibleProjects.slice(0, 14).map((p, i) => (_jsxs(Text, { wrap: "truncate-end", inverse: mode === "browse" && pane === 0 && i === selectedProject, children: [shortProjectLabel(p.slug), " (", p.memories.length, ")"] }, p.slug))))] }), _jsxs(Box, { width: "35%", flexDirection: "column", borderStyle: "round", borderColor: mode === "browse" && pane === 1 ? "cyan" : "gray", paddingX: 1, children: [_jsx(Text, { bold: true, underline: true, children: mode === "search" ? `Search: ${searchQuery || "(empty)"}` : "Memories" }), mode === "search" ? (searchResults.length === 0 ? (_jsx(Text, { dimColor: true, children: "(no matches)" })) : (searchResults.slice(0, 12).map((m, i) => (_jsxs(Text, { inverse: i === selectedMemory, children: ["[", m.type[0], "] ", truncate(m.fileName, 24)] }, m.id))))) : currentProject ? (currentProject.memories.length === 0 ? (_jsx(Text, { dimColor: true, children: "(no memories)" })) : (currentProject.memories.map((m, i) => (_jsxs(Text, { inverse: mode === "browse" && pane === 1 && i === selectedMemory, children: ["[", m.type[0], "] ", m.fileName] }, m.id))))) : null] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, flexGrow: 1, overflowX: "hidden", children: [_jsx(Text, { bold: true, underline: true, children: "Preview" }), currentMemory ? (_jsxs(_Fragment, { children: [_jsxs(Text, { wrap: "truncate-end", children: ["name: ", currentMemory.name ?? "(none)"] }), _jsxs(Text, { wrap: "truncate-end", children: ["type: ", currentMemory.type, " source: ", currentMemory.typeSource] }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: currentMemory.description ?? "(no description)" }), _jsx(Text, { children: "─".repeat(20) }), _jsx(BodyPreview, { body: currentMemory.body, maxLines: 16 })] })) : (_jsx(Text, { dimColor: true, children: "(nothing selected)" }))] })] }), _jsx(StatusBar, { mode: mode, searchQuery: searchQuery, projectsCount: projects.length, memoriesCount: allMems.length })] }));
272
+ }
273
+ function HelpScreen() {
274
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [_jsx(Text, { bold: true, children: "memex TUI \u2014 keybindings" }), _jsxs(Text, { children: [" ", "\u2191/\u2193 navigate within a pane"] }), _jsxs(Text, { children: [" ", "Tab / \u2190/\u2192 switch pane"] }), _jsxs(Text, { children: [" ", "Enter / v full-screen preview (scrollable)"] }), _jsxs(Text, { children: [" ", "o open selected memory in $EDITOR"] }), _jsxs(Text, { children: [" ", "/ search across all memories"] }), _jsxs(Text, { children: [" ", "d dedupe view (find duplicate clusters)"] }), _jsxs(Text, { children: [" ", "l lint view (structural issues)"] }), _jsxs(Text, { children: [" ", "a toggle showing empty-memory projects"] }), _jsxs(Text, { children: [" ", "? this help"] }), _jsxs(Text, { children: [" ", "Esc back to browse"] }), _jsxs(Text, { children: [" ", "q quit"] }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Inside full preview: \u2191/\u2193 PgUp/PgDn g/G to scroll, o to edit." }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Mutating actions (merge, promote, undo) are CLI-only by design." }), _jsx(Text, { dimColor: true, children: "Esc to return." })] }));
275
+ }
276
+ function DedupeScreen({ clusters, selectedIdx }) {
277
+ const current = clusters[selectedIdx];
278
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [_jsxs(Text, { bold: true, children: ["Duplicate clusters (", clusters.length, ")"] }), clusters.length === 0 ? (_jsx(Text, { dimColor: true, children: "(no duplicates found)" })) : (clusters.slice(0, 12).map((c, i) => (_jsxs(Text, { inverse: i === selectedIdx, children: [c.id, " type=", c.type, " count=", c.count, " distinctProjects=", c.distinctProjects, c.promotionCandidate ? " [promote candidate]" : "", c.intraProject ? " [intra]" : ""] }, c.id))))] }), current && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, marginTop: 1, children: [_jsxs(Text, { bold: true, children: [current.id, " members"] }), current.members.map((m) => (_jsxs(Text, { children: [m.id === current.representative.id ? "★ " : " ", m.id] }, m.id)))] })), _jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \u00B7 Esc back \u00B7 q quit" })] }));
279
+ }
280
+ function FullPreviewScreen({ memory, scroll, visibleRows, }) {
281
+ const lines = memory.body.split("\n");
282
+ const total = lines.length;
283
+ const slice = lines.slice(scroll, scroll + visibleRows);
284
+ const atEnd = scroll + visibleRows >= total;
285
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [_jsx(Text, { bold: true, wrap: "truncate-end", children: memory.id }), _jsxs(Text, { wrap: "truncate-end", children: [_jsxs(Text, { children: ["type: ", memory.type, " "] }), memory.name && _jsxs(Text, { children: ["name: ", memory.name, " "] })] }), memory.description && _jsx(Text, { dimColor: true, wrap: "truncate-end", children: memory.description })] }), _jsx(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: slice.length === 0 ? (_jsx(Text, { dimColor: true, children: "(empty body)" })) : (slice.map((line, i) => (_jsx(Text, { wrap: "truncate-end", children: line.length === 0 ? " " : line }, scroll + i)))) }), _jsxs(Text, { dimColor: true, children: [`lines ${scroll + 1}–${Math.min(scroll + visibleRows, total)} of ${total}`, atEnd ? " (end)" : "", " ", "\u2191/\u2193 scroll \u00B7 PgUp/PgDn page \u00B7 g/G top/bottom \u00B7 o open in $EDITOR \u00B7 Esc back \u00B7 q quit"] })] }));
286
+ }
287
+ function LintScreen({ issues, selectedIdx }) {
288
+ const current = issues[selectedIdx];
289
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [_jsxs(Text, { bold: true, children: ["Lint issues (", issues.length, ")"] }), issues.length === 0 ? (_jsx(Text, { dimColor: true, children: "(no issues found)" })) : (issues.slice(0, 12).map((issue, i) => (_jsxs(Text, { inverse: i === selectedIdx, children: ["[", issue.severity, "] ", issue.code, " ", truncate(issue.projectSlug, 40)] }, `${issue.projectSlug}-${issue.code}-${i}`))))] }), current && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, marginTop: 1, children: [_jsxs(Text, { bold: true, children: [current.code, " (", current.severity, ")"] }), _jsx(Text, { children: current.message }), current.hint && _jsxs(Text, { dimColor: true, children: ["hint: ", current.hint] })] })), _jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \u00B7 Esc back \u00B7 q quit" })] }));
290
+ }
291
+ function StatusBar({ mode, searchQuery, projectsCount, memoriesCount, }) {
292
+ const keys = mode === "search"
293
+ ? "type to search · ↑/↓ navigate · v preview · o edit · Esc back"
294
+ : mode === "browse"
295
+ ? "Tab pane · ↑/↓ nav · Enter preview · o edit · / search · d dedupe · l lint · ? help · q quit"
296
+ : "Esc back · q quit";
297
+ return (_jsx(Box, { paddingX: 1, children: _jsxs(Text, { dimColor: true, children: [projectsCount, " projects \u00B7 ", memoriesCount, " memories", mode === "search" && searchQuery ? ` · search="${searchQuery}"` : "", " ", keys] }) }));
298
+ }
299
+ function truncate(s, max) {
300
+ if (s.length <= max)
301
+ return s;
302
+ return s.slice(0, max - 1) + "…";
303
+ }
304
+ /**
305
+ * Shorten a project slug for display. The harness encodes the project's
306
+ * absolute path with `/` → `-`, so `-Users-husseinmoussa-Desktop-Hussein-vida`
307
+ * is really `/Users/husseinmoussa/Desktop/Hussein/vida`. Show only the last
308
+ * two path components so each row is readable.
309
+ *
310
+ * Worktree slugs (`<base>--claude-worktrees-<branch>`) get a "(wt)" tag.
311
+ */
312
+ function shortProjectLabel(slug) {
313
+ const wtMatch = slug.match(/^(.*?)--claude-worktrees-(.+)$/);
314
+ const base = wtMatch ? wtMatch[1] : slug;
315
+ const wtSuffix = wtMatch ? ` (wt:${wtMatch[2]})` : "";
316
+ const parts = base.split("-").filter(Boolean);
317
+ if (parts.length <= 2)
318
+ return slug + wtSuffix;
319
+ const tail = parts.slice(-2).join("/");
320
+ return `…/${tail}${wtSuffix}`;
321
+ }
322
+ // Render up to `maxLines` lines of body, each clipped to pane width by Ink's
323
+ // `wrap="truncate-end"`. Shows a "+N more lines" footer when truncated.
324
+ // Without this, multi-thousand-line memories (e.g. an ARCHITECTURE.md doc)
325
+ // overflow the pane horizontally because Ink's default wrap doesn't clip
326
+ // individual code-block lines well inside a flex child.
327
+ function BodyPreview({ body, maxLines }) {
328
+ const lines = body.split("\n");
329
+ const shown = lines.slice(0, maxLines);
330
+ const remaining = lines.length - shown.length;
331
+ return (_jsxs(_Fragment, { children: [shown.map((line, i) => (_jsx(Text, { wrap: "truncate-end", children: line.length === 0 ? " " : line }, i))), remaining > 0 && (_jsxs(Text, { dimColor: true, children: ["… ", remaining, " more line", remaining === 1 ? "" : "s", " (open the file to see all)"] }))] }));
332
+ }
333
+ //# sourceMappingURL=App.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"App.js","sourceRoot":"","sources":["../../../src/cli/tui/App.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type Plan } from "./plan.js";
2
+ import { type JournalEntry, type JournalOptions } from "./journal.js";
3
+ export interface ApplyOptions extends JournalOptions {
4
+ /** When true, no disk writes; returns a synthetic entry for inspection. */
5
+ dryRun?: boolean;
6
+ /** Sink for human-readable progress lines. Defaults to no-op. */
7
+ onProgress?: (msg: string) => void;
8
+ }
9
+ export declare function applyPlan(plan: Plan, opts?: ApplyOptions): JournalEntry;
10
+ /**
11
+ * Undo a journal entry: execute the inverses, in reverse order, of every op
12
+ * that recorded `result: "success"`. Failed ops are skipped (nothing to undo).
13
+ *
14
+ * Writes a new journal entry whose `undoOf` points at the original id, so
15
+ * `memex undo` again would walk *forward* (redo).
16
+ */
17
+ export declare function undoPlan(entryId: string | "latest", opts?: ApplyOptions): {
18
+ undone: JournalEntry | null;
19
+ newEntry: JournalEntry | null;
20
+ };
21
+ /**
22
+ * Best-effort cleanup of leftover `.memex-tmp` files. We can call this from
23
+ * `memex doctor` once Phase 6 ships actual mutating commands.
24
+ */
25
+ export declare function cleanupTempFiles(rootDir: string): {
26
+ removed: number;
27
+ };
@@ -0,0 +1,191 @@
1
+ // `applyPlan` — the only function in memex that mutates the filesystem.
2
+ //
3
+ // Two execution modes:
4
+ // dryRun=true prints what would happen, writes nothing
5
+ // dryRun=false captures the inverse from current disk state, executes each
6
+ // op, journals the result, returns the journal entry
7
+ //
8
+ // Safety properties:
9
+ // - writes are atomic (write to `.path.memex-tmp`, rename onto target)
10
+ // - inverses are captured *before* the op runs, while the file is still in
11
+ // its original state
12
+ // - journal is written *after* execution (success or failure) so an
13
+ // interrupted run leaves a recoverable trail on disk
14
+ // - inverses for "create" operations are "delete" — but we only delete the
15
+ // path if it was created by this plan (recorded by `inverse.kind`)
16
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
17
+ import { dirname } from "node:path";
18
+ import { describePlan, planBuilder } from "./plan.js";
19
+ import { ensureJournalDir, latestJournalEntry, readJournalEntry, writeJournalEntry, } from "./journal.js";
20
+ /** Sentinel marker on temp files. */
21
+ const TMP_SUFFIX = ".memex-tmp";
22
+ function captureInverse(op) {
23
+ switch (op.kind) {
24
+ case "write": {
25
+ // If the file exists, inverse = write(oldContent). Otherwise inverse = delete.
26
+ if (existsSync(op.path) && statSync(op.path).isFile()) {
27
+ const prev = readFileSync(op.path, "utf8");
28
+ return { kind: "write", path: op.path, content: prev };
29
+ }
30
+ return { kind: "delete", path: op.path };
31
+ }
32
+ case "delete": {
33
+ if (!existsSync(op.path)) {
34
+ // Inverse of "delete a file that wasn't there" is "do nothing" —
35
+ // model as ensure-dir on the file's parent (no-op).
36
+ return { kind: "ensure-dir", path: dirname(op.path) };
37
+ }
38
+ const prev = readFileSync(op.path, "utf8");
39
+ return { kind: "write", path: op.path, content: prev };
40
+ }
41
+ case "ensure-dir": {
42
+ // If the dir already exists, no-op inverse. If we'd create it, the
43
+ // inverse should remove it — but only if it's empty after we undo all
44
+ // other ops. We encode this as an "ensure-dir" with the parent path,
45
+ // which is a no-op on undo. (Removing dirs on undo is dangerous —
46
+ // we don't do it in v0.1.)
47
+ return { kind: "ensure-dir", path: dirname(op.path) };
48
+ }
49
+ }
50
+ }
51
+ function executeOp(op) {
52
+ switch (op.kind) {
53
+ case "ensure-dir":
54
+ mkdirSync(op.path, { recursive: true });
55
+ return;
56
+ case "delete":
57
+ if (existsSync(op.path))
58
+ unlinkSync(op.path);
59
+ return;
60
+ case "write": {
61
+ mkdirSync(dirname(op.path), { recursive: true });
62
+ const tmp = op.path + TMP_SUFFIX;
63
+ writeFileSync(tmp, op.content);
64
+ renameSync(tmp, op.path);
65
+ return;
66
+ }
67
+ }
68
+ }
69
+ export function applyPlan(plan, opts = {}) {
70
+ const onProgress = opts.onProgress ?? (() => { });
71
+ const startedAt = new Date().toISOString();
72
+ if (opts.dryRun) {
73
+ onProgress(`DRY RUN — would execute:\n${describePlan(plan)}`);
74
+ return {
75
+ plan,
76
+ status: "complete",
77
+ startedAt,
78
+ finishedAt: startedAt,
79
+ ops: plan.ops.map((op) => ({
80
+ op,
81
+ inverse: captureInverse(op),
82
+ appliedAt: startedAt,
83
+ result: "skipped",
84
+ })),
85
+ };
86
+ }
87
+ // Real run. Make sure the journal directory exists before any mutation so
88
+ // we can log even the first op's outcome.
89
+ ensureJournalDir(opts);
90
+ const appliedOps = [];
91
+ let allOk = true;
92
+ for (const op of plan.ops) {
93
+ const inverse = captureInverse(op);
94
+ const appliedAt = new Date().toISOString();
95
+ try {
96
+ executeOp(op);
97
+ appliedOps.push({ op, inverse, appliedAt, result: "success" });
98
+ onProgress(`✓ ${op.kind} ${"path" in op ? op.path : ""}`);
99
+ }
100
+ catch (err) {
101
+ const error = err instanceof Error ? err.message : String(err);
102
+ appliedOps.push({ op, inverse, appliedAt, result: "failure", error });
103
+ onProgress(`✗ ${op.kind} ${"path" in op ? op.path : ""} — ${error}`);
104
+ allOk = false;
105
+ break; // halt on first failure; undo can roll back what succeeded
106
+ }
107
+ }
108
+ const entry = {
109
+ plan,
110
+ status: allOk ? "complete" : appliedOps.some((a) => a.result === "success") ? "partial" : "failed",
111
+ startedAt,
112
+ finishedAt: new Date().toISOString(),
113
+ ops: appliedOps,
114
+ };
115
+ writeJournalEntry(entry, opts);
116
+ return entry;
117
+ }
118
+ /**
119
+ * Undo a journal entry: execute the inverses, in reverse order, of every op
120
+ * that recorded `result: "success"`. Failed ops are skipped (nothing to undo).
121
+ *
122
+ * Writes a new journal entry whose `undoOf` points at the original id, so
123
+ * `memex undo` again would walk *forward* (redo).
124
+ */
125
+ export function undoPlan(entryId, opts = {}) {
126
+ const original = entryId === "latest" ? latestJournalEntry(opts) : readJournalEntry(entryId, opts);
127
+ if (!original)
128
+ return { undone: null, newEntry: null };
129
+ const successful = original.ops.filter((a) => a.result === "success").reverse();
130
+ if (successful.length === 0) {
131
+ return { undone: original, newEntry: null };
132
+ }
133
+ const builder = planBuilder(`undo:${original.plan.label}`, `Undo of plan ${original.plan.id} (${original.plan.label})`);
134
+ for (const a of successful) {
135
+ const inv = a.inverse;
136
+ if (inv.kind === "write")
137
+ builder.write(inv.path, inv.content);
138
+ else if (inv.kind === "delete")
139
+ builder.delete(inv.path);
140
+ else if (inv.kind === "ensure-dir")
141
+ builder.ensureDir(inv.path);
142
+ }
143
+ const plan = builder.build();
144
+ const newEntry = applyPlan(plan, opts);
145
+ newEntry.undoOf = original.plan.id;
146
+ // Rewrite to include the undoOf marker.
147
+ writeJournalEntry(newEntry, opts);
148
+ return { undone: original, newEntry };
149
+ }
150
+ /**
151
+ * Best-effort cleanup of leftover `.memex-tmp` files. We can call this from
152
+ * `memex doctor` once Phase 6 ships actual mutating commands.
153
+ */
154
+ export function cleanupTempFiles(rootDir) {
155
+ let removed = 0;
156
+ const stack = [rootDir];
157
+ while (stack.length > 0) {
158
+ const dir = stack.pop();
159
+ let entries;
160
+ try {
161
+ entries = readdirSync(dir);
162
+ }
163
+ catch {
164
+ continue;
165
+ }
166
+ for (const name of entries) {
167
+ const full = `${dir}/${name}`;
168
+ let s;
169
+ try {
170
+ s = statSync(full);
171
+ }
172
+ catch {
173
+ continue;
174
+ }
175
+ if (s.isDirectory()) {
176
+ stack.push(full);
177
+ }
178
+ else if (s.isFile() && name.endsWith(TMP_SUFFIX)) {
179
+ try {
180
+ rmSync(full);
181
+ removed++;
182
+ }
183
+ catch {
184
+ // ignore
185
+ }
186
+ }
187
+ }
188
+ }
189
+ return { removed };
190
+ }
191
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export declare function defaultClaudeMdPath(): string;
2
+ /** Normalize an arbitrary string into a safe block slug. */
3
+ export declare function toBlockSlug(name: string): string;
4
+ export interface PromotedBlock {
5
+ slug: string;
6
+ heading: string;
7
+ body: string;
8
+ }
9
+ export declare function renderBlock(block: PromotedBlock): string;
10
+ /**
11
+ * Upsert a managed block into a CLAUDE.md document.
12
+ *
13
+ * - If a block with the same slug exists, replace it in place.
14
+ * - Otherwise append after ensuring the header banner is present.
15
+ * - Returns the new content (caller decides what to do with it).
16
+ */
17
+ export declare function upsertBlock(currentContent: string, block: PromotedBlock): string;
18
+ /**
19
+ * Remove a managed block by slug. Used by undo/promote-revert. Leaves
20
+ * unmanaged content alone. Returns { content, modified }.
21
+ */
22
+ export declare function removeBlock(currentContent: string, slug: string): {
23
+ content: string;
24
+ modified: boolean;
25
+ };
26
+ /** List the slugs of memex-managed blocks currently in a document. */
27
+ export declare function listBlockSlugs(currentContent: string): string[];