@blamechris/repo-memory 0.9.0 → 0.11.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 (35) hide show
  1. package/README.md +23 -6
  2. package/dist/cli/index-command.d.ts +30 -0
  3. package/dist/cli/index-command.d.ts.map +1 -0
  4. package/dist/cli/index-command.js +112 -0
  5. package/dist/cli/index-command.js.map +1 -0
  6. package/dist/grammars/tree-sitter-go.wasm +0 -0
  7. package/dist/grammars/tree-sitter-java.wasm +0 -0
  8. package/dist/grammars/tree-sitter-kotlin.wasm +0 -0
  9. package/dist/grammars/tree-sitter-python.wasm +0 -0
  10. package/dist/grammars/tree-sitter-rust.wasm +0 -0
  11. package/dist/indexer/ast-summarizer.d.ts +3 -3
  12. package/dist/indexer/ast-summarizer.d.ts.map +1 -1
  13. package/dist/indexer/ast-summarizer.js +900 -27
  14. package/dist/indexer/ast-summarizer.js.map +1 -1
  15. package/dist/indexer/imports.d.ts +2 -0
  16. package/dist/indexer/imports.d.ts.map +1 -1
  17. package/dist/indexer/imports.js +69 -0
  18. package/dist/indexer/imports.js.map +1 -1
  19. package/dist/indexer/summarize.d.ts.map +1 -1
  20. package/dist/indexer/summarize.js +15 -4
  21. package/dist/indexer/summarize.js.map +1 -1
  22. package/dist/persistence/db.d.ts +2 -0
  23. package/dist/persistence/db.d.ts.map +1 -1
  24. package/dist/persistence/db.js +5 -1
  25. package/dist/persistence/db.js.map +1 -1
  26. package/dist/server.js +14 -5
  27. package/dist/server.js.map +1 -1
  28. package/dist/tools/get-file-summary.d.ts +9 -1
  29. package/dist/tools/get-file-summary.d.ts.map +1 -1
  30. package/dist/tools/get-file-summary.js +9 -4
  31. package/dist/tools/get-file-summary.js.map +1 -1
  32. package/dist/tools/get-related-files.d.ts.map +1 -1
  33. package/dist/tools/get-related-files.js +4 -1
  34. package/dist/tools/get-related-files.js.map +1 -1
  35. package/package.json +1 -1
package/README.md CHANGED
@@ -34,6 +34,19 @@ npm install -g @blamechris/repo-memory
34
34
  repo-memory # starts MCP server on stdio
35
35
  ```
36
36
 
37
+ ### Prewarm the cache
38
+ The first time an agent touches a file it pays full price — the summary has to be generated. You can pay that cost ahead of time (post-pull hook, CI step) so the first session starts with cache hits:
39
+
40
+ ```bash
41
+ repo-memory index # index the current directory
42
+ repo-memory index /path/to/project
43
+ repo-memory index --quiet # no output on success (for scripts/CI)
44
+ ```
45
+
46
+ Only missing or stale entries are re-summarized; unchanged files are left untouched.
47
+
48
+ To automate it, drop a git `post-merge` hook in the project (see [docs/usage.md](docs/usage.md#cli) for the snippet) so every pull keeps the cache warm.
49
+
37
50
  ## How It Works
38
51
 
39
52
  ### The problem
@@ -194,7 +207,7 @@ Create a `.repo-memory.json` in your project root to customize behavior:
194
207
  }
195
208
  ```
196
209
 
197
- `summarizer` selects the summary engine: `"regex"` (default) or `"ast"`. AST mode parses TypeScript/JavaScript files (`.ts/.tsx/.js/.jsx/.mjs/.cjs`) with tree-sitter, producing accurate exports/declarations and a semantic `purpose` line that names the dominant symbols (e.g. `class CacheStore (9 methods)` instead of `source`) — which is what `search_by_purpose` matches against. TS/JS only for now; other languages, unsupported extensions, and files with parse errors fall back to the regex summarizer automatically. Switching modes regenerates summaries lazily on next access.
210
+ `summarizer` selects the summary engine: `"regex"` (default) or `"ast"`. AST mode parses supported languages (see [Language Support](#language-support)) with tree-sitter, producing accurate exports/declarations and a semantic `purpose` line that names the dominant symbols (e.g. `class CacheStore (9 methods)` instead of `source`) — which is what `search_by_purpose` matches against. Other languages, unsupported extensions, and files with parse errors fall back to the regex summarizer automatically. Switching modes regenerates summaries lazily on next access.
198
211
 
199
212
  The `tools` block toggles tool groups. `navigation` and `summaries` are **on by default** (set `"summaries": false` to drop the summary tools); `tasks` and `telemetry` are **off by default** (set them to `true` to enable).
200
213
 
@@ -209,11 +222,15 @@ Config validation is per-key: an invalid value is skipped with a warning on stde
209
222
 
210
223
  ## Language Support
211
224
 
212
- Summaries are extracted via regex analysis (or tree-sitter when `"summarizer": "ast"` is set TS/JS only). Supported languages:
213
- - **TypeScript / JavaScript** — exports, imports, declarations, purpose classification; optional AST mode for semantic purpose lines
214
- - **Python** — functions, classes, `__all__`, `from`/`import` statements
215
- - **Go** — exported names (uppercase), imports, type/func/var/const declarations
216
- - **Rust** — `pub` items, `use`/`mod` statements, structs/enums/traits/impls
225
+ Summaries are extracted via regex analysis, or from tree-sitter parse trees when `"summarizer": "ast"` is set. All language families below have AST support in `ast` mode, which adds semantic purpose lines derived from doc comments; regex stays as the universal fallback for other languages and unparseable files. Supported languages:
226
+ - **TypeScript / JavaScript** — exports, imports, declarations, purpose classification; AST mode adds JSDoc-derived purpose lines
227
+ - **Python** — functions, classes (incl. `async def`), `__all__`, `from`/`import` statements; AST mode adds docstring-derived purpose lines
228
+ - **Go** — exported names (uppercase), imports, type/func/var/const declarations; AST mode adds doc-comment purpose lines and grouped `var (…)` / `const (…)` support
229
+ - **Rust** — `pub` items, `use`/`mod` statements, structs/enums/traits/impls; AST mode adds `///` doc-comment purpose lines and `pub use` re-exports
230
+ - **Kotlin** (`.kt/.kts`) — AST mode only: public top-level `fun`/`class`/`object`/`interface`/`enum class`/`data class`/`val`/`var`/`typealias` (excluding `private`/`internal`), `import` paths, KDoc-derived purpose lines; regex mode gives only basic filename classification
231
+ - **Java** — AST mode only: public types and the public methods/fields of the public type, `import` statements (incl. `static` and wildcard), Javadoc-derived purpose lines; regex mode gives only basic filename classification
232
+
233
+ The dependency graph (`get_related_files`, `get_dependency_graph`) extracts imports for all six language families regardless of summarizer mode.
217
234
 
218
235
  Config files (JSON, YAML, TOML) and other file types get basic classification.
219
236
 
@@ -0,0 +1,30 @@
1
+ export interface IndexOptions {
2
+ /** Suppress the human-readable report printed to stdout. */
3
+ quiet?: boolean;
4
+ }
5
+ export interface IndexReport {
6
+ projectRoot: string;
7
+ cacheDbPath: string;
8
+ scanned: number;
9
+ summarized: number;
10
+ fresh: number;
11
+ skipped: number;
12
+ skippedPaths: string[];
13
+ elapsedMs: number;
14
+ }
15
+ /**
16
+ * Prewarm the summary cache for a project: scan all indexable files and run
17
+ * each one through the same hash/compare/summarize/store path the
18
+ * `get_file_summary` tool uses, so a later MCP session starts with cache hits.
19
+ *
20
+ * Files whose hash already matches the cache are left untouched ("fresh");
21
+ * files that cannot be read or summarized are counted as skipped rather than
22
+ * aborting the run.
23
+ */
24
+ export declare function runIndex(projectRoot: string, options?: IndexOptions): Promise<IndexReport>;
25
+ /**
26
+ * Thin argv wrapper for `repo-memory index [projectRoot] [--quiet]`.
27
+ * Exits 0 on success, 1 on error (message to stderr).
28
+ */
29
+ export declare function runIndexCli(argv: string[]): Promise<never>;
30
+ //# sourceMappingURL=index-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-command.d.ts","sourceRoot":"","sources":["../../src/cli/index-command.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAsDtB;AAeD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CA4BhE"}
@@ -0,0 +1,112 @@
1
+ import { existsSync, statSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { scanProject } from '../indexer/scanner.js';
4
+ import { ensureSummaryGeneration } from '../indexer/summarize.js';
5
+ import { getDatabasePath } from '../persistence/db.js';
6
+ import { getFileSummary } from '../tools/get-file-summary.js';
7
+ /**
8
+ * Prewarm the summary cache for a project: scan all indexable files and run
9
+ * each one through the same hash/compare/summarize/store path the
10
+ * `get_file_summary` tool uses, so a later MCP session starts with cache hits.
11
+ *
12
+ * Files whose hash already matches the cache are left untouched ("fresh");
13
+ * files that cannot be read or summarized are counted as skipped rather than
14
+ * aborting the run.
15
+ */
16
+ export async function runIndex(projectRoot, options = {}) {
17
+ const root = resolve(projectRoot);
18
+ if (!existsSync(root) || !statSync(root).isDirectory()) {
19
+ throw new Error(`project root does not exist or is not a directory: ${root}`);
20
+ }
21
+ const started = Date.now();
22
+ // Verify cached summaries match the configured summarizer mode/generation
23
+ // before any cache comparisons happen.
24
+ ensureSummaryGeneration(root);
25
+ const files = await scanProject(root);
26
+ let summarized = 0;
27
+ let fresh = 0;
28
+ const skippedPaths = [];
29
+ for (const file of files) {
30
+ try {
31
+ // Reuses the exact cache-read/write semantics of the get_file_summary
32
+ // tool: hash, compare, regenerate only when missing/stale. Telemetry is
33
+ // suppressed — prewarm traffic isn't agent traffic and would distort
34
+ // hit-ratio stats.
35
+ const result = await getFileSummary(root, file, { trackTelemetry: false });
36
+ if (result.fromCache) {
37
+ fresh += 1;
38
+ }
39
+ else {
40
+ summarized += 1;
41
+ }
42
+ }
43
+ catch {
44
+ // Unreadable entries (deleted since scan, gitlinks, permission errors).
45
+ skippedPaths.push(file);
46
+ }
47
+ }
48
+ const report = {
49
+ projectRoot: root,
50
+ cacheDbPath: getDatabasePath(root),
51
+ scanned: files.length,
52
+ summarized,
53
+ fresh,
54
+ skipped: skippedPaths.length,
55
+ skippedPaths,
56
+ elapsedMs: Date.now() - started,
57
+ };
58
+ if (!options.quiet) {
59
+ // stdout is safe here — the index command never runs while the MCP stdio
60
+ // transport is active, so this cannot corrupt the protocol channel.
61
+ process.stdout.write(formatReport(report));
62
+ }
63
+ return report;
64
+ }
65
+ function formatReport(report) {
66
+ const lines = [
67
+ `Indexed ${report.projectRoot}`,
68
+ ` scanned: ${report.scanned}`,
69
+ ` summarized: ${report.summarized}`,
70
+ ` already fresh: ${report.fresh}`,
71
+ ` skipped: ${report.skipped}`,
72
+ ` elapsed: ${(report.elapsedMs / 1000).toFixed(2)}s`,
73
+ ` cache db: ${report.cacheDbPath}`,
74
+ ];
75
+ return lines.join('\n') + '\n';
76
+ }
77
+ /**
78
+ * Thin argv wrapper for `repo-memory index [projectRoot] [--quiet]`.
79
+ * Exits 0 on success, 1 on error (message to stderr).
80
+ */
81
+ export async function runIndexCli(argv) {
82
+ let quiet = false;
83
+ let projectRoot;
84
+ for (const arg of argv) {
85
+ if (arg === '--quiet' || arg === '-q') {
86
+ quiet = true;
87
+ }
88
+ else if (arg.startsWith('-')) {
89
+ process.stderr.write(`repo-memory index: unknown option '${arg}'\n`);
90
+ process.stderr.write('Usage: repo-memory index [projectRoot] [--quiet]\n');
91
+ process.exit(1);
92
+ }
93
+ else if (projectRoot === undefined) {
94
+ projectRoot = arg;
95
+ }
96
+ else {
97
+ process.stderr.write(`repo-memory index: unexpected argument '${arg}'\n`);
98
+ process.stderr.write('Usage: repo-memory index [projectRoot] [--quiet]\n');
99
+ process.exit(1);
100
+ }
101
+ }
102
+ try {
103
+ await runIndex(projectRoot ?? process.cwd(), { quiet });
104
+ process.exit(0);
105
+ }
106
+ catch (error) {
107
+ const message = error instanceof Error ? error.message : String(error);
108
+ process.stderr.write(`repo-memory index: ${message}\n`);
109
+ process.exit(1);
110
+ }
111
+ }
112
+ //# sourceMappingURL=index-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-command.js","sourceRoot":"","sources":["../../src/cli/index-command.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import type { FileSummary } from '../types.js';
2
2
  /**
3
- * Summarize a TS/JS file from its syntax tree. Falls back to the regex
4
- * summarizer for unsupported extensions, empty files, parse errors, or when
5
- * the WASM runtime cannot be loaded.
3
+ * Summarize a TS/JS, Python, Go, Rust, Kotlin or Java file from its syntax
4
+ * tree. Falls back to the regex summarizer for unsupported extensions, empty
5
+ * files, parse errors, or when the WASM runtime cannot be loaded.
6
6
  */
7
7
  export declare function summarizeFileAst(filePath: string, contents: string): Promise<FileSummary>;
8
8
  /** True when the AST summarizer handles this file natively (vs regex fallback). */
@@ -1 +1 @@
1
- {"version":3,"file":"ast-summarizer.d.ts","sourceRoot":"","sources":["../../src/indexer/ast-summarizer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA+Y/C;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAmC/F;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExD"}
1
+ {"version":3,"file":"ast-summarizer.d.ts","sourceRoot":"","sources":["../../src/indexer/ast-summarizer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAsvC/C;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAqC/F;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExD"}