teammind 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.
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.extractMemoriesFromTranscript = extractMemoriesFromTranscript;
7
+ exports.formatTranscript = formatTranscript;
8
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
9
+ const constants_1 = require("./constants");
10
+ const EXTRACTION_PROMPT = `You are analyzing a Claude Code session transcript to extract high-value memories for a development team.
11
+
12
+ Extract ONLY memories that provide non-obvious, lasting value:
13
+ ✓ Bugs found and their root cause
14
+ ✓ Architectural decisions made and WHY
15
+ ✓ Non-obvious gotchas or undocumented behaviors
16
+ ✓ Performance findings
17
+ ✓ Security considerations
18
+ ✓ API quirks or workarounds discovered
19
+ ✓ Important constraints or business rules discovered in code
20
+
21
+ DO NOT extract:
22
+ ✗ Generic programming advice
23
+ ✗ Things obvious from reading the code
24
+ ✗ Temporary debugging steps that were reverted
25
+ ✗ Standard library usage
26
+ ✗ Basic explanations of how code works
27
+
28
+ For each memory output valid JSON with these exact fields:
29
+ - content: Full explanation (2-5 sentences, enough context to be useful later)
30
+ - summary: One line, max 80 chars, action-oriented
31
+ - tags: Array from ["bug","decision","gotcha","pattern","performance","security","config","api"]
32
+ - file_paths: Array of relative file paths involved (empty array if none)
33
+ - functions: Array of "ClassName.methodName" or "functionName" (empty array if none)
34
+
35
+ Respond with ONLY a JSON array. If nothing worth remembering, respond with [].
36
+
37
+ TRANSCRIPT:
38
+ {{TRANSCRIPT}}`;
39
+ async function extractMemoriesFromTranscript(transcript, apiKey) {
40
+ const key = apiKey || process.env.ANTHROPIC_API_KEY;
41
+ if (!key)
42
+ return [];
43
+ try {
44
+ const client = new sdk_1.default({ apiKey: key });
45
+ // Trim transcript to avoid huge token counts (keep last 80k chars which is ~20k tokens)
46
+ const trimmed = transcript.length > 80000
47
+ ? transcript.slice(-80000)
48
+ : transcript;
49
+ const response = await client.messages.create({
50
+ model: constants_1.HAIKU_MODEL,
51
+ max_tokens: 4096,
52
+ messages: [{
53
+ role: 'user',
54
+ content: EXTRACTION_PROMPT.replace('{{TRANSCRIPT}}', trimmed)
55
+ }]
56
+ });
57
+ const text = response.content[0].type === 'text' ? response.content[0].text : '';
58
+ // Extract JSON array — handle markdown code fences if present
59
+ const jsonMatch = text.match(/```(?:json)?\s*([\s\S]*?)\s*```/) ||
60
+ text.match(/(\[[\s\S]*\])/);
61
+ if (!jsonMatch)
62
+ return [];
63
+ const raw = JSON.parse(jsonMatch[1] || jsonMatch[0]);
64
+ if (!Array.isArray(raw))
65
+ return [];
66
+ return raw
67
+ .filter((m) => m && typeof m.content === 'string' && m.content.length > 10)
68
+ .map((m) => ({
69
+ content: String(m.content || '').slice(0, 2000),
70
+ summary: String(m.summary || m.content || '').slice(0, 80),
71
+ tags: Array.isArray(m.tags) ? m.tags.slice(0, 5) : [],
72
+ file_paths: Array.isArray(m.file_paths) ? m.file_paths : [],
73
+ functions: Array.isArray(m.functions) ? m.functions : [],
74
+ }));
75
+ }
76
+ catch {
77
+ return [];
78
+ }
79
+ }
80
+ // Format a conversation transcript from Claude Code's hook payload
81
+ function formatTranscript(hookPayload) {
82
+ try {
83
+ const transcript = hookPayload?.transcript || hookPayload?.messages || [];
84
+ if (!Array.isArray(transcript) || transcript.length === 0) {
85
+ return typeof hookPayload === 'string' ? hookPayload : JSON.stringify(hookPayload);
86
+ }
87
+ return transcript
88
+ .map((msg) => {
89
+ const role = (msg.role || 'unknown').toUpperCase();
90
+ const content = Array.isArray(msg.content)
91
+ ? msg.content.map((c) => (typeof c === 'string' ? c : c?.text || '')).join('\n')
92
+ : String(msg.content || '');
93
+ return `[${role}]: ${content}`;
94
+ })
95
+ .join('\n\n');
96
+ }
97
+ catch {
98
+ return JSON.stringify(hookPayload).slice(0, 50000);
99
+ }
100
+ }
101
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"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"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export interface GitContext {
2
+ root: string;
3
+ branch: string;
4
+ commit: string;
5
+ }
6
+ export declare function normalizePath(p: string): string;
7
+ export declare function getGitContext(cwd: string): Promise<GitContext | null>;
8
+ export declare function hashFile(filePath: string): string;
9
+ export declare function resolveFilePaths(filePaths: string[], repoRoot: string): string[];
package/dist/git.js ADDED
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.normalizePath = normalizePath;
7
+ exports.getGitContext = getGitContext;
8
+ exports.hashFile = hashFile;
9
+ exports.resolveFilePaths = resolveFilePaths;
10
+ const crypto_1 = require("crypto");
11
+ const fs_1 = require("fs");
12
+ const path_1 = __importDefault(require("path"));
13
+ const simple_git_1 = __importDefault(require("simple-git"));
14
+ function normalizePath(p) {
15
+ return p.replace(/\\/g, '/');
16
+ }
17
+ async function getGitContext(cwd) {
18
+ try {
19
+ const git = (0, simple_git_1.default)(cwd);
20
+ const isRepo = await git.checkIsRepo();
21
+ if (!isRepo)
22
+ return null;
23
+ const root = normalizePath((await git.revparse(['--show-toplevel'])).trim());
24
+ const branchResult = await git.branch();
25
+ const branch = branchResult.current || 'unknown';
26
+ const commit = (await git.revparse(['HEAD'])).trim();
27
+ return { root, branch, commit };
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ function hashFile(filePath) {
34
+ try {
35
+ if (!(0, fs_1.existsSync)(filePath))
36
+ return '';
37
+ const content = (0, fs_1.readFileSync)(filePath);
38
+ return (0, crypto_1.createHash)('sha256').update(content).digest('hex').slice(0, 16);
39
+ }
40
+ catch {
41
+ return '';
42
+ }
43
+ }
44
+ function resolveFilePaths(filePaths, repoRoot) {
45
+ return filePaths
46
+ .map(fp => {
47
+ // If already absolute, keep. Otherwise resolve from repo root.
48
+ if (path_1.default.isAbsolute(fp))
49
+ return fp;
50
+ return path_1.default.join(repoRoot, fp);
51
+ })
52
+ .filter(fp => (0, fs_1.existsSync)(fp));
53
+ }
54
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":";;;;;AAWA,sCAEC;AAED,sCAeC;AAED,4BAQC;AAED,4CAQC;AAlDD,mCAAmC;AACnC,2BAA6C;AAC7C,gDAAuB;AACvB,4DAAkC;AAQlC,SAAgB,aAAa,CAAC,CAAS;IACrC,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;AAC9B,CAAC;AAEM,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAA,oBAAS,EAAC,GAAG,CAAC,CAAA;QAC1B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,EAAE,CAAA;QACtC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA;QAExB,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QAC5E,MAAM,YAAY,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAA;QACvC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,IAAI,SAAS,CAAA;QAChD,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QAEpD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAgB,QAAQ,CAAC,QAAgB;IACvC,IAAI,CAAC;QACH,IAAI,CAAC,IAAA,eAAU,EAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,CAAA;QACpC,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,QAAQ,CAAC,CAAA;QACtC,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED,SAAgB,gBAAgB,CAAC,SAAmB,EAAE,QAAgB;IACpE,OAAO,SAAS;SACb,GAAG,CAAC,EAAE,CAAC,EAAE;QACR,+DAA+D;QAC/D,IAAI,cAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAAE,OAAO,EAAE,CAAA;QAClC,OAAO,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;IAChC,CAAC,CAAC;SACD,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,IAAA,eAAU,EAAC,EAAE,CAAC,CAAC,CAAA;AACjC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Memory } from './db';
2
+ export interface SearchResult extends Memory {
3
+ score: number;
4
+ }
5
+ export declare function searchMemories(query: string, repoPath: string, opts?: {
6
+ filePath?: string;
7
+ limit?: number;
8
+ }): Promise<SearchResult[]>;
9
+ export declare function rankMemoriesForInjection(repoPath: string, branch: string, limit?: number): Memory[];
10
+ export declare function findDuplicate(content: string, repoPath: string, threshold?: number): Promise<string | null>;
11
+ export declare function formatMemoriesForContext(memories: Memory[], projectName: string, branch: string): string;
package/dist/search.js ADDED
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.searchMemories = searchMemories;
4
+ exports.rankMemoriesForInjection = rankMemoriesForInjection;
5
+ exports.findDuplicate = findDuplicate;
6
+ exports.formatMemoriesForContext = formatMemoriesForContext;
7
+ const db_1 = require("./db");
8
+ const embed_1 = require("./embed");
9
+ const constants_1 = require("./constants");
10
+ // Full semantic + keyword hybrid search — used by MCP tool (mid-session)
11
+ async function searchMemories(query, repoPath, opts = {}) {
12
+ const { filePath, limit = 5 } = opts;
13
+ const memories = (0, db_1.getAllMemoriesWithEmbeddings)(repoPath);
14
+ if (memories.length === 0)
15
+ return [];
16
+ // Embed query
17
+ let queryVec = null;
18
+ try {
19
+ queryVec = await (0, embed_1.embed)(query);
20
+ }
21
+ catch {
22
+ // Fall back to keyword search if embedding fails
23
+ }
24
+ const scored = memories.map(m => {
25
+ let score = 0;
26
+ // Semantic score
27
+ if (queryVec && m.embedding) {
28
+ const memVec = (0, embed_1.deserializeVec)(m.embedding);
29
+ score += (0, embed_1.cosineSimilarity)(queryVec, memVec) * 2;
30
+ }
31
+ // Keyword score
32
+ score += (0, embed_1.keywordScore)(query, m.content + ' ' + m.summary);
33
+ // Recency boost: memories from last 14 days get +0.1
34
+ const ageDays = (Date.now() - m.created_at) / (1000 * 60 * 60 * 24);
35
+ if (ageDays < 14)
36
+ score += 0.1 * (1 - ageDays / 14);
37
+ // File path relevance boost
38
+ if (filePath) {
39
+ const normalizedFp = filePath.replace(/\\/g, '/');
40
+ if (m.file_paths.some(fp => normalizedFp.includes(fp) || fp.includes(normalizedFp))) {
41
+ score += 0.5;
42
+ }
43
+ }
44
+ // Tag boost for high-priority tags
45
+ if (m.tags.includes('bug') || m.tags.includes('gotcha'))
46
+ score += 0.05;
47
+ if (m.tags.includes('security'))
48
+ score += 0.1;
49
+ return { ...m, score };
50
+ });
51
+ // Apply file filter if provided
52
+ const filtered = filePath
53
+ ? scored.filter(m => {
54
+ const normalizedFp = filePath.replace(/\\/g, '/');
55
+ return m.file_paths.length === 0 ||
56
+ m.file_paths.some(fp => normalizedFp.includes(fp) || fp.includes(normalizedFp));
57
+ })
58
+ : scored;
59
+ return filtered
60
+ .filter(m => m.score > 0)
61
+ .sort((a, b) => b.score - a.score)
62
+ .slice(0, limit);
63
+ }
64
+ // Fast keyword-only ranking — used for session injection (no model needed, must be fast)
65
+ function rankMemoriesForInjection(repoPath, branch, limit = constants_1.MAX_INJECT_MEMORIES) {
66
+ const memories = (0, db_1.getMemories)(repoPath, { limit: 200, includeStale: false });
67
+ if (memories.length === 0)
68
+ return [];
69
+ const scored = memories.map(m => {
70
+ let score = 0;
71
+ // Recency: most recent gets highest score
72
+ const ageDays = (Date.now() - m.created_at) / (1000 * 60 * 60 * 24);
73
+ score += Math.max(0, 10 - ageDays * 0.5);
74
+ // Branch match boost
75
+ if (m.git_branch === branch)
76
+ score += 3;
77
+ // Tag priority
78
+ if (m.tags.includes('gotcha') || m.tags.includes('bug'))
79
+ score += 2;
80
+ if (m.tags.includes('security'))
81
+ score += 3;
82
+ if (m.tags.includes('config'))
83
+ score += 1;
84
+ return { ...m, score };
85
+ });
86
+ return scored
87
+ .sort((a, b) => b.score - a.score)
88
+ .slice(0, limit);
89
+ }
90
+ // Check if a memory is a near-duplicate of an existing one
91
+ // Returns the ID of the duplicate if found, null otherwise
92
+ async function findDuplicate(content, repoPath, threshold = 0.88) {
93
+ const existing = (0, db_1.getAllMemoriesWithEmbeddings)(repoPath);
94
+ if (existing.length === 0)
95
+ return null;
96
+ let queryVec = null;
97
+ try {
98
+ queryVec = await (0, embed_1.embed)(content);
99
+ }
100
+ catch {
101
+ return null; // can't dedup without embeddings
102
+ }
103
+ for (const m of existing) {
104
+ if (!m.embedding)
105
+ continue;
106
+ const memVec = (0, embed_1.deserializeVec)(m.embedding);
107
+ const sim = (0, embed_1.cosineSimilarity)(queryVec, memVec);
108
+ if (sim >= threshold)
109
+ return m.id;
110
+ }
111
+ return null;
112
+ }
113
+ // Format memories for injection into Claude's context
114
+ function formatMemoriesForContext(memories, projectName, branch) {
115
+ if (memories.length === 0)
116
+ return '';
117
+ const lines = [
118
+ `<team_memory project="${projectName}" branch="${branch}">`
119
+ ];
120
+ for (let i = 0; i < memories.length; i++) {
121
+ const m = memories[i];
122
+ const tag = m.tags[0] || 'note';
123
+ const staleTag = m.stale ? ' [may be outdated]' : '';
124
+ const fileHint = m.file_paths.length > 0 ? ` — ${m.file_paths[0]}` : '';
125
+ lines.push(`${i + 1}. [${tag}] ${m.summary}${staleTag}${fileHint}`);
126
+ }
127
+ lines.push(`</team_memory>`);
128
+ lines.push(`(${memories.length} memories loaded — use memory_search tool for details or more)`);
129
+ return lines.join('\n');
130
+ }
131
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function startMcpServer(): Promise<void>;
package/dist/server.js ADDED
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startMcpServer = startMcpServer;
7
+ /* eslint-disable @typescript-eslint/no-require-imports */
8
+ // Use McpServer (high-level API from SDK v1.27+) with require() to bypass
9
+ // TypeScript's module resolution for packages using the exports map
10
+ const { McpServer } = require('@modelcontextprotocol/sdk/server/mcp.js');
11
+ const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
12
+ const path_1 = __importDefault(require("path"));
13
+ const os_1 = __importDefault(require("os"));
14
+ const zod_1 = require("zod");
15
+ const search_1 = require("./search");
16
+ const db_1 = require("./db");
17
+ const git_1 = require("./git");
18
+ const embed_1 = require("./embed");
19
+ const staleness_1 = require("./staleness");
20
+ async function startMcpServer() {
21
+ const cwd = (0, git_1.normalizePath)(process.cwd());
22
+ const server = new McpServer({
23
+ name: 'teammind',
24
+ version: '0.1.0',
25
+ });
26
+ // ─── memory_search ──────────────────────────────────────────────────────────
27
+ server.registerTool('memory_search', {
28
+ description: 'Search team memory for relevant context about code, bugs, decisions, or patterns. Call this proactively when you open a file or encounter a problem that might have prior context.',
29
+ inputSchema: {
30
+ query: zod_1.z.string().describe('Natural language query, e.g. "auth middleware behavior" or "stripe webhook handling"'),
31
+ file_path: zod_1.z.string().optional().describe('Narrow results to memories about a specific file'),
32
+ limit: zod_1.z.number().optional().describe('Max results to return (default 5)'),
33
+ },
34
+ }, async ({ query, file_path, limit }) => {
35
+ const gitCtx = await (0, git_1.getGitContext)(cwd);
36
+ const repoPath = gitCtx?.root || cwd;
37
+ const results = await (0, search_1.searchMemories)(query, repoPath, {
38
+ filePath: file_path,
39
+ limit: limit || 5,
40
+ });
41
+ if (results.length === 0) {
42
+ return text('No relevant memories found for this query.');
43
+ }
44
+ const formatted = results.map((m, i) => {
45
+ const staleNote = m.stale ? ' [MAY BE OUTDATED]' : '';
46
+ const files = m.file_paths.length > 0 ? `\n Files: ${m.file_paths.join(', ')}` : '';
47
+ const fns = m.functions.length > 0 ? `\n Functions: ${m.functions.join(', ')}` : '';
48
+ const tags = `[${m.tags.join(', ') || 'note'}]`;
49
+ return `${i + 1}. ${tags} ${m.summary}${staleNote}\n ${m.content}${files}${fns}`;
50
+ }).join('\n\n');
51
+ return text(formatted);
52
+ });
53
+ // ─── memory_add ─────────────────────────────────────────────────────────────
54
+ server.registerTool('memory_add', {
55
+ description: 'Save an important insight, decision, bug fix, or pattern to team memory so future sessions can benefit from it. Use this when you discover something non-obvious.',
56
+ inputSchema: {
57
+ content: zod_1.z.string().describe('Full description (2-5 sentences with enough context to be useful later)'),
58
+ summary: zod_1.z.string().describe('One-line summary, max 80 chars'),
59
+ tags: zod_1.z.array(zod_1.z.string()).optional().describe('Tags: bug, decision, gotcha, pattern, performance, security, config, api'),
60
+ file_paths: zod_1.z.array(zod_1.z.string()).optional().describe('Relative file paths this memory relates to'),
61
+ functions: zod_1.z.array(zod_1.z.string()).optional().describe('Function or method names, e.g. ["UserAuth.handleOAuth"]'),
62
+ },
63
+ }, async ({ content, summary, tags, file_paths, functions }) => {
64
+ const gitCtx = await (0, git_1.getGitContext)(cwd);
65
+ const repoPath = gitCtx?.root || cwd;
66
+ let embedding = null;
67
+ try {
68
+ const vec = await (0, embed_1.embed)(content);
69
+ embedding = (0, embed_1.serializeVec)(vec);
70
+ }
71
+ catch { /* embedding optional */ }
72
+ const id = (0, db_1.saveMemory)({
73
+ content,
74
+ summary,
75
+ tags: tags || [],
76
+ file_paths: file_paths || [],
77
+ functions: functions || [],
78
+ embedding,
79
+ repo_path: repoPath,
80
+ git_commit: gitCtx?.commit || null,
81
+ git_branch: gitCtx?.branch || null,
82
+ created_by: os_1.default.userInfo().username || 'local',
83
+ source: 'manual',
84
+ stale: 0,
85
+ });
86
+ if (file_paths && file_paths.length > 0) {
87
+ const absFiles = (0, git_1.resolveFilePaths)(file_paths, repoPath);
88
+ (0, db_1.saveMemoryFiles)(id, absFiles.map(fp => ({
89
+ path: path_1.default.relative(repoPath, fp),
90
+ hash: (0, git_1.hashFile)(fp),
91
+ })));
92
+ }
93
+ const total = (0, db_1.countMemories)(repoPath);
94
+ return text(`Memory saved. (${total} total memories for this project)`);
95
+ });
96
+ // ─── memory_list ────────────────────────────────────────────────────────────
97
+ server.registerTool('memory_list', {
98
+ description: 'List recent memories for the current project.',
99
+ inputSchema: {
100
+ limit: zod_1.z.number().optional().describe('Number of memories to list (default 10)'),
101
+ },
102
+ }, async ({ limit }) => {
103
+ const gitCtx = await (0, git_1.getGitContext)(cwd);
104
+ const repoPath = gitCtx?.root || cwd;
105
+ const memories = (0, db_1.getMemories)(repoPath, { limit: limit || 10 });
106
+ if (memories.length === 0) {
107
+ return text('No memories yet for this project. They will be captured automatically at session end, or use memory_add.');
108
+ }
109
+ const formatted = memories.map((m, i) => {
110
+ const staleNote = m.stale ? ' ⚠ stale' : '';
111
+ const tags = `[${m.tags.join(', ') || 'note'}]`;
112
+ const age = formatAge(m.created_at);
113
+ return `${i + 1}. ${tags} ${m.summary}${staleNote} — ${age}`;
114
+ }).join('\n');
115
+ const total = (0, db_1.countMemories)(repoPath);
116
+ return text(`${formatted}\n\n(${total} total)`);
117
+ });
118
+ // ─── memory_stale ───────────────────────────────────────────────────────────
119
+ server.registerTool('memory_stale', {
120
+ description: 'Check which memories may be outdated because their referenced files changed. Run this periodically or when you suspect something is stale.',
121
+ inputSchema: {},
122
+ }, async () => {
123
+ const gitCtx = await (0, git_1.getGitContext)(cwd);
124
+ const repoPath = gitCtx?.root || cwd;
125
+ const report = await (0, staleness_1.checkAndMarkStaleness)(repoPath);
126
+ if (report.markedStale === 0) {
127
+ return text(`All ${report.checked} tracked memories are fresh.`);
128
+ }
129
+ const details = report.staleMemories
130
+ .map(m => `- ${m.summary}\n Changed files: ${m.changedFiles.join(', ')}`)
131
+ .join('\n');
132
+ return text(`Marked ${report.markedStale} memories as stale (files changed since capture):\n${details}\n\n` +
133
+ `These will still appear tagged [may be outdated] but are deprioritized in injection.`);
134
+ });
135
+ const transport = new StdioServerTransport();
136
+ await server.connect(transport);
137
+ }
138
+ function text(content) {
139
+ return { content: [{ type: 'text', text: content }] };
140
+ }
141
+ function formatAge(ts) {
142
+ const days = Math.floor((Date.now() - ts) / (1000 * 60 * 60 * 24));
143
+ if (days === 0)
144
+ return 'today';
145
+ if (days === 1)
146
+ return 'yesterday';
147
+ if (days < 30)
148
+ return `${days}d ago`;
149
+ if (days < 365)
150
+ return `${Math.floor(days / 30)}mo ago`;
151
+ return `${Math.floor(days / 365)}y ago`;
152
+ }
153
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface StalenessReport {
2
+ checked: number;
3
+ markedStale: number;
4
+ staleMemories: Array<{
5
+ id: string;
6
+ summary: string;
7
+ changedFiles: string[];
8
+ }>;
9
+ }
10
+ export declare function checkAndMarkStaleness(repoPath: string): Promise<StalenessReport>;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.checkAndMarkStaleness = checkAndMarkStaleness;
7
+ const path_1 = __importDefault(require("path"));
8
+ const db_1 = require("./db");
9
+ const git_1 = require("./git");
10
+ async function checkAndMarkStaleness(repoPath) {
11
+ const memories = (0, db_1.getMemoriesWithFiles)(repoPath);
12
+ const report = { checked: 0, markedStale: 0, staleMemories: [] };
13
+ for (const memory of memories) {
14
+ if (memory.tracked_files.length === 0)
15
+ continue;
16
+ report.checked++;
17
+ const changedFiles = [];
18
+ for (const tf of memory.tracked_files) {
19
+ const absPath = path_1.default.isAbsolute(tf.file_path)
20
+ ? tf.file_path
21
+ : path_1.default.join(repoPath, tf.file_path);
22
+ const currentHash = (0, git_1.hashFile)(absPath);
23
+ // Empty hash means file doesn't exist or couldn't be read
24
+ if (tf.file_hash && currentHash && currentHash !== tf.file_hash) {
25
+ changedFiles.push(tf.file_path);
26
+ }
27
+ }
28
+ if (changedFiles.length > 0) {
29
+ (0, db_1.markMemoryStale)(memory.id);
30
+ report.markedStale++;
31
+ report.staleMemories.push({
32
+ id: memory.id,
33
+ summary: memory.summary,
34
+ changedFiles,
35
+ });
36
+ }
37
+ }
38
+ return report;
39
+ }
40
+ //# sourceMappingURL=staleness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staleness.js","sourceRoot":"","sources":["../src/staleness.ts"],"names":[],"mappings":";;;;;AAUA,sDAmCC;AA7CD,gDAAuB;AACvB,6BAA4D;AAC5D,+BAAgC;AAQzB,KAAK,UAAU,qBAAqB,CAAC,QAAgB;IAC1D,MAAM,QAAQ,GAAG,IAAA,yBAAoB,EAAC,QAAQ,CAAC,CAAA;IAC/C,MAAM,MAAM,GAAoB,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAA;IAEjF,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC;YAAE,SAAQ;QAC/C,MAAM,CAAC,OAAO,EAAE,CAAA;QAEhB,MAAM,YAAY,GAAa,EAAE,CAAA;QAEjC,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,cAAI,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC;gBAC3C,CAAC,CAAC,EAAE,CAAC,SAAS;gBACd,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,SAAS,CAAC,CAAA;YAErC,MAAM,WAAW,GAAG,IAAA,cAAQ,EAAC,OAAO,CAAC,CAAA;YAErC,0DAA0D;YAC1D,IAAI,EAAE,CAAC,SAAS,IAAI,WAAW,IAAI,WAAW,KAAK,EAAE,CAAC,SAAS,EAAE,CAAC;gBAChE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAA;YACjC,CAAC;QACH,CAAC;QAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,IAAA,oBAAe,EAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YAC1B,MAAM,CAAC,WAAW,EAAE,CAAA;YACpB,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC;gBACxB,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,YAAY;aACb,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
package/dist/sync.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ export interface TeamMemoryExport {
2
+ version: '1.0';
3
+ exported_at: string;
4
+ memories: Array<{
5
+ id: string;
6
+ content: string;
7
+ summary: string;
8
+ tags: string[];
9
+ file_paths: string[];
10
+ functions: string[];
11
+ git_commit: string | null;
12
+ git_branch: string | null;
13
+ created_by: string;
14
+ created_at: string;
15
+ }>;
16
+ }
17
+ export declare function exportMemories(repoPath: string): TeamMemoryExport;
18
+ export declare function importMemories(filePath: string, repoPath: string, createdBy?: string): Promise<{
19
+ imported: number;
20
+ skipped: number;
21
+ }>;
22
+ export declare function writeExportFile(exportData: TeamMemoryExport, outputPath: string): void;