@bubstack/moe-memory 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 (157) hide show
  1. package/.mcp.json +18 -0
  2. package/README.md +47 -0
  3. package/agents/search-conversations.md +171 -0
  4. package/dist/LICENSE +25 -0
  5. package/dist/cli.d.ts +25 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +125 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/codex-hook-trust.d.ts +4 -0
  10. package/dist/codex-hook-trust.d.ts.map +1 -0
  11. package/dist/codex-hook-trust.js +114 -0
  12. package/dist/codex-hook-trust.js.map +1 -0
  13. package/dist/codex-support.d.ts +6 -0
  14. package/dist/codex-support.d.ts.map +1 -0
  15. package/dist/codex-support.js +29 -0
  16. package/dist/codex-support.js.map +1 -0
  17. package/dist/constants.d.ts +14 -0
  18. package/dist/constants.d.ts.map +1 -0
  19. package/dist/constants.js +14 -0
  20. package/dist/constants.js.map +1 -0
  21. package/dist/db.d.ts +103 -0
  22. package/dist/db.d.ts.map +1 -0
  23. package/dist/db.js +430 -0
  24. package/dist/db.js.map +1 -0
  25. package/dist/doctor-cli.d.ts +3 -0
  26. package/dist/doctor-cli.d.ts.map +1 -0
  27. package/dist/doctor-cli.js +43 -0
  28. package/dist/doctor-cli.js.map +1 -0
  29. package/dist/doctor.d.ts +17 -0
  30. package/dist/doctor.d.ts.map +1 -0
  31. package/dist/doctor.js +98 -0
  32. package/dist/doctor.js.map +1 -0
  33. package/dist/embedding-migration.d.ts +73 -0
  34. package/dist/embedding-migration.d.ts.map +1 -0
  35. package/dist/embedding-migration.js +120 -0
  36. package/dist/embedding-migration.js.map +1 -0
  37. package/dist/embeddings.d.ts +78 -0
  38. package/dist/embeddings.d.ts.map +1 -0
  39. package/dist/embeddings.js +180 -0
  40. package/dist/embeddings.js.map +1 -0
  41. package/dist/file-lock.d.ts +39 -0
  42. package/dist/file-lock.d.ts.map +1 -0
  43. package/dist/file-lock.js +91 -0
  44. package/dist/file-lock.js.map +1 -0
  45. package/dist/index-cli.d.ts +10 -0
  46. package/dist/index-cli.d.ts.map +1 -0
  47. package/dist/index-cli.js +195 -0
  48. package/dist/index-cli.js.map +1 -0
  49. package/dist/index.d.ts +12 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +19 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/indexer.d.ts +4 -0
  54. package/dist/indexer.d.ts.map +1 -0
  55. package/dist/indexer.js +318 -0
  56. package/dist/indexer.js.map +1 -0
  57. package/dist/install-check.d.ts +48 -0
  58. package/dist/install-check.d.ts.map +1 -0
  59. package/dist/install-check.js +82 -0
  60. package/dist/install-check.js.map +1 -0
  61. package/dist/journal/index.d.ts +5 -0
  62. package/dist/journal/index.d.ts.map +1 -0
  63. package/dist/journal/index.js +5 -0
  64. package/dist/journal/index.js.map +1 -0
  65. package/dist/journal/legacy-sidecars.d.ts +74 -0
  66. package/dist/journal/legacy-sidecars.d.ts.map +1 -0
  67. package/dist/journal/legacy-sidecars.js +151 -0
  68. package/dist/journal/legacy-sidecars.js.map +1 -0
  69. package/dist/journal/markdown.d.ts +91 -0
  70. package/dist/journal/markdown.d.ts.map +1 -0
  71. package/dist/journal/markdown.js +234 -0
  72. package/dist/journal/markdown.js.map +1 -0
  73. package/dist/journal/search.d.ts +91 -0
  74. package/dist/journal/search.d.ts.map +1 -0
  75. package/dist/journal/search.js +203 -0
  76. package/dist/journal/search.js.map +1 -0
  77. package/dist/journal/store.d.ts +96 -0
  78. package/dist/journal/store.d.ts.map +1 -0
  79. package/dist/journal/store.js +270 -0
  80. package/dist/journal/store.js.map +1 -0
  81. package/dist/journal-cli.d.ts +19 -0
  82. package/dist/journal-cli.d.ts.map +1 -0
  83. package/dist/journal-cli.js +153 -0
  84. package/dist/journal-cli.js.map +1 -0
  85. package/dist/logging.d.ts +6 -0
  86. package/dist/logging.d.ts.map +1 -0
  87. package/dist/logging.js +20 -0
  88. package/dist/logging.js.map +1 -0
  89. package/dist/mcp-server.d.ts +34 -0
  90. package/dist/mcp-server.d.ts.map +1 -0
  91. package/dist/mcp-server.js +607 -0
  92. package/dist/mcp-server.js.map +1 -0
  93. package/dist/parser.d.ts +11 -0
  94. package/dist/parser.d.ts.map +1 -0
  95. package/dist/parser.js +445 -0
  96. package/dist/parser.js.map +1 -0
  97. package/dist/paths.d.ts +103 -0
  98. package/dist/paths.d.ts.map +1 -0
  99. package/dist/paths.js +258 -0
  100. package/dist/paths.js.map +1 -0
  101. package/dist/search-cli.d.ts +3 -0
  102. package/dist/search-cli.d.ts.map +1 -0
  103. package/dist/search-cli.js +138 -0
  104. package/dist/search-cli.js.map +1 -0
  105. package/dist/search.d.ts +36 -0
  106. package/dist/search.d.ts.map +1 -0
  107. package/dist/search.js +371 -0
  108. package/dist/search.js.map +1 -0
  109. package/dist/show-cli.d.ts +3 -0
  110. package/dist/show-cli.d.ts.map +1 -0
  111. package/dist/show-cli.js +60 -0
  112. package/dist/show-cli.js.map +1 -0
  113. package/dist/show.d.ts +3 -0
  114. package/dist/show.d.ts.map +1 -0
  115. package/dist/show.js +984 -0
  116. package/dist/show.js.map +1 -0
  117. package/dist/stats-cli.d.ts +3 -0
  118. package/dist/stats-cli.d.ts.map +1 -0
  119. package/dist/stats-cli.js +51 -0
  120. package/dist/stats-cli.js.map +1 -0
  121. package/dist/stats.d.ts +19 -0
  122. package/dist/stats.d.ts.map +1 -0
  123. package/dist/stats.js +116 -0
  124. package/dist/stats.js.map +1 -0
  125. package/dist/summarizer.d.ts +83 -0
  126. package/dist/summarizer.d.ts.map +1 -0
  127. package/dist/summarizer.js +526 -0
  128. package/dist/summarizer.js.map +1 -0
  129. package/dist/summary-sentinel.d.ts +31 -0
  130. package/dist/summary-sentinel.d.ts.map +1 -0
  131. package/dist/summary-sentinel.js +80 -0
  132. package/dist/summary-sentinel.js.map +1 -0
  133. package/dist/sync-cli.d.ts +15 -0
  134. package/dist/sync-cli.d.ts.map +1 -0
  135. package/dist/sync-cli.js +202 -0
  136. package/dist/sync-cli.js.map +1 -0
  137. package/dist/sync.d.ts +35 -0
  138. package/dist/sync.d.ts.map +1 -0
  139. package/dist/sync.js +204 -0
  140. package/dist/sync.js.map +1 -0
  141. package/dist/types.d.ts +125 -0
  142. package/dist/types.d.ts.map +1 -0
  143. package/dist/types.js +32 -0
  144. package/dist/types.js.map +1 -0
  145. package/dist/verify.d.ts +30 -0
  146. package/dist/verify.d.ts.map +1 -0
  147. package/dist/verify.js +174 -0
  148. package/dist/verify.js.map +1 -0
  149. package/dist/version.d.ts +13 -0
  150. package/dist/version.d.ts.map +1 -0
  151. package/dist/version.js +13 -0
  152. package/dist/version.js.map +1 -0
  153. package/hooks/hooks.json +15 -0
  154. package/package.json +71 -0
  155. package/prompts/search-agent.md +160 -0
  156. package/skills/remembering-conversations/MCP-TOOLS.md +147 -0
  157. package/skills/remembering-conversations/SKILL.md +97 -0
package/dist/types.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The two record types.
3
+ *
4
+ * A **conversation exchange** is harvested: sync copies a transcript out of
5
+ * `~/.claude/projects` or `~/.codex/sessions` and the indexer derives rows from
6
+ * it. Nobody chose to write it down.
7
+ *
8
+ * A **journal entry** is deliberate: the model called `process_thoughts` and a
9
+ * markdown file was written. It is authored content with different privacy
10
+ * properties — a project entry belongs to the codebase, a user entry belongs to
11
+ * the person.
12
+ *
13
+ * They share one encoder and one SQLite file and nothing else. Distinct tables,
14
+ * distinct MCP tools, distinct result types. This file is where that boundary
15
+ * is stated.
16
+ *
17
+ * Reconciliation note: private-journal-mcp's own `types.ts` was entirely dead —
18
+ * `JournalEntry`, `ServerConfig` and `ProcessThoughtsRequest` had zero importers
19
+ * anywhere in its src or tests, while its live journal shape was retyped inline
20
+ * in four places. The names below are re-established as the single declaration
21
+ * those four sites now share.
22
+ */
23
+ /** The rendered `## Heading` for each thought category, in entry order. */
24
+ export const JOURNAL_SECTION_HEADINGS = [
25
+ ["reflections", "Reflections"],
26
+ ["observations", "Observations"],
27
+ ["project_notes", "Project Notes"],
28
+ ["user_context", "User Context"],
29
+ ["technical_insights", "Technical Insights"],
30
+ ["world_knowledge", "World Knowledge"],
31
+ ];
32
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA4FH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,wBAAwB,GAAmD;IACtF,CAAC,aAAa,EAAE,aAAa,CAAC;IAC9B,CAAC,cAAc,EAAE,cAAc,CAAC;IAChC,CAAC,eAAe,EAAE,eAAe,CAAC;IAClC,CAAC,cAAc,EAAE,cAAc,CAAC;IAChC,CAAC,oBAAoB,EAAE,oBAAoB,CAAC;IAC5C,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;CACvC,CAAC"}
@@ -0,0 +1,30 @@
1
+ export interface VerificationResult {
2
+ missing: Array<{
3
+ path: string;
4
+ reason: string;
5
+ }>;
6
+ orphaned: Array<{
7
+ uuid: string;
8
+ path: string;
9
+ }>;
10
+ outdated: Array<{
11
+ path: string;
12
+ fileTime: number;
13
+ dbTime: number;
14
+ }>;
15
+ corrupted: Array<{
16
+ path: string;
17
+ error: string;
18
+ }>;
19
+ }
20
+ export declare function verifyIndex(): Promise<VerificationResult>;
21
+ export interface RepairOptions {
22
+ /**
23
+ * Skip AI summary generation. Mirrors `moe-memory index --no-summaries`, which
24
+ * every other indexing entry point already had; `repair` did not, so its only
25
+ * code path required live Claude auth.
26
+ */
27
+ noSummaries?: boolean | undefined;
28
+ }
29
+ export declare function repairIndex(issues: VerificationResult, options?: RepairOptions): Promise<void>;
30
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpE,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,kBAAkB,CAAC,CA2G/D;AAED,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACnC;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,kBAAkB,EAC1B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA6Ff"}
package/dist/verify.js ADDED
@@ -0,0 +1,174 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { getAllExchanges, getFileLastIndexed, initDatabase } from "./db.js";
4
+ import { parseConversation } from "./parser.js";
5
+ import { findJsonlFiles, getArchiveDir, getExcludedProjects } from "./paths.js";
6
+ import { isErroredSentinel } from "./summary-sentinel.js";
7
+ export async function verifyIndex() {
8
+ const result = {
9
+ missing: [],
10
+ orphaned: [],
11
+ outdated: [],
12
+ corrupted: [],
13
+ };
14
+ const archiveDir = getArchiveDir();
15
+ // Track all files we find
16
+ const foundFiles = new Set();
17
+ // Find all conversation files
18
+ if (!fs.existsSync(archiveDir)) {
19
+ return result;
20
+ }
21
+ // Initialize database once for all checks
22
+ const db = initDatabase();
23
+ const projects = fs.readdirSync(archiveDir);
24
+ const excludedProjects = getExcludedProjects();
25
+ const excludedDirSet = new Set(excludedProjects);
26
+ let totalChecked = 0;
27
+ for (const project of projects) {
28
+ if (excludedProjects.includes(project)) {
29
+ console.log(`\nSkipping excluded project: ${project}`);
30
+ continue;
31
+ }
32
+ const projectPath = path.join(archiveDir, project);
33
+ const stat = fs.statSync(projectPath);
34
+ if (!stat.isDirectory())
35
+ continue;
36
+ const files = findJsonlFiles(projectPath, excludedDirSet);
37
+ for (const file of files) {
38
+ totalChecked++;
39
+ if (totalChecked % 100 === 0) {
40
+ console.log(` Checked ${totalChecked} conversations...`);
41
+ }
42
+ const conversationPath = path.join(projectPath, file);
43
+ foundFiles.add(conversationPath);
44
+ const summaryPath = conversationPath.replace(".jsonl", "-summary.txt");
45
+ // Check for missing or errored summary. An error sentinel (#96) means a
46
+ // previous summarization failed — verify treats it as "missing" so repair
47
+ // re-attempts it rather than reporting the conversation as healthy.
48
+ if (!fs.existsSync(summaryPath)) {
49
+ result.missing.push({ path: conversationPath, reason: "No summary file" });
50
+ continue;
51
+ }
52
+ if (isErroredSentinel(fs.readFileSync(summaryPath, "utf-8"))) {
53
+ result.missing.push({
54
+ path: conversationPath,
55
+ reason: "Previous summarization failed (error sentinel)",
56
+ });
57
+ continue;
58
+ }
59
+ // Check if file is outdated (modified after last_indexed)
60
+ const lastIndexed = getFileLastIndexed(db, conversationPath);
61
+ if (lastIndexed !== null) {
62
+ const fileStat = fs.statSync(conversationPath);
63
+ if (fileStat.mtimeMs > lastIndexed) {
64
+ result.outdated.push({
65
+ path: conversationPath,
66
+ fileTime: fileStat.mtimeMs,
67
+ dbTime: lastIndexed,
68
+ });
69
+ }
70
+ }
71
+ // Try parsing to detect corruption
72
+ try {
73
+ await parseConversation(conversationPath, project, conversationPath);
74
+ }
75
+ catch (error) {
76
+ result.corrupted.push({
77
+ path: conversationPath,
78
+ error: error instanceof Error ? error.message : String(error),
79
+ });
80
+ }
81
+ }
82
+ }
83
+ console.log(`Verified ${totalChecked} conversations.`);
84
+ // Check for orphaned database entries
85
+ const dbExchanges = getAllExchanges(db);
86
+ db.close();
87
+ for (const exchange of dbExchanges) {
88
+ if (!foundFiles.has(exchange.archivePath)) {
89
+ result.orphaned.push({
90
+ uuid: exchange.id,
91
+ path: exchange.archivePath,
92
+ });
93
+ }
94
+ }
95
+ return result;
96
+ }
97
+ export async function repairIndex(issues, options = {}) {
98
+ console.log("Repairing index...");
99
+ // To avoid circular dependencies, we import the indexer functions dynamically
100
+ const { initDatabase, insertExchange, deleteExchange } = await import("./db.js");
101
+ const { parseConversation } = await import("./parser.js");
102
+ const { initEmbeddings, generateExchangeEmbedding } = await import("./embeddings.js");
103
+ const { summarizeConversation } = await import("./summarizer.js");
104
+ const { formatErrorSentinel } = await import("./summary-sentinel.js");
105
+ const db = initDatabase();
106
+ await initEmbeddings();
107
+ // Remove orphaned entries first
108
+ for (const orphan of issues.orphaned) {
109
+ console.log(`Removing orphaned entry: ${orphan.uuid}`);
110
+ deleteExchange(db, orphan.uuid);
111
+ }
112
+ // Re-index missing and outdated conversations
113
+ const toReindex = [...issues.missing.map((m) => m.path), ...issues.outdated.map((o) => o.path)];
114
+ for (const conversationPath of toReindex) {
115
+ console.log(`Re-indexing: ${conversationPath}`);
116
+ try {
117
+ // Extract project name from path
118
+ const archiveDir = getArchiveDir();
119
+ const relativePath = conversationPath.replace(archiveDir + path.sep, "");
120
+ const project = relativePath.split(path.sep)[0] ?? "unknown";
121
+ // Parse conversation
122
+ const exchanges = await parseConversation(conversationPath, project, conversationPath);
123
+ if (exchanges.length === 0) {
124
+ console.log(` Skipped (no exchanges)`);
125
+ continue;
126
+ }
127
+ // Generate/update summary.
128
+ //
129
+ // A summarizer failure no longer aborts the re-index. Upstream this whole
130
+ // block was one try/catch, so a transient API error meant the exchanges
131
+ // were never indexed either — which made repair the one indexing path that
132
+ // could not run without live Claude auth. It now writes the same error
133
+ // sentinel the indexer and sync write (#96) and carries on.
134
+ const summaryPath = conversationPath.replace(".jsonl", "-summary.txt");
135
+ if (options.noSummaries) {
136
+ console.log(" Skipping summary (--no-summaries)");
137
+ }
138
+ else {
139
+ try {
140
+ const summary = await summarizeConversation(exchanges);
141
+ fs.writeFileSync(summaryPath, summary, "utf-8");
142
+ console.log(` Created summary: ${summary.split(/\s+/).length} words`);
143
+ }
144
+ catch (error) {
145
+ try {
146
+ fs.writeFileSync(summaryPath, formatErrorSentinel(error), "utf-8");
147
+ }
148
+ catch { }
149
+ console.log(` Summary failed, continuing with index: ${error instanceof Error ? error.message : String(error)}`);
150
+ }
151
+ }
152
+ // Index exchanges
153
+ for (const exchange of exchanges) {
154
+ const toolNames = exchange.toolCalls?.map((tc) => tc.toolName);
155
+ const embedding = await generateExchangeEmbedding(exchange.userMessage, exchange.assistantMessage, toolNames);
156
+ insertExchange(db, exchange, embedding, toolNames);
157
+ }
158
+ console.log(` Indexed ${exchanges.length} exchanges`);
159
+ }
160
+ catch (error) {
161
+ console.error(`Failed to re-index ${conversationPath}:`, error);
162
+ }
163
+ }
164
+ db.close();
165
+ // Report corrupted files (manual intervention needed)
166
+ if (issues.corrupted.length > 0) {
167
+ console.log("\n⚠️ Corrupted files (manual review needed):");
168
+ for (const c of issues.corrupted) {
169
+ console.log(` ${c.path}: ${c.error}`);
170
+ }
171
+ }
172
+ console.log("✅ Repair complete.");
173
+ }
174
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The package version, reported to MCP clients and to `moe-memory --version`.
3
+ *
4
+ * Upstream this file was GENERATED by `scripts/generate-version.js`, wired in
5
+ * through npm's `prebuild` and `pretest` lifecycle hooks, and gitignored — so it
6
+ * was absent from the pinned snapshot and a fresh checkout could neither
7
+ * typecheck nor test until the generator had run. Under turbo and `tsc -b` there
8
+ * is no npm lifecycle hook to hang a generator on, so it is a checked-in
9
+ * constant instead. `test/version-consistency.test.ts` asserts it equals
10
+ * package.json, which is the invariant the generator existed to guarantee.
11
+ */
12
+ export declare const VERSION = "0.1.0";
13
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,OAAO,UAAU,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The package version, reported to MCP clients and to `moe-memory --version`.
3
+ *
4
+ * Upstream this file was GENERATED by `scripts/generate-version.js`, wired in
5
+ * through npm's `prebuild` and `pretest` lifecycle hooks, and gitignored — so it
6
+ * was absent from the pinned snapshot and a fresh checkout could neither
7
+ * typecheck nor test until the generator had run. Under turbo and `tsc -b` there
8
+ * is no npm lifecycle hook to hang a generator on, so it is a checked-in
9
+ * constant instead. `test/version-consistency.test.ts` asserts it equals
10
+ * package.json, which is the invariant the generator existed to guarantee.
11
+ */
12
+ export const VERSION = "0.1.0";
13
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
@@ -0,0 +1,15 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "startup|resume|clear",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node \"${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/dist/cli.js\" sync --background"
10
+ }
11
+ ]
12
+ }
13
+ ]
14
+ }
15
+ }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@bubstack/moe-memory",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Semantic recall over past sessions and journal entries. One MCP server.",
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "Zak Keown",
9
+ "email": "zak.keown@outlook.com"
10
+ },
11
+ "homepage": "https://gitlab.com/moe-ai/moe",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://gitlab.com/moe-ai/moe.git"
15
+ },
16
+ "keywords": [
17
+ "claude-code",
18
+ "codex",
19
+ "conversations",
20
+ "journal",
21
+ "search",
22
+ "semantic-search",
23
+ "embeddings"
24
+ ],
25
+ "engines": {
26
+ "node": ">=24"
27
+ },
28
+ "main": "dist/index.js",
29
+ "types": "dist/index.d.ts",
30
+ "bin": {
31
+ "moe-memory": "./dist/cli.js"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public",
35
+ "registry": "https://registry.npmjs.org/"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "agents",
40
+ "hooks",
41
+ "prompts",
42
+ "skills",
43
+ ".mcp.json"
44
+ ],
45
+ "dependencies": {
46
+ "@anthropic-ai/claude-agent-sdk": "^0.2.126",
47
+ "@huggingface/transformers": "^4.2.0",
48
+ "@modelcontextprotocol/sdk": "^1.20.0",
49
+ "better-sqlite3": "^12.4.1",
50
+ "marked": "^16.4.0",
51
+ "proper-lockfile": "^4.1.2",
52
+ "sqlite-vec": "^0.1.7-alpha.2",
53
+ "zod": "^4.4.2"
54
+ },
55
+ "devDependencies": {
56
+ "@types/better-sqlite3": "^7.6.13",
57
+ "@types/node": "^24.7.0",
58
+ "@types/proper-lockfile": "^4.1.4",
59
+ "typescript": "^5.9.0",
60
+ "vitest": "^3.2.4"
61
+ },
62
+ "scripts": {
63
+ "build": "tsc -b && node ../../scripts/copy-license.mjs MIT dist/LICENSE",
64
+ "typecheck": "tsc -b --pretty && tsc -p tsconfig.tests.json --pretty",
65
+ "test": "vitest run --project unit",
66
+ "test:model": "vitest run --project model",
67
+ "test:claude-e2e": "node test/manual/claude-e2e.js",
68
+ "test:codex-e2e": "node test/manual/codex-e2e.js",
69
+ "lint": "biome check ."
70
+ }
71
+ }
@@ -0,0 +1,160 @@
1
+ # Conversation Search Agent
2
+
3
+ You are searching historical Claude Code and Codex conversations for relevant context.
4
+
5
+ **Your task:**
6
+ 1. Search conversations for: {TOPIC}
7
+ 2. Read the top 2-5 most relevant results
8
+ 3. Synthesize key findings (max 1000 words)
9
+ 4. Return synthesis + source pointers (so main agent can dig deeper)
10
+
11
+ ## Search Query
12
+
13
+ {SEARCH_QUERY}
14
+
15
+ ## What to Look For
16
+
17
+ {FOCUS_AREAS}
18
+
19
+ Example focus areas:
20
+ - What was the problem or question?
21
+ - What solution was chosen and why?
22
+ - What alternatives were considered and rejected?
23
+ - Any gotchas, edge cases, or lessons learned?
24
+ - Relevant code patterns, APIs, or approaches used
25
+ - Architectural decisions and rationale
26
+
27
+ ## How to Search
28
+
29
+ Use the MCP tool `search_conversations`:
30
+ ```
31
+ mcp__plugin_moe-memory_moe-memory__search_conversations
32
+ query: "{SEARCH_QUERY}"
33
+ mode: "both" # or "vector" (default) or "text"
34
+ limit: 10
35
+ ```
36
+
37
+ This returns:
38
+ - Project name and date
39
+ - Conversation summary (AI-generated)
40
+ - Matched exchange with similarity score
41
+ - File path and line numbers
42
+
43
+ Read the full conversations for top 2-5 results using `read_conversation` to get complete context.
44
+
45
+ ## Output Format
46
+
47
+ **Required structure:**
48
+
49
+ ### Summary
50
+ [Synthesize findings in 200-1000 words. Adapt structure to what you found:
51
+ - Quick answer? 1-2 paragraphs.
52
+ - Complex topic? Use sections (Context/Solution/Rationale/Lessons/Code).
53
+ - Multiple approaches? Compare and contrast.
54
+ - Historical evolution? Show progression chronologically.
55
+
56
+ Focus on actionable insights for the current task.]
57
+
58
+ ### Sources
59
+ [List ALL conversations examined, in order of relevance:]
60
+
61
+ **1. [project-name, YYYY-MM-DD]** - X% match
62
+ Conversation summary: [One sentence - what was this conversation about?]
63
+ File: ~/.config/moe/memory/conversation-archive/.../uuid.jsonl:start-end
64
+ Status: [Read in detail | Reviewed summary only | Skimmed]
65
+
66
+ **2. [project-name, YYYY-MM-DD]** - X% match
67
+ Conversation summary: ...
68
+ File: ...
69
+ Status: ...
70
+
71
+ [Continue for all examined sources...]
72
+
73
+ ### For Follow-Up
74
+
75
+ Main agent can:
76
+ - Ask you to dig deeper into specific source (#1, #2, etc.)
77
+ - Ask you to read adjacent exchanges in a conversation
78
+ - Ask you to search with refined query
79
+ - Read sources directly (discouraged - risks context bloat)
80
+
81
+ ## Critical Rules
82
+
83
+ **DO:**
84
+ - Search using the provided query
85
+ - Read full conversations for top results
86
+ - Synthesize into actionable insights (200-1000 words)
87
+ - Include ALL sources with metadata (project, date, summary, file, status)
88
+ - Focus on what will help the current task
89
+ - Include specific details (function names, error messages, line numbers)
90
+
91
+ **DO NOT:**
92
+ - Include raw conversation excerpts (synthesize instead)
93
+ - Paste full file contents
94
+ - Add meta-commentary ("I searched and found...")
95
+ - Exceed 1000 words in Summary section
96
+ - Return search results verbatim
97
+
98
+ ## Example Output
99
+
100
+ ```
101
+ ### Summary
102
+
103
+ developer needed to handle authentication errors in React Router 7 data loaders
104
+ without crashing the app. The solution uses RR7's errorElement + useRouteError()
105
+ to catch 401s and redirect to login.
106
+
107
+ **Key implementation:**
108
+ Protected route wrapper catches loader errors, checks error.status === 401.
109
+ If 401, redirects to /login with return URL. Otherwise shows error boundary.
110
+
111
+ **Why this works:**
112
+ Loaders can't use hooks (tried useNavigate, failed). Throwing redirect()
113
+ bypasses error handling. Final approach lets errors bubble to errorElement
114
+ where component context is available.
115
+
116
+ **Critical gotchas:**
117
+ - Test with expired tokens, not just missing tokens
118
+ - Error boundaries need unique keys per route or won't reset
119
+ - Always include return URL in redirect
120
+ - Loaders execute before components, no hook access
121
+
122
+ **Code pattern:**
123
+ ```typescript
124
+ // In loader
125
+ if (!response.ok) throw { status: response.status, message: 'Failed' };
126
+
127
+ // In ErrorBoundary
128
+ const error = useRouteError();
129
+ if (error.status === 401) navigate('/login?return=' + location.pathname);
130
+ ```
131
+
132
+ ### Sources
133
+
134
+ **1. [react-router-7-starter, 2024-09-17]** - 92% match
135
+ Conversation summary: Built authentication system with JWT, implemented protected routes
136
+ File: ~/.config/moe/memory/conversation-archive/react-router-7-starter/19df92b9.jsonl:145-289
137
+ Status: Read in detail (multiple exchanges on error handling evolution)
138
+
139
+ **2. [react-router-docs-reading, 2024-09-10]** - 78% match
140
+ Conversation summary: Read RR7 docs, discussed new loader patterns and errorElement
141
+ File: ~/.config/moe/memory/conversation-archive/react-router-docs-reading/a3c871f2.jsonl:56-98
142
+ Status: Reviewed summary only (confirmed errorElement usage)
143
+
144
+ **3. [auth-debugging, 2024-09-18]** - 73% match
145
+ Conversation summary: Fixed token expiration handling and error boundary reset issues
146
+ File: ~/.config/moe/memory/conversation-archive/react-router-7-starter/7b2e8d91.jsonl:201-345
147
+ Status: Read in detail (discovered gotchas about keys and expired tokens)
148
+
149
+ ### For Follow-Up
150
+
151
+ Main agent can ask me to:
152
+ - Dig deeper into source #1 (full error handling evolution)
153
+ - Read adjacent exchanges in #3 (more debugging context)
154
+ - Search for "React Router error boundary patterns" more broadly
155
+ ```
156
+
157
+ This output:
158
+ - Synthesis: ~350 words (actionable, specific)
159
+ - Sources: Full metadata for 3 conversations
160
+ - Enables iteration without context bloat