@teamlens/core 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 (49) hide show
  1. package/dist/analytics/analytics-engine.d.ts +45 -0
  2. package/dist/analytics/analytics-engine.d.ts.map +1 -0
  3. package/dist/analytics/analytics-engine.js +176 -0
  4. package/dist/analytics/analytics-engine.js.map +1 -0
  5. package/dist/distribution/distributor.d.ts +19 -0
  6. package/dist/distribution/distributor.d.ts.map +1 -0
  7. package/dist/distribution/distributor.js +220 -0
  8. package/dist/distribution/distributor.js.map +1 -0
  9. package/dist/extractor/git-extractor.d.ts +36 -0
  10. package/dist/extractor/git-extractor.d.ts.map +1 -0
  11. package/dist/extractor/git-extractor.js +198 -0
  12. package/dist/extractor/git-extractor.js.map +1 -0
  13. package/dist/index.d.ts +118 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +313 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/retrieval/retriever.d.ts +33 -0
  18. package/dist/retrieval/retriever.d.ts.map +1 -0
  19. package/dist/retrieval/retriever.js +126 -0
  20. package/dist/retrieval/retriever.js.map +1 -0
  21. package/dist/session/insight-detector.d.ts +10 -0
  22. package/dist/session/insight-detector.d.ts.map +1 -0
  23. package/dist/session/insight-detector.js +87 -0
  24. package/dist/session/insight-detector.js.map +1 -0
  25. package/dist/session/session-manager.d.ts +49 -0
  26. package/dist/session/session-manager.d.ts.map +1 -0
  27. package/dist/session/session-manager.js +228 -0
  28. package/dist/session/session-manager.js.map +1 -0
  29. package/dist/staleness/staleness-engine.d.ts +36 -0
  30. package/dist/staleness/staleness-engine.d.ts.map +1 -0
  31. package/dist/staleness/staleness-engine.js +141 -0
  32. package/dist/staleness/staleness-engine.js.map +1 -0
  33. package/dist/store/database.d.ts +121 -0
  34. package/dist/store/database.d.ts.map +1 -0
  35. package/dist/store/database.js +677 -0
  36. package/dist/store/database.js.map +1 -0
  37. package/dist/store/embeddings.d.ts +21 -0
  38. package/dist/store/embeddings.d.ts.map +1 -0
  39. package/dist/store/embeddings.js +70 -0
  40. package/dist/store/embeddings.js.map +1 -0
  41. package/dist/sync/team-sync.d.ts +77 -0
  42. package/dist/sync/team-sync.d.ts.map +1 -0
  43. package/dist/sync/team-sync.js +230 -0
  44. package/dist/sync/team-sync.js.map +1 -0
  45. package/dist/types.d.ts +223 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +24 -0
  48. package/dist/types.js.map +1 -0
  49. package/package.json +39 -0
@@ -0,0 +1,33 @@
1
+ import type { MemoryDatabase } from '../store/database.js';
2
+ import { EmbeddingProvider } from '../store/embeddings.js';
3
+ import type { RetrievalQuery, ScoredMemory, Memory, TeamLensConfig } from '../types.js';
4
+ /**
5
+ * Multi-signal retriever — ranks memories using:
6
+ * 0.40 × semantic similarity (embedding cosine)
7
+ * 0.25 × file proximity (same directory as scope)
8
+ * 0.20 × recency (newer = higher)
9
+ * 0.15 × confidence (author confidence score)
10
+ * – staleness penalty (stale memories pushed down)
11
+ *
12
+ * Falls back to keyword matching when embeddings aren't available.
13
+ */
14
+ export declare class MemoryRetriever {
15
+ private db;
16
+ private embeddings;
17
+ private config;
18
+ constructor(db: MemoryDatabase, embeddings: EmbeddingProvider, config: TeamLensConfig);
19
+ query(request: RetrievalQuery): Promise<ScoredMemory[]>;
20
+ /** Convenience: get all conventions (no query needed). */
21
+ getConventions(): Promise<Memory[]>;
22
+ /** Convenience: get decisions for a scope. */
23
+ getDecisions(scope?: string): Promise<Memory[]>;
24
+ private scoreSemantic;
25
+ private scoreFileProximity;
26
+ private scoreRecency;
27
+ /**
28
+ * Simple keyword overlap score when embeddings aren't available.
29
+ * Counts how many query words appear in the content.
30
+ */
31
+ private keywordScore;
32
+ }
33
+ //# sourceMappingURL=retriever.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retriever.d.ts","sourceRoot":"","sources":["../../src/retrieval/retriever.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,MAAM,EACN,cAAc,EACf,MAAM,aAAa,CAAC;AAErB;;;;;;;;;GASG;AACH,qBAAa,eAAe;IAExB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,MAAM;gBAFN,EAAE,EAAE,cAAc,EAClB,UAAU,EAAE,iBAAiB,EAC7B,MAAM,EAAE,cAAc;IAG1B,KAAK,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAgE7D,0DAA0D;IACpD,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIzC,8CAA8C;IACxC,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAUrD,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,YAAY;IAQpB;;;OAGG;IACH,OAAO,CAAC,YAAY;CAYrB"}
@@ -0,0 +1,126 @@
1
+ import { EmbeddingProvider } from '../store/embeddings.js';
2
+ /**
3
+ * Multi-signal retriever — ranks memories using:
4
+ * 0.40 × semantic similarity (embedding cosine)
5
+ * 0.25 × file proximity (same directory as scope)
6
+ * 0.20 × recency (newer = higher)
7
+ * 0.15 × confidence (author confidence score)
8
+ * – staleness penalty (stale memories pushed down)
9
+ *
10
+ * Falls back to keyword matching when embeddings aren't available.
11
+ */
12
+ export class MemoryRetriever {
13
+ db;
14
+ embeddings;
15
+ config;
16
+ constructor(db, embeddings, config) {
17
+ this.db = db;
18
+ this.embeddings = embeddings;
19
+ this.config = config;
20
+ }
21
+ async query(request) {
22
+ const limit = request.limit ?? this.config.defaultLimit;
23
+ const includeStale = request.includeStale ?? false;
24
+ // Get candidate memories
25
+ let candidates;
26
+ if (request.tier) {
27
+ candidates = this.db.getMemoriesByTier(request.tier, includeStale);
28
+ }
29
+ else if (request.category) {
30
+ candidates = this.db.getMemoriesByCategory(request.category);
31
+ }
32
+ else {
33
+ candidates = this.db.getAllMemories(includeStale);
34
+ }
35
+ // Further filter by category if both tier and category specified
36
+ if (request.tier && request.category) {
37
+ candidates = candidates.filter((m) => m.category === request.category);
38
+ }
39
+ // Filter by scope (directory prefix)
40
+ if (request.scope) {
41
+ candidates = candidates.filter((m) => m.relatedFiles.some((f) => f.startsWith(request.scope)));
42
+ }
43
+ if (candidates.length === 0)
44
+ return [];
45
+ // Try to get query embedding for semantic scoring
46
+ const queryEmbedding = await this.embeddings.embed(request.query);
47
+ // Score each candidate
48
+ const scored = candidates.map((memory) => {
49
+ const semantic = this.scoreSemantic(memory, request.query, queryEmbedding);
50
+ const fileProximity = this.scoreFileProximity(memory, request.scope);
51
+ const recency = this.scoreRecency(memory);
52
+ const confidence = memory.confidence;
53
+ const stalenessPenalty = memory.staleness * 0.5;
54
+ const score = 0.4 * semantic +
55
+ 0.25 * fileProximity +
56
+ 0.2 * recency +
57
+ 0.15 * confidence -
58
+ stalenessPenalty;
59
+ return {
60
+ memory,
61
+ score,
62
+ breakdown: {
63
+ semantic,
64
+ fileProximity,
65
+ recency,
66
+ confidence,
67
+ stalenessPenalty,
68
+ },
69
+ };
70
+ });
71
+ // Sort by score descending, return top-K
72
+ scored.sort((a, b) => b.score - a.score);
73
+ return scored.slice(0, limit);
74
+ }
75
+ /** Convenience: get all conventions (no query needed). */
76
+ async getConventions() {
77
+ return this.db.getMemoriesByCategory('convention');
78
+ }
79
+ /** Convenience: get decisions for a scope. */
80
+ async getDecisions(scope) {
81
+ const decisions = this.db.getMemoriesByCategory('decision');
82
+ if (!scope)
83
+ return decisions;
84
+ return decisions.filter((m) => m.relatedFiles.some((f) => f.startsWith(scope)));
85
+ }
86
+ // ── Scoring Functions ──
87
+ scoreSemantic(memory, query, queryEmbedding) {
88
+ // If we have embeddings for both, use cosine similarity
89
+ if (queryEmbedding && memory.embedding) {
90
+ return EmbeddingProvider.cosineSimilarity(queryEmbedding, memory.embedding);
91
+ }
92
+ // Fallback: keyword matching
93
+ return this.keywordScore(memory.content, query);
94
+ }
95
+ scoreFileProximity(memory, scope) {
96
+ if (!scope)
97
+ return 0.5; // Neutral when no scope
98
+ const matches = memory.relatedFiles.filter((f) => f.startsWith(scope)).length;
99
+ const total = memory.relatedFiles.length;
100
+ if (total === 0)
101
+ return 0.3;
102
+ return Math.min(matches / total, 1.0);
103
+ }
104
+ scoreRecency(memory) {
105
+ const ageMs = Date.now() - new Date(memory.createdAt).getTime();
106
+ const ageDays = ageMs / (1000 * 60 * 60 * 24);
107
+ // Exponential decay: half-life of 30 days
108
+ return Math.exp(-ageDays / 30);
109
+ }
110
+ /**
111
+ * Simple keyword overlap score when embeddings aren't available.
112
+ * Counts how many query words appear in the content.
113
+ */
114
+ keywordScore(content, query) {
115
+ const queryWords = query
116
+ .toLowerCase()
117
+ .split(/\s+/)
118
+ .filter((w) => w.length > 2);
119
+ const contentLower = content.toLowerCase();
120
+ if (queryWords.length === 0)
121
+ return 0;
122
+ const matches = queryWords.filter((w) => contentLower.includes(w)).length;
123
+ return matches / queryWords.length;
124
+ }
125
+ }
126
+ //# sourceMappingURL=retriever.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retriever.js","sourceRoot":"","sources":["../../src/retrieval/retriever.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { InsightType, MemoryCategory } from '../types.js';
2
+ export declare class InsightDetector {
3
+ /** Detect the most likely insight type from content. */
4
+ detect(content: string): InsightType;
5
+ /** Score confidence in the detected type (0.0 - 1.0). */
6
+ scoreConfidence(content: string, type: InsightType): number;
7
+ /** Convert InsightType to MemoryCategory. */
8
+ toCategory(type: InsightType): MemoryCategory;
9
+ }
10
+ //# sourceMappingURL=insight-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insight-detector.d.ts","sourceRoot":"","sources":["../../src/session/insight-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAkD/D,qBAAa,eAAe;IAC1B,wDAAwD;IACxD,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW;IAoBpC,yDAAyD;IACzD,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM;IAkB3D,6CAA6C;IAC7C,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,cAAc;CAG9C"}
@@ -0,0 +1,87 @@
1
+ const PATTERNS = {
2
+ gotcha: [
3
+ /\b(gotcha|pitfall|trap|caveat|watch out|careful|beware|silently|unexpect|quirk|subtle|hidden)\b/i,
4
+ /\b(doesn'?t work|broke|breaking|fail|error when|crash|bug|issue with)\b/i,
5
+ /\b(actually|turns out|it seems|surprisingly|counterintuitive)\b/i,
6
+ ],
7
+ convention: [
8
+ /\b(convention|naming|style|pattern|always use|never use|prefer|standard|consistent)\b/i,
9
+ /\b(format|lint|eslint|prettier|coding style|best practice)\b/i,
10
+ /\b(should be|must be|required to|expected to)\b/i,
11
+ ],
12
+ architecture: [
13
+ /\b(architect|structure|design|pattern|module|component|layer|service|system)\b/i,
14
+ /\b(split|extract|decouple|separate|organize|restructure)\b/i,
15
+ /\b(data flow|pipeline|middleware|handler|controller|provider)\b/i,
16
+ ],
17
+ dependency: [
18
+ /\b(depend|package|library|version|npm|import|require|install|upgrade)\b/i,
19
+ /\b(compatible|incompatible|peer|resolution|conflict)\b/i,
20
+ /\b(deprecated|removed|replaced|alternative)\b/i,
21
+ ],
22
+ decision: [
23
+ /\b(decided|chose|picked|selected|went with|opted for|reason)\b/i,
24
+ /\b(because|instead of|trade-?off|pros? and cons?|alternative)\b/i,
25
+ /\b(approach|strategy|solution|design decision)\b/i,
26
+ ],
27
+ correction: [
28
+ /\b(wrong|incorrect|mistake|fix|correct|should not|don'?t|avoid|never)\b/i,
29
+ /\b(deprecated|outdated|stale|obsolete|removed)\b/i,
30
+ /\b(instead|replace|update|change to)\b/i,
31
+ ],
32
+ discovery: [
33
+ /\b(found|discover|learn|realize|notice|understand|figure out)\b/i,
34
+ /\b(how .+ works|works by|implemented as|under the hood)\b/i,
35
+ /\b(interesting|notable|important|key insight)\b/i,
36
+ ],
37
+ };
38
+ const INSIGHT_TO_CATEGORY = {
39
+ gotcha: 'gotcha',
40
+ convention: 'convention',
41
+ architecture: 'architecture',
42
+ dependency: 'dependency',
43
+ decision: 'decision',
44
+ correction: 'correction',
45
+ discovery: 'discovery',
46
+ };
47
+ export class InsightDetector {
48
+ /** Detect the most likely insight type from content. */
49
+ detect(content) {
50
+ let bestType = 'discovery';
51
+ let bestScore = 0;
52
+ for (const [type, patterns] of Object.entries(PATTERNS)) {
53
+ let score = 0;
54
+ for (const pattern of patterns) {
55
+ if (pattern.test(content)) {
56
+ score++;
57
+ }
58
+ }
59
+ if (score > bestScore) {
60
+ bestScore = score;
61
+ bestType = type;
62
+ }
63
+ }
64
+ return bestType;
65
+ }
66
+ /** Score confidence in the detected type (0.0 - 1.0). */
67
+ scoreConfidence(content, type) {
68
+ const patterns = PATTERNS[type];
69
+ if (!patterns)
70
+ return 0.5;
71
+ let matches = 0;
72
+ for (const pattern of patterns) {
73
+ if (pattern.test(content))
74
+ matches++;
75
+ }
76
+ // Base confidence from pattern matches
77
+ const matchRatio = matches / patterns.length;
78
+ // Boost for longer content (more context = more confident)
79
+ const lengthBoost = Math.min(content.length / 200, 0.2);
80
+ return Math.min(0.5 + matchRatio * 0.4 + lengthBoost, 1.0);
81
+ }
82
+ /** Convert InsightType to MemoryCategory. */
83
+ toCategory(type) {
84
+ return INSIGHT_TO_CATEGORY[type];
85
+ }
86
+ }
87
+ //# sourceMappingURL=insight-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insight-detector.js","sourceRoot":"","sources":["../../src/session/insight-detector.ts"],"names":[],"mappings":"AAEA,MAAM,QAAQ,GAAkC;IAC9C,MAAM,EAAE;QACN,kGAAkG;QAClG,0EAA0E;QAC1E,kEAAkE;KACnE;IACD,UAAU,EAAE;QACV,wFAAwF;QACxF,+DAA+D;QAC/D,kDAAkD;KACnD;IACD,YAAY,EAAE;QACZ,iFAAiF;QACjF,6DAA6D;QAC7D,kEAAkE;KACnE;IACD,UAAU,EAAE;QACV,0EAA0E;QAC1E,yDAAyD;QACzD,gDAAgD;KACjD;IACD,QAAQ,EAAE;QACR,iEAAiE;QACjE,kEAAkE;QAClE,mDAAmD;KACpD;IACD,UAAU,EAAE;QACV,0EAA0E;QAC1E,mDAAmD;QACnD,yCAAyC;KAC1C;IACD,SAAS,EAAE;QACT,kEAAkE;QAClE,4DAA4D;QAC5D,kDAAkD;KACnD;CACF,CAAC;AAEF,MAAM,mBAAmB,GAAwC;IAC/D,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,YAAY;IACxB,YAAY,EAAE,cAAc;IAC5B,UAAU,EAAE,YAAY;IACxB,QAAQ,EAAE,UAAU;IACpB,UAAU,EAAE,YAAY;IACxB,SAAS,EAAE,WAAW;CACvB,CAAC;AAEF,MAAM,OAAO,eAAe;IAC1B,wDAAwD;IACxD,MAAM,CAAC,OAAe;QACpB,IAAI,QAAQ,GAAgB,WAAW,CAAC;QACxC,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAA8B,EAAE,CAAC;YACrF,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC1B,KAAK,EAAE,CAAC;gBACV,CAAC;YACH,CAAC;YACD,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;gBACtB,SAAS,GAAG,KAAK,CAAC;gBAClB,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,yDAAyD;IACzD,eAAe,CAAC,OAAe,EAAE,IAAiB;QAChD,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ;YAAE,OAAO,GAAG,CAAC;QAE1B,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;gBAAE,OAAO,EAAE,CAAC;QACvC,CAAC;QAED,uCAAuC;QACvC,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC;QAE7C,2DAA2D;QAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC;QAExD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,UAAU,GAAG,GAAG,GAAG,WAAW,EAAE,GAAG,CAAC,CAAC;IAC7D,CAAC;IAED,6CAA6C;IAC7C,UAAU,CAAC,IAAiB;QAC1B,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,49 @@
1
+ import type { MemoryDatabase } from '../store/database.js';
2
+ import type { TeamLensConfig, Session, ActivityType, Memory } from '../types.js';
3
+ import type { TeamSync } from '../sync/team-sync.js';
4
+ import type { EmbeddingProvider } from '../store/embeddings.js';
5
+ export declare class SessionManager {
6
+ private db;
7
+ private config;
8
+ private teamSync;
9
+ private embeddings;
10
+ private currentSessionId;
11
+ private sessionJustCreated;
12
+ private insightDetector;
13
+ constructor(db: MemoryDatabase, config: TeamLensConfig, teamSync: TeamSync, embeddings: EmbeddingProvider);
14
+ /** Get or create an active session. Auto-session pattern. */
15
+ getOrCreateSession(toolName?: string): Session;
16
+ /** Check if the last getOrCreateSession call created a new session. */
17
+ wasSessionJustCreated(): boolean;
18
+ /** Explicitly start a session with task context. */
19
+ startSession(task?: string, toolName?: string): Session;
20
+ /** End a session with optional summary. */
21
+ endSession(sessionId?: string, summary?: string): Session | null;
22
+ /** Share an insight with the team. Auto-detects type, auto-creates session if needed. */
23
+ shareInsight(content: string, relatedFiles?: string[], tags?: string[]): Promise<{
24
+ memoryId: string;
25
+ insightType: string;
26
+ sessionId: string;
27
+ }>;
28
+ /** Log an activity event. Auto-creates session if needed. */
29
+ logActivity(type: ActivityType, description?: string, files?: string[]): {
30
+ eventId: string;
31
+ sessionId: string;
32
+ };
33
+ /** Add a file to the session's files_touched list. */
34
+ trackFile(sessionId: string, filePath: string): void;
35
+ /** Close stale sessions that have been active too long. */
36
+ cleanupStaleSessions(timeoutMinutes?: number): number;
37
+ /** Get the current active session. */
38
+ getActiveSession(): Session | null;
39
+ /** Get team context for injection at session start. */
40
+ getTeamContext(limit?: number): Memory[];
41
+ /**
42
+ * Ingest hook events from .teamlens/hooks.jsonl into the database.
43
+ * Called by the MCP server before each tool handler to pick up
44
+ * activity logged by Claude Code PostToolUse hooks.
45
+ */
46
+ ingestHookEvents(repoPath: string): number;
47
+ private createSession;
48
+ }
49
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAiB,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEhG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,qBAAa,cAAc;IAMvB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,UAAU;IARpB,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,eAAe,CAAkB;gBAG/B,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,iBAAiB;IAKvC,6DAA6D;IAC7D,kBAAkB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAgB9C,uEAAuE;IACvE,qBAAqB,IAAI,OAAO;IAIhC,oDAAoD;IACpD,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAavD,2CAA2C;IAC3C,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAahE,yFAAyF;IACnF,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,YAAY,GAAE,MAAM,EAAO,EAC3B,IAAI,GAAE,MAAM,EAAO,GAClB,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAqDxE,6DAA6D;IAC7D,WAAW,CACT,IAAI,EAAE,YAAY,EAClB,WAAW,GAAE,MAAW,EACxB,KAAK,GAAE,MAAM,EAAO,GACnB;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAyBzC,sDAAsD;IACtD,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYpD,2DAA2D;IAC3D,oBAAoB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM;IAKrD,sCAAsC;IACtC,gBAAgB,IAAI,OAAO,GAAG,IAAI;IAQlC,uDAAuD;IACvD,cAAc,CAAC,KAAK,SAAK,GAAG,MAAM,EAAE;IAIpC;;;;OAIG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAuD1C,OAAO,CAAC,aAAa;CA0BtB"}
@@ -0,0 +1,228 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { InsightDetector } from './insight-detector.js';
5
+ export class SessionManager {
6
+ db;
7
+ config;
8
+ teamSync;
9
+ embeddings;
10
+ currentSessionId = null;
11
+ sessionJustCreated = false;
12
+ insightDetector;
13
+ constructor(db, config, teamSync, embeddings) {
14
+ this.db = db;
15
+ this.config = config;
16
+ this.teamSync = teamSync;
17
+ this.embeddings = embeddings;
18
+ this.insightDetector = new InsightDetector();
19
+ }
20
+ /** Get or create an active session. Auto-session pattern. */
21
+ getOrCreateSession(toolName) {
22
+ // Check for existing active session
23
+ const developer = this.config.developer !== 'unknown' ? this.config.developer : this.config.author;
24
+ const existing = this.db.getActiveSession(developer);
25
+ if (existing) {
26
+ this.currentSessionId = existing.id;
27
+ this.sessionJustCreated = false;
28
+ return existing;
29
+ }
30
+ // Create new session
31
+ const session = this.createSession(toolName);
32
+ this.sessionJustCreated = true;
33
+ return session;
34
+ }
35
+ /** Check if the last getOrCreateSession call created a new session. */
36
+ wasSessionJustCreated() {
37
+ return this.sessionJustCreated;
38
+ }
39
+ /** Explicitly start a session with task context. */
40
+ startSession(task, toolName) {
41
+ const developer = this.config.developer !== 'unknown' ? this.config.developer : this.config.author;
42
+ // Close any existing active session
43
+ const existing = this.db.getActiveSession(developer);
44
+ if (existing) {
45
+ this.db.closeSession(existing.id);
46
+ }
47
+ const session = this.createSession(toolName, task);
48
+ return session;
49
+ }
50
+ /** End a session with optional summary. */
51
+ endSession(sessionId, summary) {
52
+ const id = sessionId ?? this.currentSessionId;
53
+ if (!id)
54
+ return null;
55
+ this.db.closeSession(id, summary);
56
+ if (id === this.currentSessionId) {
57
+ this.currentSessionId = null;
58
+ }
59
+ return this.db.getSession(id);
60
+ }
61
+ /** Share an insight with the team. Auto-detects type, auto-creates session if needed. */
62
+ async shareInsight(content, relatedFiles = [], tags = []) {
63
+ // Ensure session exists
64
+ const session = this.getOrCreateSession();
65
+ // Auto-detect insight type
66
+ const insightType = this.insightDetector.detect(content);
67
+ const category = this.insightDetector.toCategory(insightType);
68
+ const confidence = this.insightDetector.scoreConfidence(content, insightType);
69
+ // Store as team memory with session context
70
+ const memory = this.db.insertMemory({
71
+ content,
72
+ category,
73
+ relatedFiles,
74
+ tags: [...tags, insightType],
75
+ confidence,
76
+ commitSha: null,
77
+ }, this.config.developer !== 'unknown' ? this.config.developer : this.config.author, 'team', session.id);
78
+ // Generate embedding
79
+ const embedding = await this.embeddings.embed(content);
80
+ if (embedding) {
81
+ this.db.updateEmbedding(memory.id, embedding);
82
+ }
83
+ // Update session insight count
84
+ this.db.updateSession(session.id, {
85
+ insightCount: session.insightCount + 1,
86
+ });
87
+ // Export to team.jsonl (append-only, not full rewrite)
88
+ this.teamSync.appendMemory(memory);
89
+ // Auto-commit and push so teammates get it immediately
90
+ this.teamSync.autoCommitAndPush();
91
+ // Track related files
92
+ for (const file of relatedFiles) {
93
+ this.trackFile(session.id, file);
94
+ }
95
+ return {
96
+ memoryId: memory.id,
97
+ insightType,
98
+ sessionId: session.id,
99
+ };
100
+ }
101
+ /** Log an activity event. Auto-creates session if needed. */
102
+ logActivity(type, description = '', files = []) {
103
+ const session = this.getOrCreateSession();
104
+ const event = {
105
+ id: randomUUID(),
106
+ sessionId: session.id,
107
+ type,
108
+ description,
109
+ files,
110
+ timestamp: new Date().toISOString(),
111
+ };
112
+ this.db.insertActivityEvent(event);
113
+ // Track files
114
+ for (const file of files) {
115
+ this.trackFile(session.id, file);
116
+ }
117
+ return {
118
+ eventId: event.id,
119
+ sessionId: session.id,
120
+ };
121
+ }
122
+ /** Add a file to the session's files_touched list. */
123
+ trackFile(sessionId, filePath) {
124
+ const session = this.db.getSession(sessionId);
125
+ if (!session)
126
+ return;
127
+ if (!session.filesTouched.includes(filePath)) {
128
+ session.filesTouched.push(filePath);
129
+ this.db.updateSession(sessionId, {
130
+ filesTouched: session.filesTouched,
131
+ });
132
+ }
133
+ }
134
+ /** Close stale sessions that have been active too long. */
135
+ cleanupStaleSessions(timeoutMinutes) {
136
+ const timeout = timeoutMinutes ?? this.config.sessionTimeoutMinutes;
137
+ return this.db.cleanupStaleSessions(timeout);
138
+ }
139
+ /** Get the current active session. */
140
+ getActiveSession() {
141
+ if (this.currentSessionId) {
142
+ return this.db.getSession(this.currentSessionId);
143
+ }
144
+ const developer = this.config.developer !== 'unknown' ? this.config.developer : this.config.author;
145
+ return this.db.getActiveSession(developer);
146
+ }
147
+ /** Get team context for injection at session start. */
148
+ getTeamContext(limit = 10) {
149
+ return this.db.getRecentInsights(limit);
150
+ }
151
+ /**
152
+ * Ingest hook events from .teamlens/hooks.jsonl into the database.
153
+ * Called by the MCP server before each tool handler to pick up
154
+ * activity logged by Claude Code PostToolUse hooks.
155
+ */
156
+ ingestHookEvents(repoPath) {
157
+ const hooksFile = path.join(repoPath, this.config.storageDir, 'hooks.jsonl');
158
+ if (!fs.existsSync(hooksFile))
159
+ return 0;
160
+ const content = fs.readFileSync(hooksFile, 'utf-8').trim();
161
+ if (!content)
162
+ return 0;
163
+ const lines = content.split('\n').filter(Boolean);
164
+ if (lines.length === 0)
165
+ return 0;
166
+ const session = this.getOrCreateSession();
167
+ let ingested = 0;
168
+ for (const line of lines) {
169
+ try {
170
+ const hookEvent = JSON.parse(line);
171
+ const event = {
172
+ id: randomUUID(),
173
+ sessionId: session.id,
174
+ type: hookEvent.type ?? 'other',
175
+ description: hookEvent.description ?? hookEvent.tool ?? '',
176
+ files: hookEvent.files ?? [],
177
+ timestamp: hookEvent.timestamp ?? new Date().toISOString(),
178
+ };
179
+ this.db.insertActivityEvent(event);
180
+ // Track files
181
+ for (const file of event.files) {
182
+ this.trackFile(session.id, file);
183
+ }
184
+ ingested++;
185
+ }
186
+ catch {
187
+ // Skip malformed lines
188
+ }
189
+ }
190
+ // Update session activity count
191
+ if (ingested > 0) {
192
+ const updated = this.db.getSession(session.id);
193
+ if (updated) {
194
+ this.db.updateSession(session.id, {
195
+ activityCount: updated.activityCount + ingested,
196
+ });
197
+ }
198
+ }
199
+ // Clear the hooks file after ingestion
200
+ fs.writeFileSync(hooksFile, '');
201
+ return ingested;
202
+ }
203
+ // ── Private ──
204
+ createSession(toolName, task) {
205
+ const developer = this.config.developer !== 'unknown' ? this.config.developer : this.config.author;
206
+ const session = {
207
+ id: randomUUID(),
208
+ developer,
209
+ task: task ?? '',
210
+ status: 'active',
211
+ toolName: toolName ?? 'unknown',
212
+ startedAt: new Date().toISOString(),
213
+ endedAt: null,
214
+ durationSeconds: null,
215
+ filesTouched: [],
216
+ summary: null,
217
+ insightCount: 0,
218
+ activityCount: 0,
219
+ duplicatesPrevented: 0,
220
+ };
221
+ this.db.insertSession(session);
222
+ this.currentSessionId = session.id;
223
+ // Cleanup any stale sessions
224
+ this.cleanupStaleSessions();
225
+ return session;
226
+ }
227
+ }
228
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAIxD,MAAM,OAAO,cAAc;IAMf;IACA;IACA;IACA;IARF,gBAAgB,GAAkB,IAAI,CAAC;IACvC,kBAAkB,GAAG,KAAK,CAAC;IAC3B,eAAe,CAAkB;IAEzC,YACU,EAAkB,EAClB,MAAsB,EACtB,QAAkB,EAClB,UAA6B;QAH7B,OAAE,GAAF,EAAE,CAAgB;QAClB,WAAM,GAAN,MAAM,CAAgB;QACtB,aAAQ,GAAR,QAAQ,CAAU;QAClB,eAAU,GAAV,UAAU,CAAmB;QAErC,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IAC/C,CAAC;IAED,6DAA6D;IAC7D,kBAAkB,CAAC,QAAiB;QAClC,oCAAoC;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QACnG,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;YAChC,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,qBAAqB;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,uEAAuE;IACvE,qBAAqB;QACnB,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACjC,CAAC;IAED,oDAAoD;IACpD,YAAY,CAAC,IAAa,EAAE,QAAiB;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAEnG,oCAAoC;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACnD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,2CAA2C;IAC3C,UAAU,CAAC,SAAkB,EAAE,OAAgB;QAC7C,MAAM,EAAE,GAAG,SAAS,IAAI,IAAI,CAAC,gBAAgB,CAAC;QAC9C,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAErB,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAElC,IAAI,EAAE,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACjC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC/B,CAAC;QAED,OAAO,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,yFAAyF;IACzF,KAAK,CAAC,YAAY,CAChB,OAAe,EACf,eAAyB,EAAE,EAC3B,OAAiB,EAAE;QAEnB,wBAAwB;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAE1C,2BAA2B;QAC3B,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAE9E,4CAA4C;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,YAAY,CACjC;YACE,OAAO;YACP,QAAQ;YACR,YAAY;YACZ,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,WAAW,CAAC;YAC5B,UAAU;YACV,SAAS,EAAE,IAAI;SAChB,EACD,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAChF,MAAM,EACN,OAAO,CAAC,EAAE,CACX,CAAC;QAEF,qBAAqB;QACrB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACvD,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QAChD,CAAC;QAED,+BAA+B;QAC/B,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE;YAChC,YAAY,EAAE,OAAO,CAAC,YAAY,GAAG,CAAC;SACvC,CAAC,CAAC;QAEH,uDAAuD;QACvD,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAEnC,uDAAuD;QACvD,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,CAAC;QAElC,sBAAsB;QACtB,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;YAChC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,WAAW;YACX,SAAS,EAAE,OAAO,CAAC,EAAE;SACtB,CAAC;IACJ,CAAC;IAED,6DAA6D;IAC7D,WAAW,CACT,IAAkB,EAClB,cAAsB,EAAE,EACxB,QAAkB,EAAE;QAEpB,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAE1C,MAAM,KAAK,GAAkB;YAC3B,EAAE,EAAE,UAAU,EAAE;YAChB,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,IAAI;YACJ,WAAW;YACX,KAAK;YACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAEnC,cAAc;QACd,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC;QAED,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,EAAE;YACjB,SAAS,EAAE,OAAO,CAAC,EAAE;SACtB,CAAC;IACJ,CAAC;IAED,sDAAsD;IACtD,SAAS,CAAC,SAAiB,EAAE,QAAgB;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7C,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE;gBAC/B,YAAY,EAAE,OAAO,CAAC,YAAY;aACnC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,oBAAoB,CAAC,cAAuB;QAC1C,MAAM,OAAO,GAAG,cAAc,IAAI,IAAI,CAAC,MAAM,CAAC,qBAAqB,CAAC;QACpE,OAAO,IAAI,CAAC,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,sCAAsC;IACtC,gBAAgB;QACd,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACnD,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QACnG,OAAO,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC;IAED,uDAAuD;IACvD,cAAc,CAAC,KAAK,GAAG,EAAE;QACvB,OAAO,IAAI,CAAC,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACH,gBAAgB,CAAC,QAAgB;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QAC7E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,CAAC,CAAC;QAExC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3D,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC;QAEvB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAEjC,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC1C,IAAI,QAAQ,GAAG,CAAC,CAAC;QAEjB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACnC,MAAM,KAAK,GAAkB;oBAC3B,EAAE,EAAE,UAAU,EAAE;oBAChB,SAAS,EAAE,OAAO,CAAC,EAAE;oBACrB,IAAI,EAAG,SAAS,CAAC,IAAqB,IAAI,OAAO;oBACjD,WAAW,EAAE,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,IAAI,IAAI,EAAE;oBAC1D,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,EAAE;oBAC5B,SAAS,EAAE,SAAS,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBAC3D,CAAC;gBACF,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;gBAEnC,cAAc;gBACd,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAC/B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;gBACnC,CAAC;gBAED,QAAQ,EAAE,CAAC;YACb,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC/C,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE;oBAChC,aAAa,EAAE,OAAO,CAAC,aAAa,GAAG,QAAQ;iBAChD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,uCAAuC;QACvC,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAEhC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,gBAAgB;IAER,aAAa,CAAC,QAAiB,EAAE,IAAa;QACpD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QACnG,MAAM,OAAO,GAAY;YACvB,EAAE,EAAE,UAAU,EAAE;YAChB,SAAS;YACT,IAAI,EAAE,IAAI,IAAI,EAAE;YAChB,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,QAAQ,IAAI,SAAS;YAC/B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,IAAI;YACb,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,EAAE;YAChB,OAAO,EAAE,IAAI;YACb,YAAY,EAAE,CAAC;YACf,aAAa,EAAE,CAAC;YAChB,mBAAmB,EAAE,CAAC;SACvB,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,EAAE,CAAC;QAEnC,6BAA6B;QAC7B,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,36 @@
1
+ import type { MemoryDatabase } from '../store/database.js';
2
+ import type { GitExtractor } from '../extractor/git-extractor.js';
3
+ import type { StalenessCheck, Memory } from '../types.js';
4
+ /**
5
+ * Staleness Engine — auto-invalidates memories when referenced files change.
6
+ *
7
+ * On each git event:
8
+ * 1. Get changed files from diff
9
+ * 2. Find memories that reference those files
10
+ * 3. Score staleness based on change magnitude
11
+ * 4. Update memory staleness scores
12
+ *
13
+ * Stale memories are downranked in retrieval, not deleted.
14
+ */
15
+ export declare class StalenessEngine {
16
+ private db;
17
+ private git;
18
+ constructor(db: MemoryDatabase, git: GitExtractor);
19
+ /** Check all memories against current file states. Returns list of changes made. */
20
+ checkAll(): Promise<StalenessCheck[]>;
21
+ /** Check a single memory against its referenced files. */
22
+ checkMemory(memory: Memory): Promise<StalenessCheck[]>;
23
+ /** Process a set of changed files (e.g., from a git hook). */
24
+ processChangedFiles(changedFiles: string[]): Promise<StalenessCheck[]>;
25
+ private applyStale;
26
+ /**
27
+ * Estimate how much a file change should affect staleness.
28
+ *
29
+ * Heuristic based on file name patterns:
30
+ * - Config files changing → high impact (0.7)
31
+ * - Test files changing → low impact (0.1)
32
+ * - Source files → medium (0.3–0.5)
33
+ */
34
+ private estimateChangeMagnitude;
35
+ }
36
+ //# sourceMappingURL=staleness-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staleness-engine.d.ts","sourceRoot":"","sources":["../../src/staleness/staleness-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IAExB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,GAAG;gBADH,EAAE,EAAE,cAAc,EAClB,GAAG,EAAE,YAAY;IAG3B,oFAAoF;IAC9E,QAAQ,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAY3C,0DAA0D;IACpD,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA4C5D,8DAA8D;IACxD,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAqC5E,OAAO,CAAC,UAAU;IAoBlB;;;;;;;OAOG;YACW,uBAAuB;CAiCtC"}