@exaudeus/memory-mcp 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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +264 -0
  3. package/dist/__tests__/clock-and-validators.test.d.ts +1 -0
  4. package/dist/__tests__/clock-and-validators.test.js +237 -0
  5. package/dist/__tests__/config-manager.test.d.ts +1 -0
  6. package/dist/__tests__/config-manager.test.js +142 -0
  7. package/dist/__tests__/config.test.d.ts +1 -0
  8. package/dist/__tests__/config.test.js +236 -0
  9. package/dist/__tests__/crash-journal.test.d.ts +1 -0
  10. package/dist/__tests__/crash-journal.test.js +203 -0
  11. package/dist/__tests__/e2e.test.d.ts +1 -0
  12. package/dist/__tests__/e2e.test.js +788 -0
  13. package/dist/__tests__/ephemeral-benchmark.test.d.ts +1 -0
  14. package/dist/__tests__/ephemeral-benchmark.test.js +651 -0
  15. package/dist/__tests__/ephemeral.test.d.ts +1 -0
  16. package/dist/__tests__/ephemeral.test.js +435 -0
  17. package/dist/__tests__/git-service.test.d.ts +1 -0
  18. package/dist/__tests__/git-service.test.js +43 -0
  19. package/dist/__tests__/normalize.test.d.ts +1 -0
  20. package/dist/__tests__/normalize.test.js +161 -0
  21. package/dist/__tests__/store.test.d.ts +1 -0
  22. package/dist/__tests__/store.test.js +1153 -0
  23. package/dist/config-manager.d.ts +49 -0
  24. package/dist/config-manager.js +126 -0
  25. package/dist/config.d.ts +32 -0
  26. package/dist/config.js +162 -0
  27. package/dist/crash-journal.d.ts +38 -0
  28. package/dist/crash-journal.js +198 -0
  29. package/dist/ephemeral-weights.json +1847 -0
  30. package/dist/ephemeral.d.ts +20 -0
  31. package/dist/ephemeral.js +516 -0
  32. package/dist/formatters.d.ts +10 -0
  33. package/dist/formatters.js +92 -0
  34. package/dist/git-service.d.ts +5 -0
  35. package/dist/git-service.js +39 -0
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.js +1197 -0
  38. package/dist/normalize.d.ts +2 -0
  39. package/dist/normalize.js +69 -0
  40. package/dist/store.d.ts +84 -0
  41. package/dist/store.js +813 -0
  42. package/dist/text-analyzer.d.ts +32 -0
  43. package/dist/text-analyzer.js +190 -0
  44. package/dist/thresholds.d.ts +39 -0
  45. package/dist/thresholds.js +75 -0
  46. package/dist/types.d.ts +186 -0
  47. package/dist/types.js +33 -0
  48. package/package.json +57 -0
@@ -0,0 +1,2 @@
1
+ /** Normalize args before Zod validation: resolve aliases, default workspace, fix wildcards */
2
+ export declare function normalizeArgs(toolName: string, raw: Record<string, unknown> | undefined, lobeNames: readonly string[]): Record<string, unknown>;
@@ -0,0 +1,69 @@
1
+ // Argument normalization for MCP tool calls.
2
+ //
3
+ // Agents frequently guess wrong param names. This module resolves common aliases
4
+ // and applies defaults to avoid wasted round-trips from validation errors.
5
+ // Pure functions — no side effects, no state.
6
+ /** Canonical param name aliases — maps guessed names to their correct form */
7
+ const PARAM_ALIASES = {
8
+ // memory_store aliases
9
+ key: 'title',
10
+ name: 'title',
11
+ value: 'content',
12
+ body: 'content',
13
+ text: 'content',
14
+ refs: 'references',
15
+ // memory_query aliases
16
+ query: 'filter',
17
+ search: 'filter',
18
+ keyword: 'filter',
19
+ // memory_context aliases
20
+ description: 'context',
21
+ task: 'context',
22
+ // lobe aliases
23
+ workspace: 'lobe',
24
+ repo: 'lobe',
25
+ };
26
+ /** Wildcard scope aliases — agents guess many variations instead of "*" */
27
+ const SCOPE_WILDCARDS = new Set([
28
+ 'all', 'everything', 'any', '*', 'global', 'project', 'repo',
29
+ 'workspace', 'every', 'full', 'complete',
30
+ ]);
31
+ /** Normalize args before Zod validation: resolve aliases, default workspace, fix wildcards */
32
+ export function normalizeArgs(toolName, raw, lobeNames) {
33
+ const args = { ...(raw ?? {}) };
34
+ // 1. Resolve param aliases (move aliased keys to canonical names)
35
+ for (const [alias, canonical] of Object.entries(PARAM_ALIASES)) {
36
+ if (alias in args && !(canonical in args)) {
37
+ args[canonical] = args[alias];
38
+ delete args[alias];
39
+ }
40
+ }
41
+ // 2. For memory_store: accept "scope" as alias for "topic"
42
+ if (toolName === 'memory_store' && 'scope' in args && !('topic' in args)) {
43
+ args['topic'] = args['scope'];
44
+ delete args['scope'];
45
+ }
46
+ // 3. Default lobe to the only available one when omitted
47
+ if (!('lobe' in args) || args['lobe'] === undefined || args['lobe'] === '') {
48
+ if (lobeNames.length === 1) {
49
+ args['lobe'] = lobeNames[0];
50
+ }
51
+ }
52
+ // 4. Normalize wildcard scope values
53
+ if ('scope' in args && typeof args['scope'] === 'string') {
54
+ if (SCOPE_WILDCARDS.has(args['scope'].toLowerCase())) {
55
+ args['scope'] = '*';
56
+ }
57
+ }
58
+ // 5. For memory_query: default scope to "*" when missing
59
+ if (toolName === 'memory_query' && !('scope' in args)) {
60
+ args['scope'] = '*';
61
+ }
62
+ // 6. Normalize branch wildcard values
63
+ if ('branch' in args && typeof args['branch'] === 'string') {
64
+ if (SCOPE_WILDCARDS.has(args['branch'].toLowerCase())) {
65
+ args['branch'] = '*';
66
+ }
67
+ }
68
+ return args;
69
+ }
@@ -0,0 +1,84 @@
1
+ import type { MemoryEntry, TopicScope, TrustLevel, DetailLevel, QueryResult, StoreResult, CorrectResult, MemoryStats, BriefingResult, ConflictPair, MemoryConfig } from './types.js';
2
+ export declare class MarkdownMemoryStore {
3
+ private readonly config;
4
+ private readonly memoryPath;
5
+ private readonly clock;
6
+ private readonly git;
7
+ private entries;
8
+ private corruptFileCount;
9
+ constructor(config: MemoryConfig);
10
+ /** Resolved behavior thresholds — user config merged over defaults.
11
+ * Centralizes threshold resolution so every caller gets the same value. */
12
+ private get behavior();
13
+ /** Initialize the store: create memory dir and load existing entries */
14
+ init(): Promise<void>;
15
+ /** Store a new knowledge entry */
16
+ store(topic: TopicScope, title: string, content: string, sources?: string[], trust?: TrustLevel, references?: string[]): Promise<StoreResult>;
17
+ /** Query knowledge by scope and detail level */
18
+ query(scope: string, detail?: DetailLevel, filter?: string, branchFilter?: string): Promise<QueryResult>;
19
+ /** Generate a session-start briefing */
20
+ briefing(maxTokens?: number): Promise<BriefingResult>;
21
+ /** Correct an existing entry */
22
+ correct(id: string, correction: string, action: 'append' | 'replace' | 'delete'): Promise<CorrectResult>;
23
+ /** Get memory health statistics */
24
+ stats(): Promise<MemoryStats>;
25
+ /** Bootstrap: scan repo structure and seed initial knowledge */
26
+ bootstrap(): Promise<StoreResult[]>;
27
+ /** Search across all topics using keyword matching with topic-based boosting.
28
+ * @param minMatch Minimum ratio of context keywords that must match (0-1, default 0.2) */
29
+ contextSearch(context: string, maxResults?: number, branchFilter?: string, minMatch?: number): Promise<Array<{
30
+ entry: MemoryEntry;
31
+ score: number;
32
+ matchedKeywords: string[];
33
+ }>>;
34
+ /** Generate a collision-resistant ID: {prefix}-{8 random hex chars} */
35
+ private generateId;
36
+ /** Compute relative file path for an entry within the memory directory */
37
+ private entryToRelativePath;
38
+ /** Sanitize git branch name for use as a directory name */
39
+ private sanitizeBranchName;
40
+ /** Get the current git branch name — delegates to injected GitService */
41
+ getCurrentBranch(): Promise<string>;
42
+ /** Write a single entry to its own file */
43
+ private persistEntry;
44
+ /** Delete the file for an entry */
45
+ private deleteEntryFile;
46
+ /** Load all entries from disk and return as an immutable snapshot.
47
+ * Pure read — no mutation. Callers decide whether to cache.
48
+ * Tracks corrupt files for observability without failing the load. */
49
+ private loadSnapshot;
50
+ /** Reload entries from disk into the store's working state.
51
+ * This is the single mutation point for disk reads. */
52
+ private reloadFromDisk;
53
+ /** Recursively find all .md files in a directory */
54
+ private findMarkdownFiles;
55
+ /** Parse a single-entry Markdown file (# heading format).
56
+ * Validates topic and trust at the boundary — rejects corrupt files. */
57
+ private parseSingleEntry;
58
+ private formatEntry;
59
+ private isFresh;
60
+ /** Days elapsed since entry was last accessed */
61
+ private daysSinceAccess;
62
+ private summarize;
63
+ /** Get HEAD SHA for source tracking — delegates to injected GitService */
64
+ private getGitSha;
65
+ /** Get total storage size in bytes, or null if unmeasurable */
66
+ private getStorageSize;
67
+ private formatBytes;
68
+ /** Find entries in the same topic with significant overlap (dedup detection).
69
+ * Uses hybrid jaccard+containment similarity. */
70
+ private findRelatedEntries;
71
+ /** Fetch raw MemoryEntry objects by ID for conflict detection.
72
+ * Must be called after query() (which calls reloadFromDisk) to ensure entries are current. */
73
+ getEntriesByIds(ids: readonly string[]): MemoryEntry[];
74
+ /** Detect potential conflicts in a result set — lazy, high-signal, never background.
75
+ * Compares all pairs from the given entries using similarity().
76
+ * Only flags pairs where both entries have substantive content (>50 chars) and
77
+ * similarity exceeds 0.6. Returns at most 2 pairs to avoid overwhelming the agent.
78
+ *
79
+ * Accepts a minimal shape so it works with both MemoryEntry and QueryEntry (full detail). */
80
+ detectConflicts(entries: readonly Pick<MemoryEntry, 'id' | 'title' | 'content' | 'confidence' | 'created' | 'topic' | 'trust'>[]): ConflictPair[];
81
+ /** Find preferences relevant to a given entry (cross-topic overlap).
82
+ * Lower threshold than dedup since preferences are always worth surfacing. */
83
+ private findRelevantPreferences;
84
+ }