@blamechris/repo-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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +85 -0
  3. package/dist/cache/gc.d.ts +14 -0
  4. package/dist/cache/gc.d.ts.map +1 -0
  5. package/dist/cache/gc.js +75 -0
  6. package/dist/cache/gc.js.map +1 -0
  7. package/dist/cache/hash.d.ts +10 -0
  8. package/dist/cache/hash.d.ts.map +1 -0
  9. package/dist/cache/hash.js +22 -0
  10. package/dist/cache/hash.js.map +1 -0
  11. package/dist/cache/invalidation.d.ts +29 -0
  12. package/dist/cache/invalidation.d.ts.map +1 -0
  13. package/dist/cache/invalidation.js +58 -0
  14. package/dist/cache/invalidation.js.map +1 -0
  15. package/dist/cache/ranking.d.ts +57 -0
  16. package/dist/cache/ranking.d.ts.map +1 -0
  17. package/dist/cache/ranking.js +196 -0
  18. package/dist/cache/ranking.js.map +1 -0
  19. package/dist/cache/store.d.ts +16 -0
  20. package/dist/cache/store.d.ts.map +1 -0
  21. package/dist/cache/store.js +70 -0
  22. package/dist/cache/store.js.map +1 -0
  23. package/dist/graph/dependency-graph.d.ts +26 -0
  24. package/dist/graph/dependency-graph.d.ts.map +1 -0
  25. package/dist/graph/dependency-graph.js +131 -0
  26. package/dist/graph/dependency-graph.js.map +1 -0
  27. package/dist/indexer/diff-analyzer.d.ts +8 -0
  28. package/dist/indexer/diff-analyzer.d.ts.map +1 -0
  29. package/dist/indexer/diff-analyzer.js +95 -0
  30. package/dist/indexer/diff-analyzer.js.map +1 -0
  31. package/dist/indexer/imports.d.ts +3 -0
  32. package/dist/indexer/imports.d.ts.map +1 -0
  33. package/dist/indexer/imports.js +123 -0
  34. package/dist/indexer/imports.js.map +1 -0
  35. package/dist/indexer/project-map.d.ts +20 -0
  36. package/dist/indexer/project-map.d.ts.map +1 -0
  37. package/dist/indexer/project-map.js +120 -0
  38. package/dist/indexer/project-map.js.map +1 -0
  39. package/dist/indexer/scanner.d.ts +7 -0
  40. package/dist/indexer/scanner.d.ts.map +1 -0
  41. package/dist/indexer/scanner.js +114 -0
  42. package/dist/indexer/scanner.js.map +1 -0
  43. package/dist/indexer/smart-summarizer.d.ts +6 -0
  44. package/dist/indexer/smart-summarizer.d.ts.map +1 -0
  45. package/dist/indexer/smart-summarizer.js +26 -0
  46. package/dist/indexer/smart-summarizer.js.map +1 -0
  47. package/dist/indexer/summarizer.d.ts +3 -0
  48. package/dist/indexer/summarizer.d.ts.map +1 -0
  49. package/dist/indexer/summarizer.js +145 -0
  50. package/dist/indexer/summarizer.js.map +1 -0
  51. package/dist/memory/session.d.ts +18 -0
  52. package/dist/memory/session.d.ts.map +1 -0
  53. package/dist/memory/session.js +75 -0
  54. package/dist/memory/session.js.map +1 -0
  55. package/dist/memory/task.d.ts +35 -0
  56. package/dist/memory/task.d.ts.map +1 -0
  57. package/dist/memory/task.js +120 -0
  58. package/dist/memory/task.js.map +1 -0
  59. package/dist/persistence/db.d.ts +4 -0
  60. package/dist/persistence/db.d.ts.map +1 -0
  61. package/dist/persistence/db.js +146 -0
  62. package/dist/persistence/db.js.map +1 -0
  63. package/dist/server.d.ts +3 -0
  64. package/dist/server.d.ts.map +1 -0
  65. package/dist/server.js +197 -0
  66. package/dist/server.js.map +1 -0
  67. package/dist/telemetry/tracker.d.ts +40 -0
  68. package/dist/telemetry/tracker.d.ts.map +1 -0
  69. package/dist/telemetry/tracker.js +136 -0
  70. package/dist/telemetry/tracker.js.map +1 -0
  71. package/dist/tools/force-reread.d.ts +9 -0
  72. package/dist/tools/force-reread.d.ts.map +1 -0
  73. package/dist/tools/force-reread.js +17 -0
  74. package/dist/tools/force-reread.js.map +1 -0
  75. package/dist/tools/get-changed-files.d.ts +8 -0
  76. package/dist/tools/get-changed-files.d.ts.map +1 -0
  77. package/dist/tools/get-changed-files.js +61 -0
  78. package/dist/tools/get-changed-files.js.map +1 -0
  79. package/dist/tools/get-dependency-graph.d.ts +17 -0
  80. package/dist/tools/get-dependency-graph.d.ts.map +1 -0
  81. package/dist/tools/get-dependency-graph.js +88 -0
  82. package/dist/tools/get-dependency-graph.js.map +1 -0
  83. package/dist/tools/get-file-summary.d.ts +12 -0
  84. package/dist/tools/get-file-summary.d.ts.map +1 -0
  85. package/dist/tools/get-file-summary.js +53 -0
  86. package/dist/tools/get-file-summary.js.map +1 -0
  87. package/dist/tools/get-project-map.d.ts +3 -0
  88. package/dist/tools/get-project-map.d.ts.map +1 -0
  89. package/dist/tools/get-project-map.js +5 -0
  90. package/dist/tools/get-project-map.js.map +1 -0
  91. package/dist/tools/get-token-report.d.ts +16 -0
  92. package/dist/tools/get-token-report.d.ts.map +1 -0
  93. package/dist/tools/get-token-report.js +44 -0
  94. package/dist/tools/get-token-report.js.map +1 -0
  95. package/dist/tools/invalidate.d.ts +5 -0
  96. package/dist/tools/invalidate.d.ts.map +1 -0
  97. package/dist/tools/invalidate.js +19 -0
  98. package/dist/tools/invalidate.js.map +1 -0
  99. package/dist/tools/task-context.d.ts +18 -0
  100. package/dist/tools/task-context.d.ts.map +1 -0
  101. package/dist/tools/task-context.js +28 -0
  102. package/dist/tools/task-context.js.map +1 -0
  103. package/dist/types.d.ts +21 -0
  104. package/dist/types.d.ts.map +1 -0
  105. package/dist/types.js +2 -0
  106. package/dist/types.js.map +1 -0
  107. package/dist/utils/validate-path.d.ts +10 -0
  108. package/dist/utils/validate-path.d.ts.map +1 -0
  109. package/dist/utils/validate-path.js +22 -0
  110. package/dist/utils/validate-path.js.map +1 -0
  111. package/package.json +62 -0
@@ -0,0 +1,146 @@
1
+ import Database from 'better-sqlite3';
2
+ import { mkdirSync, existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ const REPO_MEMORY_DIR = '.repo-memory';
5
+ const DB_FILENAME = 'cache.db';
6
+ let instance = null;
7
+ let instancePath = null;
8
+ const MIGRATIONS = [
9
+ {
10
+ version: 1,
11
+ up: (db) => {
12
+ db.exec(`
13
+ CREATE TABLE IF NOT EXISTS files (
14
+ path TEXT PRIMARY KEY,
15
+ hash TEXT NOT NULL,
16
+ last_checked INTEGER NOT NULL,
17
+ summary_json TEXT
18
+ );
19
+ `);
20
+ },
21
+ },
22
+ {
23
+ version: 2,
24
+ up: (db) => {
25
+ db.exec(`
26
+ CREATE TABLE IF NOT EXISTS tasks (
27
+ id TEXT PRIMARY KEY,
28
+ name TEXT NOT NULL,
29
+ state TEXT NOT NULL DEFAULT 'created',
30
+ created_at INTEGER NOT NULL,
31
+ updated_at INTEGER NOT NULL,
32
+ session_id TEXT,
33
+ metadata_json TEXT
34
+ );
35
+
36
+ CREATE TABLE IF NOT EXISTS task_files (
37
+ task_id TEXT NOT NULL,
38
+ file_path TEXT NOT NULL,
39
+ status TEXT NOT NULL DEFAULT 'explored',
40
+ notes TEXT,
41
+ explored_at INTEGER NOT NULL,
42
+ PRIMARY KEY (task_id, file_path),
43
+ FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE
44
+ );
45
+ `);
46
+ },
47
+ },
48
+ {
49
+ version: 3,
50
+ up: (db) => {
51
+ db.exec(`
52
+ CREATE TABLE IF NOT EXISTS imports (
53
+ source TEXT NOT NULL,
54
+ target TEXT NOT NULL,
55
+ specifiers TEXT NOT NULL,
56
+ import_type TEXT NOT NULL,
57
+ PRIMARY KEY (source, target, import_type)
58
+ );
59
+ CREATE INDEX IF NOT EXISTS idx_imports_target ON imports (target);
60
+ `);
61
+ },
62
+ },
63
+ {
64
+ version: 4,
65
+ up: (db) => {
66
+ db.exec(`
67
+ CREATE TABLE IF NOT EXISTS telemetry (
68
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
69
+ timestamp INTEGER NOT NULL,
70
+ event_type TEXT NOT NULL,
71
+ file_path TEXT,
72
+ tokens_estimated INTEGER,
73
+ metadata_json TEXT
74
+ );
75
+ CREATE INDEX IF NOT EXISTS idx_telemetry_type ON telemetry (event_type);
76
+ CREATE INDEX IF NOT EXISTS idx_telemetry_timestamp ON telemetry (timestamp);
77
+ `);
78
+ },
79
+ },
80
+ {
81
+ version: 5,
82
+ up: (db) => {
83
+ db.exec(`
84
+ CREATE TABLE IF NOT EXISTS sessions (
85
+ id TEXT PRIMARY KEY,
86
+ started_at INTEGER NOT NULL,
87
+ ended_at INTEGER,
88
+ metadata_json TEXT
89
+ );
90
+ `);
91
+ },
92
+ },
93
+ ];
94
+ function runMigrations(db) {
95
+ db.exec(`
96
+ CREATE TABLE IF NOT EXISTS schema_version (
97
+ version INTEGER PRIMARY KEY,
98
+ applied_at INTEGER NOT NULL
99
+ );
100
+ `);
101
+ const applied = db
102
+ .prepare('SELECT version FROM schema_version ORDER BY version DESC LIMIT 1')
103
+ .get();
104
+ const currentVersion = applied?.version ?? 0;
105
+ const sortedMigrations = [...MIGRATIONS].sort((a, b) => a.version - b.version);
106
+ const insertVersion = db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)');
107
+ const applyMigrations = db.transaction(() => {
108
+ for (const migration of sortedMigrations) {
109
+ if (migration.version > currentVersion) {
110
+ migration.up(db);
111
+ insertVersion.run(migration.version, Date.now());
112
+ }
113
+ }
114
+ });
115
+ applyMigrations();
116
+ }
117
+ export function getDatabase(projectRoot) {
118
+ const dbDir = join(projectRoot, REPO_MEMORY_DIR);
119
+ const dbPath = join(dbDir, DB_FILENAME);
120
+ if (instance && instancePath === dbPath) {
121
+ return instance;
122
+ }
123
+ if (instance && instancePath !== dbPath) {
124
+ instance.close();
125
+ instance = null;
126
+ instancePath = null;
127
+ }
128
+ if (!existsSync(dbDir)) {
129
+ mkdirSync(dbDir, { recursive: true });
130
+ }
131
+ const db = new Database(dbPath);
132
+ db.pragma('journal_mode = WAL');
133
+ db.pragma('foreign_keys = ON');
134
+ runMigrations(db);
135
+ instance = db;
136
+ instancePath = dbPath;
137
+ return db;
138
+ }
139
+ export function closeDatabase() {
140
+ if (instance) {
141
+ instance.close();
142
+ instance = null;
143
+ instancePath = null;
144
+ }
145
+ }
146
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/persistence/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":""}
package/dist/server.js ADDED
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { z } from 'zod';
5
+ import { getFileSummary } from './tools/get-file-summary.js';
6
+ import { getChangedFiles } from './tools/get-changed-files.js';
7
+ import { getProjectMap } from './tools/get-project-map.js';
8
+ import { forceReread } from './tools/force-reread.js';
9
+ import { invalidateCache } from './tools/invalidate.js';
10
+ import { getDependencyGraphTool } from './tools/get-dependency-graph.js';
11
+ import { createTaskTool, getTaskContext, markExploredTool } from './tools/task-context.js';
12
+ import { getTokenReport } from './tools/get-token-report.js';
13
+ const server = new McpServer({
14
+ name: 'repo-memory',
15
+ version: '0.1.0',
16
+ });
17
+ server.registerTool('get_file_summary', {
18
+ title: 'Get File Summary',
19
+ description: 'Returns a cached summary of a file. If the file has not changed since last read, returns the cached summary without re-reading. Use this instead of reading files directly to save tokens.',
20
+ inputSchema: {
21
+ path: z.string().describe('File path relative to project root'),
22
+ },
23
+ }, async ({ path }) => {
24
+ try {
25
+ const projectRoot = process.cwd();
26
+ const result = await getFileSummary(projectRoot, path);
27
+ return {
28
+ content: [{ type: 'text', text: JSON.stringify(result) }],
29
+ };
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ const isNotFound = error instanceof Error && 'code' in error && error.code === 'ENOENT';
34
+ return {
35
+ content: [
36
+ {
37
+ type: 'text',
38
+ text: JSON.stringify({
39
+ error: isNotFound ? 'file_not_found' : 'internal_error',
40
+ message,
41
+ path,
42
+ }),
43
+ },
44
+ ],
45
+ isError: true,
46
+ };
47
+ }
48
+ });
49
+ server.registerTool('get_changed_files', {
50
+ title: 'Get Changed Files',
51
+ description: 'Returns files that have changed since the last check. Compares current file hashes against cached hashes.',
52
+ inputSchema: {
53
+ since: z.string().optional().describe('ISO timestamp or "last_check"'),
54
+ },
55
+ }, async ({ since }) => {
56
+ const projectRoot = process.cwd();
57
+ const result = await getChangedFiles(projectRoot, since);
58
+ return {
59
+ content: [{ type: 'text', text: JSON.stringify(result) }],
60
+ };
61
+ });
62
+ server.registerTool('get_project_map', {
63
+ title: 'Get Project Map',
64
+ description: 'Returns a structural overview of the project including directory tree, entry points, and key modules.',
65
+ inputSchema: {
66
+ project_root: z.string().describe('Absolute path to the project root'),
67
+ depth: z.number().optional().describe('Max directory depth to include'),
68
+ },
69
+ }, async ({ project_root, depth }) => {
70
+ const projectMap = await getProjectMap(project_root, depth);
71
+ return {
72
+ content: [{ type: 'text', text: JSON.stringify(projectMap) }],
73
+ };
74
+ });
75
+ server.registerTool('force_reread', {
76
+ title: 'Force Re-read',
77
+ description: 'Re-reads a file from disk, generates a fresh summary, and updates the cache. Use when you know a file has changed or want guaranteed-fresh data.',
78
+ inputSchema: {
79
+ path: z.string().describe('File path relative to project root'),
80
+ },
81
+ }, async ({ path }) => {
82
+ const projectRoot = process.cwd();
83
+ const result = await forceReread(projectRoot, path);
84
+ return {
85
+ content: [{ type: 'text', text: JSON.stringify(result) }],
86
+ };
87
+ });
88
+ server.registerTool('invalidate', {
89
+ title: 'Invalidate Cache',
90
+ description: 'Invalidates cached entries. If a path is provided, only that entry is removed. If no path is provided, all entries are removed.',
91
+ inputSchema: {
92
+ path: z.string().optional().describe('File path to invalidate, or omit to invalidate all'),
93
+ },
94
+ }, async ({ path }) => {
95
+ const projectRoot = process.cwd();
96
+ const result = await invalidateCache(projectRoot, path);
97
+ return {
98
+ content: [{ type: 'text', text: JSON.stringify(result) }],
99
+ };
100
+ });
101
+ server.registerTool('get_dependency_graph', {
102
+ title: 'Get Dependency Graph',
103
+ description: 'Returns dependency graph information. If a path is given, returns its dependencies/dependents. If no path, returns a summary of the most connected files.',
104
+ inputSchema: {
105
+ path: z.string().optional().describe('File path to query, or omit for full graph summary'),
106
+ direction: z
107
+ .enum(['dependencies', 'dependents', 'both'])
108
+ .optional()
109
+ .describe('Query direction (default: both)'),
110
+ depth: z.number().optional().describe('Max traversal depth'),
111
+ },
112
+ }, async ({ path, direction, depth }) => {
113
+ const projectRoot = process.cwd();
114
+ const result = await getDependencyGraphTool(projectRoot, path, direction, depth);
115
+ return {
116
+ content: [{ type: 'text', text: JSON.stringify(result) }],
117
+ };
118
+ });
119
+ server.registerTool('create_task', {
120
+ title: 'Create Task',
121
+ description: 'Creates a new investigation task for tracking file exploration.',
122
+ inputSchema: {
123
+ name: z.string().describe('Human-readable task name'),
124
+ },
125
+ }, async ({ name }) => {
126
+ const projectRoot = process.cwd();
127
+ const task = createTaskTool(projectRoot, name);
128
+ return {
129
+ content: [{ type: 'text', text: JSON.stringify(task) }],
130
+ };
131
+ });
132
+ server.registerTool('get_task_context', {
133
+ title: 'Get Task Context',
134
+ description: 'Returns task state, explored files, and frontier. If no task_id, returns list of all tasks.',
135
+ inputSchema: {
136
+ task_id: z.string().optional().describe('Task ID to query, or omit to list all tasks'),
137
+ },
138
+ }, async ({ task_id }) => {
139
+ const projectRoot = process.cwd();
140
+ const result = getTaskContext(projectRoot, task_id);
141
+ return {
142
+ content: [{ type: 'text', text: JSON.stringify(result) }],
143
+ };
144
+ });
145
+ server.registerTool('mark_explored', {
146
+ title: 'Mark Explored',
147
+ description: 'Marks a file as explored for a task, with optional status and notes.',
148
+ inputSchema: {
149
+ task_id: z.string().describe('Task ID'),
150
+ path: z.string().describe('File path relative to project root'),
151
+ status: z
152
+ .enum(['explored', 'skipped', 'flagged'])
153
+ .optional()
154
+ .describe('Exploration status (default: explored)'),
155
+ notes: z.string().optional().describe('Optional notes about the file'),
156
+ },
157
+ }, async ({ task_id, path, status, notes }) => {
158
+ const projectRoot = process.cwd();
159
+ const result = markExploredTool(projectRoot, task_id, path, status, notes);
160
+ return {
161
+ content: [{ type: 'text', text: JSON.stringify(result) }],
162
+ };
163
+ });
164
+ server.registerTool('get_token_report', {
165
+ title: 'Get Token Report',
166
+ description: 'Get aggregated token usage telemetry report showing cache efficiency and token savings',
167
+ inputSchema: {
168
+ period: z
169
+ .enum(['session', 'all', 'last_n_hours'])
170
+ .optional()
171
+ .describe('Time period for the report'),
172
+ hours: z
173
+ .number()
174
+ .optional()
175
+ .describe('Number of hours to look back (only for last_n_hours period)'),
176
+ session_id: z
177
+ .string()
178
+ .optional()
179
+ .describe('Session ID (only for session period)'),
180
+ },
181
+ }, async ({ period, hours, session_id }) => {
182
+ const projectRoot = process.cwd();
183
+ const report = getTokenReport(projectRoot, period, hours, session_id);
184
+ return {
185
+ content: [{ type: 'text', text: JSON.stringify(report, null, 2) }],
186
+ };
187
+ });
188
+ async function main() {
189
+ const transport = new StdioServerTransport();
190
+ await server.connect(transport);
191
+ }
192
+ main().catch((error) => {
193
+ const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
194
+ process.stderr.write(`Fatal error: ${message}\n`);
195
+ process.exit(1);
196
+ });
197
+ //# 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,40 @@
1
+ export type TelemetryEvent = 'cache_hit' | 'cache_miss' | 'invalidation' | 'force_reread' | 'summary_served';
2
+ export interface TelemetryEntry {
3
+ id: number;
4
+ timestamp: number;
5
+ eventType: TelemetryEvent;
6
+ filePath: string | null;
7
+ tokensEstimated: number | null;
8
+ metadata: Record<string, unknown> | null;
9
+ }
10
+ export declare class TelemetryTracker {
11
+ private readonly projectRoot;
12
+ private enabled;
13
+ private samplingRate;
14
+ constructor(projectRoot: string, enabled?: boolean, samplingRate?: number);
15
+ trackEvent(eventType: TelemetryEvent, filePath?: string, tokensEstimated?: number, metadata?: Record<string, unknown>): void;
16
+ getEvents(filter?: {
17
+ eventType?: TelemetryEvent;
18
+ since?: number;
19
+ limit?: number;
20
+ }): TelemetryEntry[];
21
+ getStats(since?: number): {
22
+ totalEvents: number;
23
+ cacheHits: number;
24
+ cacheMisses: number;
25
+ hitRatio: number;
26
+ totalTokensSaved: number;
27
+ eventsByType: Record<string, number>;
28
+ };
29
+ isEnabled(): boolean;
30
+ setEnabled(enabled: boolean): void;
31
+ getSamplingRate(): number;
32
+ setSamplingRate(rate: number): void;
33
+ exportEvents(filter?: {
34
+ since?: number;
35
+ eventType?: TelemetryEvent;
36
+ }): string;
37
+ enforceRetention(maxAgeDays: number): number;
38
+ private rowToEntry;
39
+ }
40
+ //# sourceMappingURL=tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/telemetry/tracker.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,YAAY,GACZ,cAAc,GACd,cAAc,GACd,gBAAgB,CAAC;AAErB,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAWD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,YAAY,CAAS;gBAEjB,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,OAAc,EAAE,YAAY,GAAE,MAAY;IAMpF,UAAU,CACR,SAAS,EAAE,cAAc,EACzB,QAAQ,CAAC,EAAE,MAAM,EACjB,eAAe,CAAC,EAAE,MAAM,EACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,IAAI;IAgBP,SAAS,CAAC,MAAM,CAAC,EAAE;QACjB,SAAS,CAAC,EAAE,cAAc,CAAC;QAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,cAAc,EAAE;IA4BpB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,MAAM,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACtC;IA0CD,SAAS,IAAI,OAAO;IAIpB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIlC,eAAe,IAAI,MAAM;IAIzB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAInC,YAAY,CAAC,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,MAAM;IAmC7E,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAO5C,OAAO,CAAC,UAAU;CAUnB"}
@@ -0,0 +1,136 @@
1
+ import { getDatabase } from '../persistence/db.js';
2
+ export class TelemetryTracker {
3
+ projectRoot;
4
+ enabled;
5
+ samplingRate;
6
+ constructor(projectRoot, enabled = true, samplingRate = 1.0) {
7
+ this.projectRoot = projectRoot;
8
+ this.enabled = enabled;
9
+ this.samplingRate = Math.max(0.0, Math.min(1.0, samplingRate));
10
+ }
11
+ trackEvent(eventType, filePath, tokensEstimated, metadata) {
12
+ if (!this.enabled)
13
+ return;
14
+ if (this.samplingRate < 1.0 && Math.random() > this.samplingRate)
15
+ return;
16
+ const db = getDatabase(this.projectRoot);
17
+ db.prepare('INSERT INTO telemetry (timestamp, event_type, file_path, tokens_estimated, metadata_json) VALUES (?, ?, ?, ?, ?)').run(Date.now(), eventType, filePath ?? null, tokensEstimated ?? null, metadata ? JSON.stringify(metadata) : null);
18
+ }
19
+ getEvents(filter) {
20
+ const db = getDatabase(this.projectRoot);
21
+ const conditions = [];
22
+ const params = [];
23
+ if (filter?.eventType) {
24
+ conditions.push('event_type = ?');
25
+ params.push(filter.eventType);
26
+ }
27
+ if (filter?.since) {
28
+ conditions.push('timestamp >= ?');
29
+ params.push(filter.since);
30
+ }
31
+ let sql = 'SELECT * FROM telemetry';
32
+ if (conditions.length > 0) {
33
+ sql += ' WHERE ' + conditions.join(' AND ');
34
+ }
35
+ sql += ' ORDER BY timestamp DESC';
36
+ if (filter?.limit) {
37
+ sql += ' LIMIT ?';
38
+ params.push(filter.limit);
39
+ }
40
+ const rows = db.prepare(sql).all(...params);
41
+ return rows.map(this.rowToEntry);
42
+ }
43
+ getStats(since) {
44
+ const db = getDatabase(this.projectRoot);
45
+ const whereClause = since ? ' WHERE timestamp >= ?' : '';
46
+ const params = since ? [since] : [];
47
+ const countRows = db
48
+ .prepare(`SELECT event_type, COUNT(*) as cnt FROM telemetry${whereClause} GROUP BY event_type`)
49
+ .all(...params);
50
+ const eventsByType = {};
51
+ let totalEvents = 0;
52
+ let cacheHits = 0;
53
+ let cacheMisses = 0;
54
+ for (const row of countRows) {
55
+ eventsByType[row.event_type] = row.cnt;
56
+ totalEvents += row.cnt;
57
+ if (row.event_type === 'cache_hit')
58
+ cacheHits = row.cnt;
59
+ if (row.event_type === 'cache_miss')
60
+ cacheMisses = row.cnt;
61
+ }
62
+ const hitTotal = cacheHits + cacheMisses;
63
+ const hitRatio = hitTotal > 0 ? cacheHits / hitTotal : 0;
64
+ const tokenRow = db
65
+ .prepare(`SELECT COALESCE(SUM(tokens_estimated), 0) as total FROM telemetry WHERE event_type = 'cache_hit'${since ? ' AND timestamp >= ?' : ''}`)
66
+ .get(...params);
67
+ return {
68
+ totalEvents,
69
+ cacheHits,
70
+ cacheMisses,
71
+ hitRatio,
72
+ totalTokensSaved: tokenRow.total,
73
+ eventsByType,
74
+ };
75
+ }
76
+ isEnabled() {
77
+ return this.enabled;
78
+ }
79
+ setEnabled(enabled) {
80
+ this.enabled = enabled;
81
+ }
82
+ getSamplingRate() {
83
+ return this.samplingRate;
84
+ }
85
+ setSamplingRate(rate) {
86
+ this.samplingRate = Math.max(0.0, Math.min(1.0, rate));
87
+ }
88
+ exportEvents(filter) {
89
+ const db = getDatabase(this.projectRoot);
90
+ const conditions = [];
91
+ const params = [];
92
+ if (filter?.eventType) {
93
+ conditions.push('event_type = ?');
94
+ params.push(filter.eventType);
95
+ }
96
+ if (filter?.since) {
97
+ conditions.push('timestamp >= ?');
98
+ params.push(filter.since);
99
+ }
100
+ let sql = 'SELECT * FROM telemetry';
101
+ if (conditions.length > 0) {
102
+ sql += ' WHERE ' + conditions.join(' AND ');
103
+ }
104
+ sql += ' ORDER BY timestamp ASC';
105
+ const rows = db.prepare(sql).all(...params);
106
+ return rows
107
+ .map((row) => {
108
+ const entry = this.rowToEntry(row);
109
+ return JSON.stringify({
110
+ timestamp: entry.timestamp,
111
+ eventType: entry.eventType,
112
+ filePath: entry.filePath,
113
+ tokensEstimated: entry.tokensEstimated,
114
+ metadata: entry.metadata,
115
+ });
116
+ })
117
+ .join('\n');
118
+ }
119
+ enforceRetention(maxAgeDays) {
120
+ const db = getDatabase(this.projectRoot);
121
+ const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;
122
+ const result = db.prepare('DELETE FROM telemetry WHERE timestamp < ?').run(cutoff);
123
+ return result.changes;
124
+ }
125
+ rowToEntry(row) {
126
+ return {
127
+ id: row.id,
128
+ timestamp: row.timestamp,
129
+ eventType: row.event_type,
130
+ filePath: row.file_path,
131
+ tokensEstimated: row.tokens_estimated,
132
+ metadata: row.metadata_json ? JSON.parse(row.metadata_json) : null,
133
+ };
134
+ }
135
+ }
136
+ //# sourceMappingURL=tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/telemetry/tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { FileSummary } from '../types.js';
2
+ export declare function forceReread(projectRoot: string, relativePath: string): Promise<{
3
+ path: string;
4
+ hash: string;
5
+ summary: FileSummary;
6
+ reread: true;
7
+ reason: string;
8
+ }>;
9
+ //# sourceMappingURL=force-reread.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"force-reread.d.ts","sourceRoot":"","sources":["../../src/tools/force-reread.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAW7F"}
@@ -0,0 +1,17 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { hashContents } from '../cache/hash.js';
4
+ import { CacheStore } from '../cache/store.js';
5
+ import { summarizeFile } from '../indexer/summarizer.js';
6
+ import { validatePath } from '../utils/validate-path.js';
7
+ export async function forceReread(projectRoot, relativePath) {
8
+ relativePath = validatePath(projectRoot, relativePath);
9
+ const absolutePath = join(projectRoot, relativePath);
10
+ const contents = await readFile(absolutePath, 'utf-8');
11
+ const hash = hashContents(contents);
12
+ const summary = summarizeFile(relativePath, contents);
13
+ const store = new CacheStore(projectRoot);
14
+ store.setEntry(relativePath, hash, summary);
15
+ return { path: relativePath, hash, summary, reread: true, reason: 'force_reread: explicitly requested' };
16
+ }
17
+ //# sourceMappingURL=force-reread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"force-reread.js","sourceRoot":"","sources":["../../src/tools/force-reread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,WAAmB,EACnB,YAAoB;IAEpB,YAAY,GAAG,YAAY,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAEtD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC1C,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAE5C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAC;AAC3G,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface ChangedFilesResult {
2
+ changed: string[];
3
+ added: string[];
4
+ deleted: string[];
5
+ checkedAt: string;
6
+ }
7
+ export declare function getChangedFiles(projectRoot: string, since?: string): Promise<ChangedFilesResult>;
8
+ //# sourceMappingURL=get-changed-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-changed-files.d.ts","sourceRoot":"","sources":["../../src/tools/get-changed-files.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC,CAuD7B"}