@jafreck/lore 0.2.0 → 0.2.2

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 (180) hide show
  1. package/README.md +399 -199
  2. package/dist/cli.js +139 -18
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.d.ts +7 -6
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +3 -3
  7. package/dist/index.js.map +1 -1
  8. package/dist/indexer/db.d.ts +12 -11
  9. package/dist/indexer/db.d.ts.map +1 -1
  10. package/dist/indexer/db.js +118 -18
  11. package/dist/indexer/db.js.map +1 -1
  12. package/dist/indexer/docs.d.ts +42 -0
  13. package/dist/indexer/docs.d.ts.map +1 -0
  14. package/dist/indexer/docs.js +214 -0
  15. package/dist/indexer/docs.js.map +1 -0
  16. package/dist/indexer/embedder.d.ts +7 -0
  17. package/dist/indexer/embedder.d.ts.map +1 -1
  18. package/dist/indexer/embedder.js +10 -0
  19. package/dist/indexer/embedder.js.map +1 -1
  20. package/dist/indexer/ensure-python-deps.d.ts +1 -1
  21. package/dist/indexer/ensure-python-deps.js +1 -1
  22. package/dist/indexer/extractors/types.d.ts +22 -0
  23. package/dist/indexer/extractors/types.d.ts.map +1 -1
  24. package/dist/indexer/extractors/types.js +12 -0
  25. package/dist/indexer/extractors/types.js.map +1 -1
  26. package/dist/indexer/extractors/typescript.d.ts +1 -1
  27. package/dist/indexer/extractors/typescript.d.ts.map +1 -1
  28. package/dist/indexer/extractors/typescript.js +38 -8
  29. package/dist/indexer/extractors/typescript.js.map +1 -1
  30. package/dist/indexer/git-history.d.ts.map +1 -1
  31. package/dist/indexer/git-history.js +4 -4
  32. package/dist/indexer/git-history.js.map +1 -1
  33. package/dist/indexer/git-hooks.d.ts +1 -0
  34. package/dist/indexer/git-hooks.d.ts.map +1 -1
  35. package/dist/indexer/git-hooks.js +3 -2
  36. package/dist/indexer/git-hooks.js.map +1 -1
  37. package/dist/indexer/index.d.ts +35 -9
  38. package/dist/indexer/index.d.ts.map +1 -1
  39. package/dist/indexer/index.js +470 -30
  40. package/dist/indexer/index.js.map +1 -1
  41. package/dist/indexer/lsp/client.d.ts +61 -0
  42. package/dist/indexer/lsp/client.d.ts.map +1 -0
  43. package/dist/indexer/lsp/client.js +217 -0
  44. package/dist/indexer/lsp/client.js.map +1 -0
  45. package/dist/indexer/lsp/config.d.ts +16 -0
  46. package/dist/indexer/lsp/config.d.ts.map +1 -0
  47. package/dist/indexer/lsp/config.js +78 -0
  48. package/dist/indexer/lsp/config.js.map +1 -0
  49. package/dist/indexer/lsp/enrichment.d.ts +55 -0
  50. package/dist/indexer/lsp/enrichment.d.ts.map +1 -0
  51. package/dist/indexer/lsp/enrichment.js +211 -0
  52. package/dist/indexer/lsp/enrichment.js.map +1 -0
  53. package/dist/indexer/lsp/registry.d.ts +19 -0
  54. package/dist/indexer/lsp/registry.d.ts.map +1 -0
  55. package/dist/indexer/lsp/registry.js +118 -0
  56. package/dist/indexer/lsp/registry.js.map +1 -0
  57. package/dist/indexer/parser.d.ts +7 -0
  58. package/dist/indexer/parser.d.ts.map +1 -1
  59. package/dist/indexer/parser.js +3 -1
  60. package/dist/indexer/parser.js.map +1 -1
  61. package/dist/indexer/poller.d.ts +8 -1
  62. package/dist/indexer/poller.d.ts.map +1 -1
  63. package/dist/indexer/poller.js +7 -1
  64. package/dist/indexer/poller.js.map +1 -1
  65. package/dist/indexer/walker.d.ts +22 -0
  66. package/dist/indexer/walker.d.ts.map +1 -1
  67. package/dist/indexer/walker.js +15 -0
  68. package/dist/indexer/walker.js.map +1 -1
  69. package/dist/indexer/watcher.d.ts +8 -1
  70. package/dist/indexer/watcher.d.ts.map +1 -1
  71. package/dist/indexer/watcher.js +7 -1
  72. package/dist/indexer/watcher.js.map +1 -1
  73. package/dist/{kb-server → lore-server}/db.d.ts +158 -4
  74. package/dist/lore-server/db.d.ts.map +1 -0
  75. package/dist/{kb-server → lore-server}/db.js +457 -26
  76. package/dist/lore-server/db.js.map +1 -0
  77. package/dist/lore-server/server.d.ts +43 -0
  78. package/dist/lore-server/server.d.ts.map +1 -0
  79. package/dist/lore-server/server.js +385 -0
  80. package/dist/lore-server/server.js.map +1 -0
  81. package/dist/{kb-server → lore-server}/tools/annotations.d.ts +2 -2
  82. package/dist/lore-server/tools/annotations.d.ts.map +1 -0
  83. package/dist/{kb-server → lore-server}/tools/annotations.js +2 -2
  84. package/dist/lore-server/tools/annotations.js.map +1 -0
  85. package/dist/{kb-server → lore-server}/tools/architecture.d.ts +9 -2
  86. package/dist/lore-server/tools/architecture.d.ts.map +1 -0
  87. package/dist/{kb-server → lore-server}/tools/architecture.js +37 -2
  88. package/dist/lore-server/tools/architecture.js.map +1 -0
  89. package/dist/lore-server/tools/blame.d.ts +159 -0
  90. package/dist/lore-server/tools/blame.d.ts.map +1 -0
  91. package/dist/lore-server/tools/blame.js +595 -0
  92. package/dist/lore-server/tools/blame.js.map +1 -0
  93. package/dist/{kb-server → lore-server}/tools/coverage.d.ts +2 -2
  94. package/dist/lore-server/tools/coverage.d.ts.map +1 -0
  95. package/dist/{kb-server → lore-server}/tools/coverage.js +2 -2
  96. package/dist/lore-server/tools/coverage.js.map +1 -0
  97. package/dist/lore-server/tools/docs.d.ts +86 -0
  98. package/dist/lore-server/tools/docs.d.ts.map +1 -0
  99. package/dist/lore-server/tools/docs.js +243 -0
  100. package/dist/lore-server/tools/docs.js.map +1 -0
  101. package/dist/{kb-server → lore-server}/tools/graph.d.ts +40 -3
  102. package/dist/lore-server/tools/graph.d.ts.map +1 -0
  103. package/dist/{kb-server → lore-server}/tools/graph.js +122 -11
  104. package/dist/lore-server/tools/graph.js.map +1 -0
  105. package/dist/{kb-server → lore-server}/tools/history.d.ts +13 -6
  106. package/dist/lore-server/tools/history.d.ts.map +1 -0
  107. package/dist/{kb-server → lore-server}/tools/history.js +43 -10
  108. package/dist/lore-server/tools/history.js.map +1 -0
  109. package/dist/lore-server/tools/lookup.d.ts +75 -0
  110. package/dist/lore-server/tools/lookup.d.ts.map +1 -0
  111. package/dist/lore-server/tools/lookup.js +148 -0
  112. package/dist/lore-server/tools/lookup.js.map +1 -0
  113. package/dist/{kb-server → lore-server}/tools/metrics.d.ts +3 -3
  114. package/dist/lore-server/tools/metrics.d.ts.map +1 -0
  115. package/dist/{kb-server → lore-server}/tools/metrics.js +3 -3
  116. package/dist/lore-server/tools/metrics.js.map +1 -0
  117. package/dist/{kb-server → lore-server}/tools/notes.d.ts +16 -16
  118. package/dist/lore-server/tools/notes.d.ts.map +1 -0
  119. package/dist/{kb-server → lore-server}/tools/notes.js +55 -20
  120. package/dist/lore-server/tools/notes.js.map +1 -0
  121. package/dist/{kb-server → lore-server}/tools/routes.d.ts +2 -2
  122. package/dist/lore-server/tools/routes.d.ts.map +1 -0
  123. package/dist/{kb-server → lore-server}/tools/routes.js +2 -2
  124. package/dist/lore-server/tools/routes.js.map +1 -0
  125. package/dist/{kb-server → lore-server}/tools/search.d.ts +57 -13
  126. package/dist/lore-server/tools/search.d.ts.map +1 -0
  127. package/dist/{kb-server → lore-server}/tools/search.js +123 -23
  128. package/dist/lore-server/tools/search.js.map +1 -0
  129. package/dist/{kb-server → lore-server}/tools/snippet.d.ts +20 -4
  130. package/dist/lore-server/tools/snippet.d.ts.map +1 -0
  131. package/dist/lore-server/tools/snippet.js +116 -0
  132. package/dist/lore-server/tools/snippet.js.map +1 -0
  133. package/dist/{kb-server → lore-server}/tools/test-map.d.ts +2 -2
  134. package/dist/lore-server/tools/test-map.d.ts.map +1 -0
  135. package/dist/{kb-server → lore-server}/tools/test-map.js +2 -2
  136. package/dist/lore-server/tools/test-map.js.map +1 -0
  137. package/dist/{kb-server → lore-server}/tools/writeback.d.ts +2 -2
  138. package/dist/lore-server/tools/writeback.d.ts.map +1 -0
  139. package/dist/{kb-server → lore-server}/tools/writeback.js +3 -3
  140. package/dist/lore-server/tools/writeback.js.map +1 -0
  141. package/package.json +14 -14
  142. package/dist/kb-server/db.d.ts.map +0 -1
  143. package/dist/kb-server/db.js.map +0 -1
  144. package/dist/kb-server/server.d.ts +0 -42
  145. package/dist/kb-server/server.d.ts.map +0 -1
  146. package/dist/kb-server/server.js +0 -241
  147. package/dist/kb-server/server.js.map +0 -1
  148. package/dist/kb-server/tools/annotations.d.ts.map +0 -1
  149. package/dist/kb-server/tools/annotations.js.map +0 -1
  150. package/dist/kb-server/tools/architecture.d.ts.map +0 -1
  151. package/dist/kb-server/tools/architecture.js.map +0 -1
  152. package/dist/kb-server/tools/blame.d.ts +0 -67
  153. package/dist/kb-server/tools/blame.d.ts.map +0 -1
  154. package/dist/kb-server/tools/blame.js +0 -162
  155. package/dist/kb-server/tools/blame.js.map +0 -1
  156. package/dist/kb-server/tools/coverage.d.ts.map +0 -1
  157. package/dist/kb-server/tools/coverage.js.map +0 -1
  158. package/dist/kb-server/tools/graph.d.ts.map +0 -1
  159. package/dist/kb-server/tools/graph.js.map +0 -1
  160. package/dist/kb-server/tools/history.d.ts.map +0 -1
  161. package/dist/kb-server/tools/history.js.map +0 -1
  162. package/dist/kb-server/tools/lookup.d.ts +0 -36
  163. package/dist/kb-server/tools/lookup.d.ts.map +0 -1
  164. package/dist/kb-server/tools/lookup.js +0 -45
  165. package/dist/kb-server/tools/lookup.js.map +0 -1
  166. package/dist/kb-server/tools/metrics.d.ts.map +0 -1
  167. package/dist/kb-server/tools/metrics.js.map +0 -1
  168. package/dist/kb-server/tools/notes.d.ts.map +0 -1
  169. package/dist/kb-server/tools/notes.js.map +0 -1
  170. package/dist/kb-server/tools/routes.d.ts.map +0 -1
  171. package/dist/kb-server/tools/routes.js.map +0 -1
  172. package/dist/kb-server/tools/search.d.ts.map +0 -1
  173. package/dist/kb-server/tools/search.js.map +0 -1
  174. package/dist/kb-server/tools/snippet.d.ts.map +0 -1
  175. package/dist/kb-server/tools/snippet.js +0 -49
  176. package/dist/kb-server/tools/snippet.js.map +0 -1
  177. package/dist/kb-server/tools/test-map.d.ts.map +0 -1
  178. package/dist/kb-server/tools/test-map.js.map +0 -1
  179. package/dist/kb-server/tools/writeback.d.ts.map +0 -1
  180. package/dist/kb-server/tools/writeback.js.map +0 -1
package/README.md CHANGED
@@ -1,20 +1,25 @@
1
1
  # Lore
2
2
 
3
3
  [![CI](https://github.com/jafreck/Lore/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/jafreck/Lore/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/@jafreck/lore)](https://www.npmjs.com/package/@jafreck/lore)
4
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
6
  [![Node.js](https://img.shields.io/badge/node-%3E%3D22.0.0-brightgreen)](https://nodejs.org)
6
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9+-blue)](https://www.typescriptlang.org)
7
8
 
8
- **The teammate that has seen it all** Lore is your agent's institutional knowledge over the codebase — it knows what was built, why it changed, and how it all connects. Lore indexes your code and git history into a structured knowledge base that agents query through MCP. It maps symbols, imports, call relationships, and git history — with optional embeddings for semantic search — so agents can reason about your codebase
9
+ **The teammate that has seen it all**
10
+
11
+ Lore is your agent's institutional knowledge over the codebase — it knows what was built, why it changed, and how it all connects. Lore indexes your code and git history into a structured knowledge base that agents query through MCP. It maps symbols, imports, call relationships, and git history — with optional embeddings for semantic search — so agents can reason about your codebase
9
12
  without re-reading it from scratch.
10
13
 
11
14
  ## What Lore does
12
15
 
13
16
  - Parses source files and extracts symbols, imports, and call refs
14
17
  - Resolves internal vs external imports and builds call/import graph edges
18
+ - Discovers and indexes documentation (`.md`, `.rst`, `.adoc`, `.txt`) with inferred kinds/titles
15
19
  - Stores everything in a normalized SQL schema with optional vector search
16
- - Enables RAG-style retrieval with semantic/fused search
20
+ - Enables RAG-style retrieval with semantic/fused search across symbols and doc sections
17
21
  - Indexes git history (commits, touched files, refs/branches/tags)
22
+ - Enriches symbols with resolved type signatures and definitions via optional index-time LSP integration
18
23
  - Supports line-level git blame through MCP
19
24
  - Supports automatic refresh via watch mode, poll mode, and git hooks
20
25
 
@@ -24,70 +29,72 @@ without re-reading it from scratch.
24
29
  flowchart LR
25
30
  subgraph Codebase
26
31
  SRC[Source Files]
32
+ DOCS[Documentation<br/>md · rst · adoc · txt]
27
33
  GIT[Git Repo]
28
34
  COV[Coverage Reports]
29
35
  end
30
36
 
31
37
  subgraph Lore Indexer
32
- WALK[Walker]
33
- PARSE[Parser]
34
- EXTRACT[Extractors<br/>symbols · imports · call refs]
35
- RESOLVE[Import Resolver<br/>internal external]
36
- CALLGRAPH[Call-Graph Builder]
37
- EMBED[Embedder]
38
+ WALK[Walker] --> PARSE[Parser] --> EXTRACT[Extractors<br/>symbols · imports · call refs]
39
+ EXTRACT --> RESOLVE[Import Resolver<br/>internal ↔ external]
40
+ EXTRACT --> CALLGRAPH[Call-Graph Builder]
41
+ EXTRACT -.-> LSPENRICH[LSP Enrichment<br/>type signatures · definition locations]
42
+ DOCSINGEST[Docs Ingest<br/>sections · headings · notes]
38
43
  GITHIST[Git History Ingest<br/>commits · diffs · refs]
39
44
  COVINGEST[Coverage Ingest<br/>lcov · cobertura]
40
45
  end
41
46
 
42
47
  DB[(SQL DB)]
48
+ EMBED([Embedding Model])
43
49
 
44
50
  subgraph MCP Server
45
- LOOKUP[kb_lookup]
46
- SEARCH[kb_search]
47
- GRAPH[kb_graph]
48
- SNIPPET[kb_snippet]
49
- BLAME[kb_blame]
50
- HISTORY[kb_history]
51
- METRICS[kb_metrics]
52
- WRITEBACK[kb_writeback]
53
- end
54
-
55
- subgraph LLM_AGENTS[Agents]
56
- CLAUDE[Claude]
57
- COPILOT[GitHub Copilot]
58
- CUSTOM_AGENT[Custom Agents]
59
- CLAUDE ~~~ COPILOT ~~~ CUSTOM_AGENT
51
+ LOOKUP[lore_lookup]
52
+ SEARCH[lore_search]
53
+ DOCS_TOOL[lore_docs]
54
+ GRAPH[lore_graph]
55
+ TESTMAP[lore_test_map]
56
+ SNIPPET[lore_snippet]
57
+ BLAME[lore_blame]
58
+ HISTORY[lore_history]
59
+ COMMITSTATS[lore_commit_stats]
60
+ METRICS[lore_metrics]
61
+ COVERAGE[lore_coverage]
62
+ WRITEBACK[lore_writeback]
60
63
  end
61
64
 
62
- subgraph ENTRY[User Entrypoints]
63
- VSCODE[VS Code]
65
+ subgraph MCP_CLIENTS[MCP Clients — Agents]
66
+ CLAUDE_CODE[Claude Code / Desktop]
67
+ COPILOT[VS Code + Copilot]
64
68
  CURSOR[Cursor]
65
- CHAT[Chat UI]
66
- ORCH[Agent Frameworks]
67
- VSCODE ~~~ CURSOR ~~~ CHAT ~~~ ORCH
69
+ CUSTOM[Custom Agent Frameworks]
70
+ CLAUDE_CODE ~~~ COPILOT ~~~ CURSOR ~~~ CUSTOM
68
71
  end
69
72
 
70
- SRC --> WALK --> PARSE --> EXTRACT
71
- EXTRACT --> RESOLVE & CALLGRAPH
72
- EXTRACT & RESOLVE & CALLGRAPH --> DB
73
- EMBED -.->|optional| DB
73
+ SRC --> WALK
74
+ DOCS --> DOCSINGEST --> DB
74
75
  GIT --> GITHIST --> DB
75
76
  COV --> COVINGEST --> DB
76
77
 
77
- DB --- LOOKUP & SEARCH & GRAPH & SNIPPET & BLAME & HISTORY & METRICS & WRITEBACK
78
+ RESOLVE & CALLGRAPH --> DB
79
+ LSPENRICH -.->|optional| DB
80
+ RESOLVE -.->|optional| EMBED
81
+ EMBED -.-> DB
78
82
 
79
- LOOKUP & SEARCH & GRAPH & SNIPPET & BLAME & HISTORY & METRICS & WRITEBACK <--> LLM_AGENTS
83
+ DB --- LOOKUP & SEARCH & DOCS_TOOL & GRAPH & TESTMAP & SNIPPET & BLAME & HISTORY & COMMITSTATS & METRICS & COVERAGE & WRITEBACK
84
+ EMBED <-.->|semantic/fused| SEARCH
80
85
 
81
- LLM_AGENTS <--- ENTRY
86
+ LOOKUP & SEARCH & DOCS_TOOL & GRAPH & TESTMAP & SNIPPET & BLAME & HISTORY & COMMITSTATS & METRICS & COVERAGE & WRITEBACK <--> MCP_CLIENTS
82
87
  ```
83
88
 
84
89
  Lore sits between your codebase and any LLM-powered tool. The **indexer**
85
90
  pipeline walks source files, parses them into ASTs, and extracts
86
91
  symbols/imports/call-refs via language-specific extractors, then resolves
87
92
  imports (internal vs external) and builds the call graph. An optional
88
- **embedder** generates dense vectors for semantic search, and a parallel
89
- **git history** ingest captures commits, diffs, and refs. Everything is
90
- persisted to a normalized SQL database. The **MCP server** then exposes that
93
+ **LSP enrichment** pass queries language servers to resolve type signatures
94
+ and jump-to-definition URIs for extracted symbols. An optional **embedder**
95
+ generates dense vectors for semantic search, and a parallel **git history**
96
+ ingest captures commits, diffs, and refs. Everything is persisted to a
97
+ normalized SQL database. The **MCP server** then exposes that
91
98
  database as a set of tools that any MCP-compatible client can call to look up
92
99
  symbols, search code, traverse call graphs, read snippets, query
93
100
  blame/history, and write summaries back.
@@ -120,52 +127,14 @@ npm install @jafreck/lore
120
127
  Note: Lore uses native add-ons (`tree-sitter`, `better-sqlite3`). A working
121
128
  C/C++ toolchain is required the first time dependencies are built.
122
129
 
123
- ## Publish authentication (npm)
124
-
125
- Lore publish operations use `NODE_AUTH_TOKEN` (see `.npmrc`) and never commit
126
- tokens to the repository.
127
-
128
- Local publish flow:
129
-
130
- ```bash
131
- export NODE_AUTH_TOKEN=<npm automation token>
132
- npm publish --access public
133
- ```
134
-
135
- CI publish flow:
136
-
137
- - Add `NODE_AUTH_TOKEN` as a secret in your CI provider (for GitHub Actions,
138
- use a repository or environment secret).
139
- - Ensure publish jobs expose that secret as the `NODE_AUTH_TOKEN` environment
140
- variable before running `npm publish`.
141
-
142
- ## Release publish workflow (`@jafreck/lore@0.1.0`)
143
-
144
- Publishing is automated by `.github/workflows/publish.yml`. Creating a version
145
- tag (for example, `v0.1.0`) or publishing a GitHub Release triggers the npm
146
- publish job.
147
-
148
- Release steps for `@jafreck/lore@0.1.0`:
149
-
150
- 1. Ensure `package.json` has `"version": "0.1.0"`.
151
- 2. Push the tag: `git tag v0.1.0 && git push origin v0.1.0` (or publish a
152
- GitHub Release for `v0.1.0`).
153
- 3. Confirm the workflow logs show `npm publish --dry-run` output before the
154
- live `npm publish` step.
155
-
156
- Post-publish verification:
157
-
158
- - Check the package metadata: `npm view @jafreck/lore version` returns `0.1.0`.
159
- - Confirm installability: `npm view @jafreck/lore@0.1.0 name version`.
160
-
161
130
  ## Quick start (CLI)
162
131
 
163
132
  ```bash
164
133
  # 1) Build an index
165
- npx @jafreck/lore index --root ./my-project --db ./kb.db
134
+ npx @jafreck/lore index --root ./my-project --db ./lore.db
166
135
 
167
136
  # 2) Start MCP server over stdio
168
- npx @jafreck/lore mcp --db ./kb.db
137
+ npx @jafreck/lore mcp --db ./lore.db
169
138
  ```
170
139
 
171
140
  ## Quick start (programmatic)
@@ -174,7 +143,7 @@ npx @jafreck/lore mcp --db ./kb.db
174
143
  import { IndexBuilder } from '@jafreck/lore';
175
144
 
176
145
  const builder = new IndexBuilder(
177
- './kb.db',
146
+ './lore.db',
178
147
  { rootDir: './my-project' },
179
148
  undefined,
180
149
  { history: true },
@@ -183,196 +152,369 @@ const builder = new IndexBuilder(
183
152
  await builder.build();
184
153
  ```
185
154
 
186
- ### Programmatic configuration examples
155
+ ## MCP tools
187
156
 
188
- ```ts
189
- import { IndexBuilder } from '@jafreck/lore';
157
+ | Tool | Purpose |
158
+ |------|---------|
159
+ | `lore_lookup` | Find symbols by name or files by path, including external dependency API symbols and LSP-resolved metadata when available |
160
+ | `lore_search` | Structural BM25, semantic vector, or fused RRF search across symbols and doc sections |
161
+ | `lore_docs` | List, fetch, or search indexed documentation with branch, kind, and path filters |
162
+ | `lore_annotations` | Return indexed TODO/FIXME/HACK/NOTE-style annotations with optional path and limit filters |
163
+ | `lore_routes` | Query extracted API routes/endpoints with optional method, path prefix, and framework filters |
164
+ | `lore_notes_write` | Upsert agent-authored notes by key and scope, with optional source hash for staleness tracking |
165
+ | `lore_notes_read` | Read notes by exact key or key prefix with scope-aware staleness metadata |
166
+ | `lore_architecture` | Build a component-level architecture view with edges, entry/leaf nodes, and external dependency usage |
167
+ | `lore_graph` | Query call/import/module/inheritance edges; call edges include `callee_coverage_percent` |
168
+ | `lore_snippet` | Return snippets from indexed source snapshots by file path + line range or by symbol name; path/symbol resolution is branch-aware and responses include containing-symbol context metadata (name, kind, start/end lines) when available |
169
+ | `lore_test_map` | Return mapped test files (with confidence) for a given source file path |
170
+ | `lore_blame` | Query blame, line-range history, or ownership aggregates with optional symbol targeting, commit-context enrichment, and risk signals |
171
+ | `lore_history` | Query commit history by file, commit, author, ref, recency, or semantic commit-message similarity |
172
+ | `lore_commit_stats` | Git commit analytics: cadence, size, churn, top authors, message patterns, schedule heatmaps, branch activity |
173
+ | `lore_metrics` | Aggregate index metrics plus coverage/staleness fields |
174
+ | `lore_coverage` | Symbol-level coverage, uncovered lines, and staleness metadata |
175
+ | `lore_writeback` | Persist agent-authored symbol summaries |
176
+
177
+ ### lore_lookup query options
178
+
179
+ For symbol lookups (`kind: "symbol"`), `lore_lookup` supports:
180
+
181
+ - `match_mode`: optional symbol-name matching mode (`exact`, `prefix`, `contains`); defaults to `exact` (case-insensitive).
182
+ - `symbol_kind`: optional symbol kind filter (for example, `function` or `class`).
183
+ - `path_prefix`: optional indexed file-path prefix filter.
184
+ - `language`: optional indexed file language filter.
185
+ - `limit`: optional maximum rows for empty/browse symbol queries (default `20`).
186
+ - `offset`: optional rows to skip for empty/browse symbol queries (default `0`).
187
+
188
+ Example symbol lookup requests:
190
189
 
191
- // Index with embedding model + history options
192
- await new IndexBuilder(
193
- './kb.db',
194
- {
195
- rootDir: './my-project',
196
- includeGlobs: ['src/**'],
197
- excludeGlobs: ['**/*.gen.ts'],
198
- extensions: ['.ts', '.tsx'],
199
- },
200
- undefined,
201
- {
202
- embeddingModel: 'Qwen/Qwen3-Embedding-4B',
203
- history: { all: true, depth: 2000 },
204
- },
205
- ).build();
190
+ ```json
191
+ { "kind": "symbol", "query": "IndexBuilder", "match_mode": "prefix", "symbol_kind": "class" }
192
+ { "kind": "symbol", "query": "", "path_prefix": "src/indexer/", "language": "typescript", "limit": 20, "offset": 20 }
206
193
  ```
207
194
 
208
- ## CLI reference
195
+ ### MCP config example
209
196
 
210
- ### lore index
197
+ ```json
198
+ {
199
+ "mcpServers": {
200
+ "lore": {
201
+ "command": "npx",
202
+ "args": ["@jafreck/lore", "mcp", "--db", "/path/to/lore.db"]
203
+ }
204
+ }
205
+ }
206
+ ```
211
207
 
212
- Build or update a knowledge base.
208
+ ### lore_docs examples
213
209
 
214
- ```bash
215
- npx @jafreck/lore index --root <dir> --db <path> [--embedding-model <id>] [--history] [--history-depth <n>] [--history-all] [--include <glob>] [--exclude <glob>] [--language <lang>]
210
+ ```json
211
+ { "action": "list", "branch": "main", "kinds": ["readme", "architecture"] }
212
+ { "action": "get", "path": "/repo/docs/architecture.md", "branch": "main", "include_sections": true }
213
+ { "action": "search", "query": "incremental refresh", "kinds": ["guide", "architecture"], "limit": 10 }
216
214
  ```
217
215
 
218
- Key flags:
216
+ ### lore_search filter parameters
219
217
 
220
- - `--root <dir>` required source root
221
- - `--db <path>` required SQLite output path
222
- - `--embedding-model <id>` embedding model identifier
223
- - `--history` enable git history ingestion
224
- - `--history-depth <n>` cap number of ingested commits
225
- - `--history-all` traverse all refs (branches/tags)
226
- - `--include` repeatable glob include filter
227
- - `--exclude` repeatable glob exclude filter
228
- - `--language` repeatable language filter (mapped to extensions)
218
+ `lore_search` supports additional optional filters to narrow symbol and documentation hits:
229
219
 
230
- ### lore refresh
220
+ | Parameter | Applies to | Description |
221
+ |-----------|------------|-------------|
222
+ | `path_prefix` | Symbol results | Restrict symbol hits to files whose source path starts with the prefix |
223
+ | `language` | Symbol results | Restrict symbol hits to indexed file language (for example `typescript`, `python`) |
224
+ | `kind` | Symbol results | Restrict symbol hits to a symbol kind (for example `function`, `class`) |
225
+ | `doc_path_prefix` | Doc-section results | Restrict semantic/fused doc hits to docs whose path starts with the prefix |
226
+ | `doc_kind` | Doc-section results | Restrict semantic/fused doc hits to a documentation kind (for example `readme`, `architecture`) |
231
227
 
232
- Incremental refresh flow for an existing index.
228
+ Mode behavior:
233
229
 
234
- ```bash
235
- npx @jafreck/lore refresh --db <path> --root <dir> [--history] [--history-depth <n>] [--history-all]
236
- npx @jafreck/lore refresh --db <path> --root <dir> --watch [--history]
237
- npx @jafreck/lore refresh --db <path> --root <dir> --poll [--history]
230
+ - `structural`: returns symbol hits only; applies `path_prefix`, `language`, and `kind`.
231
+ - `semantic`: may return symbol and doc-section hits; symbol filters (`path_prefix`, `language`, `kind`) apply to symbol results, while `doc_path_prefix` and `doc_kind` apply to doc-section results before ranking output.
232
+ - `fused`: combines structural and semantic candidates; symbol filters apply to symbol candidates and doc filters apply to semantic doc-section candidates before final fused ranking.
233
+
234
+ ### lore_history modes
235
+
236
+ | Mode | Query |
237
+ |------|-------|
238
+ | `recent` | Newest commits |
239
+ | `semantic` | Conceptual commit-message search (falls back to `recent` when vectors are unavailable) |
240
+ | `file` | Commits that touched a path |
241
+ | `commit` | Full/prefix SHA lookup (+files +refs) |
242
+ | `author` | Commits by author/email substring |
243
+ | `ref` | Commits matching branch/tag ref name |
244
+
245
+ ### lore_blame examples
246
+
247
+ ```json
248
+ { "path": "/repo/src/index.ts", "line": 120 }
249
+ { "path": "/repo/src/index.ts", "start_line": 120, "end_line": 140 }
250
+ { "path": "/repo/src/index.ts", "line": 120, "ref": "main" }
251
+ { "symbol": "handleAuth", "path": "/repo/src/auth.ts", "branch": "main" }
252
+ { "mode": "history", "symbol": "handleAuth", "path": "/repo/src/auth.ts", "ref": "main" }
253
+ { "mode": "ownership", "path": "/repo/src", "scope": "directory", "ref": "main" }
238
254
  ```
239
255
 
240
- Modes:
256
+ Legacy line and line-range requests remain fully supported; `mode` defaults to `"blame"` when omitted.
257
+ History and ownership responses include commit context (`commits`, `history[*].commit_context` with message/files/refs) and `risk` indicators (`recency`, `author_dispersion`, `churn`, `overall`), and symbol-targeted requests return `resolved_symbol`.
241
258
 
242
- - Manual: one-shot incremental refresh and exit
243
- - Watch: filesystem event driven (`fs.watch`), low latency
244
- - Poll: periodic mtime diffing, most reliable across filesystems
259
+ ## Data ingestion
245
260
 
246
- Coverage reports are auto-detected during build/update/refresh from known paths (`coverage/lcov.info`, `coverage/cobertura-coverage.xml`, `coverage.xml`) and only ingested when newer than the last stored coverage run.
261
+ Lore indexes multiple data sources into a normalized SQLite schema. Each source
262
+ has its own ingestion pipeline and can be enabled independently.
247
263
 
248
- ### lore hooks
264
+ ### Source code
249
265
 
250
- Install repo-local git hooks that trigger Lore refresh automatically on:
266
+ The indexer walks source files, parses them into ASTs via tree-sitter, and
267
+ extracts symbols, imports, and call references through language-specific
268
+ extractors. The import resolver classifies each import as internal or external,
269
+ and a call-graph builder creates edges between symbols.
251
270
 
252
- - `post-commit`
253
- - `post-merge`
254
- - `post-checkout`
255
- - `post-rewrite`
271
+ Programmatic example:
256
272
 
257
- ```bash
258
- npx @jafreck/lore hooks --root <repo> --db <path>
259
- npx @jafreck/lore hooks --root <repo> --db <path> --history
273
+ ```ts
274
+ import { IndexBuilder } from '@jafreck/lore';
275
+
276
+ await new IndexBuilder('./lore.db', {
277
+ rootDir: './my-project',
278
+ includeGlobs: ['src/**'],
279
+ excludeGlobs: ['**/*.gen.ts'],
280
+ extensions: ['.ts', '.tsx'],
281
+ }).build();
260
282
  ```
261
283
 
262
- Note: for `lore hooks`, any history-related flag currently enables history in
263
- hook-triggered refreshes.
284
+ ### Documentation
264
285
 
265
- ### lore ingest-coverage
286
+ Lore discovers and indexes documentation files (`.md`, `.rst`, `.adoc`, `.txt`)
287
+ during both `index` and `refresh` flows. By default it scans:
266
288
 
267
- Manually ingest an explicit coverage report (useful for CI or non-standard report locations).
289
+ - `README*` variants
290
+ - `docs/**/*.{md,rst,adoc,txt}`
291
+ - ADR-style paths (`**/{adr,adrs,ADR,ADRS}/**/*` and `**/{ADR,adr}-*`)
292
+ - Top-level architecture/design/overview/changelog/guide files
268
293
 
269
- ```bash
270
- npx @jafreck/lore ingest-coverage --db <path> --root <dir> --file <path> --format <lcov|cobertura> [--commit <sha>]
294
+ Indexed docs are stored per `(path, branch)` in `docs`, with heading-based
295
+ chunks in `doc_sections`. When embeddings are enabled, section vectors are stored
296
+ in `doc_section_embeddings`.
297
+
298
+ CLI discovery controls:
299
+
300
+ - `--docs-include <glob>` / `--docs-exclude <glob>` — repeatable include/exclude filters
301
+ - `--docs-extension <ext>` — repeatable extension filter (e.g. `.md`)
302
+ - `--docs-auto-notes` / `--no-docs-auto-notes` — toggle seeded doc-note upserts (default: enabled)
303
+
304
+ When auto-notes are enabled, Lore seeds `notes` rows for README, architecture,
305
+ and ADR docs using deterministic keys. Each note tracks a `source_hash` for
306
+ staleness detection — `lore_notes_read` reports doc-scoped notes as stale when
307
+ the backing document changes or disappears.
308
+
309
+ Programmatic example:
310
+
311
+ ```ts
312
+ await new IndexBuilder('./lore.db', {
313
+ rootDir: './my-project',
314
+ docsIncludeGlobs: ['**/README*', 'handbook/**/*.rst'],
315
+ docsExcludeGlobs: ['**/docs/private/**'],
316
+ docsExtensions: ['.md', '.rst'],
317
+ }).build();
271
318
  ```
272
319
 
273
- Key flags:
320
+ ### Git history
274
321
 
275
- - `--db <path>` required SQLite output path
276
- - `--root <dir>` required repository root used to normalize relative coverage paths
277
- - `--file <path>` required coverage report file path
278
- - `--format <lcov|cobertura>` required coverage format
279
- - `--commit <sha>` optional commit override (defaults to `HEAD`)
322
+ Lore ingests commits, touched files (with change type and diff stats), and
323
+ refs (branches/tags). Enable with `--history`; use `--history-all` to traverse
324
+ all refs and `--history-depth <n>` to cap the number of commits.
280
325
 
281
- ### lore mcp
326
+ Indexed tables:
327
+
328
+ - `commits` — sha, author, author_email, timestamp, message, parents
329
+ - `commit_files` — per-commit touched paths with change type and diff stats
330
+ - `commit_refs` — refs currently pointing at commits (`branch`/`tag`/`other`)
331
+ - `commit_embeddings` — commit-message vectors keyed to `commits` for semantic history retrieval
332
+
333
+ Programmatic example:
334
+
335
+ ```ts
336
+ await new IndexBuilder('./lore.db', {
337
+ rootDir: './my-project',
338
+ }, undefined, {
339
+ history: { all: true, depth: 2000 },
340
+ }).build();
341
+ ```
282
342
 
283
- Start the built-in MCP server over stdio.
343
+ ### Coverage
344
+
345
+ Coverage reports are auto-detected during build/update/refresh from known paths
346
+ (`coverage/lcov.info`, `coverage/cobertura-coverage.xml`, `coverage.xml`) and
347
+ only ingested when newer than the last stored coverage run.
348
+
349
+ For non-standard report locations, use `lore ingest-coverage`:
284
350
 
285
351
  ```bash
286
- npx @jafreck/lore mcp --db <path>
352
+ npx @jafreck/lore ingest-coverage --db ./lore.db --root ./my-project \
353
+ --file ./custom/coverage.xml --format cobertura
287
354
  ```
288
355
 
289
- If the embedding model cannot initialize at runtime, semantic/fused search
290
- gracefully degrades to structural search.
356
+ ### Embeddings
291
357
 
292
- ## MCP tools
358
+ Lore optionally generates dense vector embeddings for semantic search using a
359
+ sentence-transformers model. The embedding model is downloaded and managed
360
+ automatically — specify it with `--embedding-model`:
293
361
 
294
- | Tool | Purpose |
295
- |------|---------|
296
- | `kb_lookup` | Find symbols by name or files by path (optional branch filter) |
297
- | `kb_search` | Structural BM25, semantic vector, or fused RRF search |
298
- | `kb_graph` | Query call/import/module/inheritance edges; call edges include `callee_coverage_percent` |
299
- | `kb_snippet` | Return source snippets by file path and line range |
300
- | `kb_blame` | Return git blame metadata for a line or line range |
301
- | `kb_history` | Query history by file, commit, author, ref, or recency |
302
- | `kb_metrics` | Return aggregate index metrics plus coverage/staleness fields (`coverage_available`, `coverage_commit`, `current_commit`, `commits_behind`, `stale`, global coverage totals) |
303
- | `kb_coverage` | Return symbol-level coverage, uncovered lines, and staleness metadata for the latest coverage run |
304
- | `kb_writeback` | Persist symbol summaries into `symbol_summaries` |
362
+ ```bash
363
+ npx @jafreck/lore index --root ./my-project --db ./lore.db \
364
+ --embedding-model 'Qwen/Qwen3-Embedding-4B'
365
+ ```
305
366
 
306
- ### MCP config example
367
+ At query time, `lore_search` in `semantic` or `fused` mode embeds the query
368
+ and performs cosine similarity against stored vectors. If the model cannot
369
+ initialize, search gracefully degrades to structural BM25.
370
+ When history indexing is enabled, Lore also stores commit-message vectors in
371
+ `commit_embeddings` so `lore_history` can serve semantic commit retrieval.
372
+
373
+ ### LSP enrichment
374
+
375
+ Lore can enrich symbols and call refs with resolved type metadata at index time
376
+ by querying language servers via the Language Server Protocol. Enriched columns:
377
+
378
+ - `resolved_type_signature`, `resolved_return_type`
379
+ - `definition_uri`, `definition_path`
380
+
381
+ These are persisted in `symbols`, `symbol_refs`, and `external_symbols` tables.
382
+ `lore_lookup` and `lore_search` return them when present. Query handlers stay
383
+ SQLite-only — language servers are never invoked at runtime.
384
+
385
+ LSP precedence:
386
+
387
+ 1. CLI flags (`--lsp` / `--no-lsp`)
388
+ 2. `.lore.config` `lsp.enabled`
389
+ 3. Built-in default (`false`)
390
+
391
+ `.lore.config` example:
307
392
 
308
393
  ```json
309
394
  {
310
- "mcpServers": {
311
- "lore": {
312
- "command": "npx",
313
- "args": ["@jafreck/lore", "mcp", "--db", "/path/to/kb.db"]
395
+ "lsp": {
396
+ "enabled": true,
397
+ "timeoutMs": 5000,
398
+ "servers": {
399
+ "typescript": { "command": "typescript-language-server", "args": ["--stdio"] },
400
+ "python": { "command": "pyright-langserver", "args": ["--stdio"] }
314
401
  }
315
402
  }
316
403
  }
317
404
  ```
318
405
 
319
- ## Git history indexing
406
+ Default server mappings cover all supported extractor languages:
320
407
 
321
- Lore can ingest full git history and expose it through `kb_history`.
408
+ | Language(s) | Default command |
409
+ |-------------|------------------|
410
+ | `c`, `cpp`, `objc` | `clangd` |
411
+ | `rust` | `rust-analyzer` |
412
+ | `python` | `pyright-langserver --stdio` |
413
+ | `typescript`, `javascript` | `typescript-language-server --stdio` |
414
+ | `go` | `gopls` |
415
+ | `java` | `jdtls` |
416
+ | `csharp` | `csharp-ls` |
417
+ | `ruby` | `solargraph stdio` |
418
+ | `php` | `intelephense --stdio` |
419
+ | `swift` | `sourcekit-lsp` |
420
+ | `kotlin` | `kotlin-language-server` |
421
+ | `scala` | `metals` |
422
+ | `lua` | `lua-language-server` |
423
+ | `bash` | `bash-language-server start` |
424
+ | `elixir` | `elixir-ls` |
425
+ | `zig` | `zls` |
426
+ | `dart` | `dart language-server --protocol=lsp` |
427
+ | `ocaml` | `ocamllsp` |
428
+ | `haskell` | `haskell-language-server-wrapper --lsp` |
429
+ | `julia` | `julia --startup-file=no --history-file=no --quiet --eval "using LanguageServer, SymbolServer; runserver()"` |
430
+ | `elm` | `elm-language-server` |
322
431
 
323
- ### Indexed history tables
432
+ Install whichever language servers you need on `PATH`; unavailable servers are
433
+ auto-detected and skipped without failing indexing.
324
434
 
325
- - `commits`: sha, author, author_email, timestamp, message, parents
326
- - `commit_files`: per-commit touched paths with change type and diff stats
327
- - `commit_refs`: refs currently pointing at commits (`branch`/`tag`/`other`)
435
+ ### Dependency APIs
328
436
 
329
- ### kb_history modes
437
+ Lore can index declaration-level public API surface from direct dependencies.
438
+ Enable with `--index-deps` or `indexDependencies: true` programmatically.
330
439
 
331
- - `recent`: newest commits
332
- - `file`: commits that touched a path
333
- - `commit`: full/prefix sha lookup (+files +refs)
334
- - `author`: commits by author/email substring
335
- - `ref`: commits matching branch/tag ref name substring
440
+ Supported ecosystems:
336
441
 
337
- ## Blame queries
442
+ - **TypeScript/JavaScript** — exported declarations from `.d.ts` files in direct npm dependencies
443
+ - **Python** — stubbed/public declarations from direct dependencies via `.pyi` and `py.typed`
444
+ - **Go** — exported declarations from direct module requirements in `go.mod`
445
+ - **Rust** — `pub` declarations from crates in `Cargo.toml`
338
446
 
339
- Use `kb_blame` for line-level attribution.
447
+ Implementation bodies are excluded and transitive dependencies are not crawled.
340
448
 
341
- Examples:
449
+ ## Keeping the index fresh
342
450
 
343
- ```json
344
- { "path": "/repo/src/index.ts", "line": 120 }
345
- { "path": "/repo/src/index.ts", "start_line": 120, "end_line": 140 }
346
- { "path": "/repo/src/index.ts", "line": 120, "ref": "main" }
451
+ The index stays current automatically through three mechanisms:
452
+
453
+ **Git hooks** install once with `lore hooks`, and Lore refreshes on every
454
+ `post-commit`, `post-merge`, `post-checkout`, and `post-rewrite`:
455
+
456
+ ```bash
457
+ npx @jafreck/lore hooks --root ./my-project --db ./lore.db --history
347
458
  ```
348
459
 
349
- ## Automatic freshness patterns
460
+ **Watch mode** reacts to filesystem events in real time:
350
461
 
351
- If you want Lore to stay updated without explicit requests:
462
+ ```bash
463
+ npx @jafreck/lore refresh --db ./lore.db --root ./my-project --watch
464
+ ```
352
465
 
353
- 1. Run `lore hooks` once in the repo (git lifecycle updates)
354
- 2. Optionally run `lore refresh --watch` in a background session for near-real-time updates during active editing
355
- 3. Use `--poll` on filesystems where watch events are unreliable
466
+ **Poll mode** periodic mtime diffing, most reliable across filesystems:
356
467
 
357
- ## Benchmarking index performance (500+ file repos)
468
+ ```bash
469
+ npx @jafreck/lore refresh --db ./lore.db --root ./my-project --poll
470
+ ```
358
471
 
359
- Use this procedure when you need measurable before/after evidence for indexing changes:
472
+ Each refresh only re-processes files whose content hash has changed, so updates
473
+ are fast even on large repositories.
360
474
 
361
- 1. Pick a repository with at least 500 source files and note the exact commit SHA you will test.
362
- 2. Capture a baseline timing from the same machine and environment:
475
+ ## CLI reference
476
+
477
+ ### lore index
478
+
479
+ Build or update a knowledge base.
363
480
 
364
481
  ```bash
365
- time npx @jafreck/lore index --root /path/to/repo --db ./kb-baseline.db
482
+ npx @jafreck/lore index --root <dir> --db <path> [--embedding-model <id>] [--index-deps] [--history] [--history-depth <n>] [--history-all] [--include <glob>] [--exclude <glob>] [--language <lang>] [--docs-include <glob>] [--docs-exclude <glob>] [--docs-extension <ext>] [--docs-auto-notes|--no-docs-auto-notes] [--lsp] [--no-lsp]
366
483
  ```
367
484
 
368
- 3. Apply your change, rebuild Lore, then capture a post-change timing against the same repository commit:
485
+ ### lore refresh
486
+
487
+ Incremental refresh (one-shot, watch, or poll).
369
488
 
370
489
  ```bash
371
- npm run build
372
- time npx @jafreck/lore index --root /path/to/repo --db ./kb-after.db
490
+ npx @jafreck/lore refresh --db <path> --root <dir> [--index-deps] [--history] [--history-depth <n>] [--history-all] [--docs-include <glob>] [--docs-exclude <glob>] [--docs-extension <ext>] [--docs-auto-notes|--no-docs-auto-notes] [--lsp] [--no-lsp]
491
+ npx @jafreck/lore refresh --db <path> --root <dir> --watch [--index-deps] [--history] [--docs-include <glob>] [--docs-exclude <glob>] [--docs-extension <ext>] [--lsp] [--no-lsp]
492
+ npx @jafreck/lore refresh --db <path> --root <dir> --poll [--index-deps] [--history] [--docs-include <glob>] [--docs-exclude <glob>] [--docs-extension <ext>] [--lsp] [--no-lsp]
373
493
  ```
374
494
 
375
- 4. Record both timings (baseline and post-change) in the related GitHub issue or PR under an "Acceptance Evidence" section, including repo name, commit SHA, and command used.
495
+ ### lore hooks
496
+
497
+ Install repo-local git hooks for automatic refresh.
498
+
499
+ ```bash
500
+ npx @jafreck/lore hooks --root <repo> --db <path> [--history] [--lsp] [--no-lsp]
501
+ ```
502
+
503
+ ### lore ingest-coverage
504
+
505
+ Manually ingest a coverage report.
506
+
507
+ ```bash
508
+ npx @jafreck/lore ingest-coverage --db <path> --root <dir> --file <path> --format <lcov|cobertura> [--commit <sha>]
509
+ ```
510
+
511
+ ### lore mcp
512
+
513
+ Start the MCP server over stdio.
514
+
515
+ ```bash
516
+ npx @jafreck/lore mcp --db <path>
517
+ ```
376
518
 
377
519
  ## Build from source
378
520
 
@@ -400,6 +542,64 @@ npm run coverage
400
542
 
401
543
  CI enforces a minimum 95% coverage threshold.
402
544
 
545
+ ## Publish authentication (npm)
546
+
547
+ Lore publish operations use `NODE_AUTH_TOKEN` (see `.npmrc`) and never commit
548
+ tokens to the repository.
549
+
550
+ Local publish flow:
551
+
552
+ ```bash
553
+ export NODE_AUTH_TOKEN=<npm automation token>
554
+ npm publish --access public
555
+ ```
556
+
557
+ CI publish flow:
558
+
559
+ - Add `NODE_AUTH_TOKEN` as a secret in your CI provider (for GitHub Actions,
560
+ use a repository or environment secret).
561
+ - Ensure publish jobs expose that secret as the `NODE_AUTH_TOKEN` environment
562
+ variable before running `npm publish`.
563
+
564
+ ## Release publish workflow (`@jafreck/lore@0.1.0`)
565
+
566
+ Publishing is automated by `.github/workflows/publish.yml`. Creating a version
567
+ tag (for example, `v0.1.0`) or publishing a GitHub Release triggers the npm
568
+ publish job.
569
+
570
+ Release steps for `@jafreck/lore@0.1.0`:
571
+
572
+ 1. Ensure `package.json` has `"version": "0.1.0"`.
573
+ 2. Push the tag: `git tag v0.1.0 && git push origin v0.1.0` (or publish a
574
+ GitHub Release for `v0.1.0`).
575
+ 3. Confirm the workflow logs show `npm publish --dry-run` output before the
576
+ live `npm publish` step.
577
+
578
+ Post-publish verification:
579
+
580
+ - Check the package metadata: `npm view @jafreck/lore version` returns `0.1.0`.
581
+ - Confirm installability: `npm view @jafreck/lore@0.1.0 name version`.
582
+
583
+ ## Benchmarking index performance (500+ file repos)
584
+
585
+ Use this procedure when you need measurable before/after evidence for indexing changes:
586
+
587
+ 1. Pick a repository with at least 500 source files and note the exact commit SHA you will test.
588
+ 2. Capture a baseline timing from the same machine and environment:
589
+
590
+ ```bash
591
+ time npx @jafreck/lore index --root /path/to/repo --db ./lore-baseline.db
592
+ ```
593
+
594
+ 3. Apply your change, rebuild Lore, then capture a post-change timing against the same repository commit:
595
+
596
+ ```bash
597
+ npm run build
598
+ time npx @jafreck/lore index --root /path/to/repo --db ./lore-after.db
599
+ ```
600
+
601
+ 4. Record both timings (baseline and post-change) in the related GitHub issue or PR under an "Acceptance Evidence" section, including repo name, commit SHA, and command used.
602
+
403
603
  ## License
404
604
 
405
605
  [MIT](LICENSE)