nexusmem 0.3.0 → 0.3.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.
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # NexusMem
2
2
 
3
+ [![CI](https://github.com/yaminbkk/NexusMem/actions/workflows/ci.yml/badge.svg)](https://github.com/yaminbkk/NexusMem/actions/workflows/ci.yml)
3
4
  [![npm](https://img.shields.io/npm/v/nexusmem)](https://www.npmjs.com/package/nexusmem)
5
+ [![npm downloads](https://img.shields.io/npm/dm/nexusmem)](https://www.npmjs.com/package/nexusmem)
4
6
  [![License: MIT](https://img.shields.io/badge/license-MIT-informational)](LICENSE)
5
7
  ![Node](https://img.shields.io/badge/node-%3E%3D22-brightgreen)
6
8
 
@@ -70,6 +72,55 @@ Requirements: Node 22 or newer, and git. Node 20 will not work, because `better-
70
72
  prebuilt binary for it and Node 20 went end-of-life in April 2026. Ollama is optional and only
71
73
  affects semantic search (see below).
72
74
 
75
+ ## Optional: exact shell capture
76
+
77
+ Scraped history files (PSReadLine, `.bash_history`, `.zsh_history`) give you command text and not
78
+ much else. The hook gives you working directory, exit code and a real timestamp:
79
+
80
+ ```bash
81
+ nexusmem hook install
82
+ ```
83
+
84
+ It wraps your existing PowerShell prompt rather than replacing it, is idempotent, and
85
+ `nexusmem hook remove` undoes it cleanly.
86
+
87
+ Exit codes are what make this worth installing. A failed command is a stronger signal than a
88
+ successful one, and without the hook there is no way to tell them apart.
89
+
90
+ ## Failure → fix chains (opt-in)
91
+
92
+ ```bash
93
+ nexusmem sync --link-failures
94
+ ```
95
+
96
+ After a normal sync, this walks every failed `shell_command` (non-zero exit code) and looks for
97
+ whatever later resolved it, using two independent heuristics: a later command in the same project
98
+ and working directory, exact same normalized text, that exited `0` within 24h (**same-command
99
+ retry**); and, separately, the best full-text match among nearby conversation turns or session
100
+ summaries, requiring every significant word of the failing command to appear, not just one
101
+ (**conversation bridge**). A failure can be linked by either, both, or neither.
102
+
103
+ Both links are surfaced in query results. The conversation-bridge heuristic originally matched on
104
+ any shared word, and dogfooding against this repo's own real history found it wrong on roughly half
105
+ its links — a shared word as generic as "npm" was enough to link an unrelated discussion. Requiring
106
+ every significant word fixed that: re-dogfooded against the same corpus, every resulting link (the
107
+ full set produced, not a sample) checked out correct on manual review of the full text, not just the
108
+ summary.
109
+
110
+ When a linked failure appears in a result set, its fix rides along immediately after it, inheriting
111
+ the failure's own relevance score rather than needing to match the query on its own merits. That is
112
+ the point: a query about why something failed shouldn't need to separately guess the words used in
113
+ whatever fixed it. This works across projects too — `query --all-projects` chains a failure to its
114
+ fix using whichever project's own database recorded the link, since links are always local to the
115
+ project they were found in.
116
+
117
+ ```
118
+ $ nexusmem query "why did npm whoami fail"
119
+
120
+ - 2026-08-12 shell: npm whoami (exit 1)
121
+ - 2026-08-12 shell: npm login (exit 0) -- linked as the fix
122
+ ```
123
+
73
124
  ## How retrieval works
74
125
 
75
126
  Every source normalizes to the same `MemoryNode` shape, so a commit, a shell command and a docs
@@ -155,21 +206,6 @@ Three tools over stdio: `search_memory` returns the packed context block, `sync_
155
206
  MCP tool call carries no shell working directory. `sync_project` runs `init` for you if the
156
207
  repository has not been set up.
157
208
 
158
- ## Optional: exact shell capture
159
-
160
- Scraped history files (PSReadLine, `.bash_history`, `.zsh_history`) give you command text and not
161
- much else. The hook gives you working directory, exit code and a real timestamp:
162
-
163
- ```bash
164
- nexusmem hook install
165
- ```
166
-
167
- It wraps your existing PowerShell prompt rather than replacing it, is idempotent, and
168
- `nexusmem hook remove` undoes it cleanly.
169
-
170
- Exit codes are what make this worth installing. A failed command is a stronger signal than a
171
- successful one, and without the hook there is no way to tell them apart.
172
-
173
209
  ## What it costs you
174
210
 
175
211
  Two numbers get conflated in tools like this, so they are kept apart here.
@@ -179,14 +215,40 @@ corpus it runs 81–84%. It is useful for tuning the ranker and useless as a cla
179
215
  because the baseline is hypothetical: without NexusMem those candidates were never going into your
180
216
  context window in the first place.
181
217
 
182
- **End-to-end saving** compares packed context against reading the equivalent files in full. Measured
183
- at **~40%** on design queries against this codebase, hand-tallied from one real session rather than
184
- instrumented. Treat it as an order of magnitude.
185
-
186
- The long-term target is >70%, and this repository cannot demonstrate it. That figure describes repos
187
- with thousands of commits, where the win comes from omitting hundreds of unrelated items rather than
188
- shaving a handful. A benchmark at that size is still outstanding, and until it exists the honest
189
- number is 40%.
218
+ **End-to-end saving** compares the packed context NexusMem actually sends against reading, in full,
219
+ the same files its own ranking identified as relevant to the query. Measured with
220
+ [`scripts/benchmark.ts`](scripts/benchmark.ts) (`npm run bench`), which anyone who clones this repo
221
+ and points it at a synced corpus can re-run from scratch:
222
+
223
+ | Corpus | Commits | Query set | vs. full file content | vs. `git log -p` on those files |
224
+ | --- | --- | --- | --- | --- |
225
+ | This repo | 62 | 16 real prompts, verbatim from this project's own history | 95% (median 94%) | 98% (median 97%) |
226
+ | [`vitejs/vite`](https://github.com/vitejs/vite) | 9,567 | 16, mechanically sampled — see below | 99% (median 98%) | ~100% (median ~100%) — see caveat |
227
+
228
+ Both clear the original >70% target ("cut API token spend versus sending full context"), and the vite
229
+ run is the first measurement at the scale that target was always described as applying to.
230
+
231
+ **Read the methodology before quoting either number, because it is a narrower claim than it looks:**
232
+
233
+ - The file set each query is graded against comes from NexusMem's *own* ranking — whichever files the
234
+ packed nodes for that query touch, not an outside judge's idea of the right answer. This isolates
235
+ what the pack step (rank → budget → excerpt) saves once retrieval has already picked a candidate
236
+ set; it does not independently verify that the candidate set was the right one to pick.
237
+ - The vite query set is not hand-picked: an even sample, across the full commit history, of
238
+ well-explained `fix`/`feat`/`perf`/`refactor` commits turned into "why does vite `<description>`"
239
+ from the commit's own conventional-commit text, plus rationale-bearing doc section headings. This
240
+ repo's own query set instead reuses real historical prompts verbatim from `conversation_turn`
241
+ nodes — several are broad task instructions rather than narrow questions, which pulls a wider file
242
+ set into scope and is part of why its number, while still high, sits below vite's. Both derivations
243
+ are mechanical and disclosed in `scripts/benchmark.ts`, neither is cherry-picked per-query.
244
+ - `git log -p` on a file touched by thousands of commits is enormous — one vite query's baseline hit
245
+ 7.5M tokens because a file in its resolved set has that much history. That is itself a finding, not
246
+ noise: at this scale, "just read the file's history instead" stops being a viable alternative at
247
+ all, which is a big part of why that column rounds to ~100%.
248
+ - **This supersedes the previous ~40% figure**, which was hand-tallied from two hand-picked queries
249
+ against this repo alone, never instrumented, and used an unstated baseline. It was not wrong so much
250
+ as underspecified — this number replaces it with a stated method and a script that reproduces it,
251
+ rather than being a claim that the product got better.
190
252
 
191
253
  One thing that is not a percentage: shell commands and conversation turns have no cheap `grep`
192
254
  equivalent. Without something recording them, they are gone, not merely more expensive to find.
@@ -241,6 +303,11 @@ optimizing, and it is somebody else's process.
241
303
  unmounted drive is not a deleted project.
242
304
  - **Conversation chunking is unevaluated.** Splitting long replies at heading boundaries measurably
243
305
  helped, but it has never been tested systematically.
306
+ - **A chunked node's sibling count in one result is capped, not tuned.** `conversation_turn` and
307
+ `doc_section` both split one reply or file into several nodes; at most 2 of them may appear
308
+ together in a packed result. Found live: a query for "token" returned 9 of its top 12 hits as
309
+ different pieces of one heavily-sectioned reply, crowding out the node that actually answered it.
310
+ The cap of 2 is a judgement call, not a measured optimum, same as the ranking priors' budget above.
244
311
  - **The size of the prior budget is a judgement call, not a measured optimum.** Priors are now
245
312
  bounded jointly rather than one at a time, which closed a real 4× hole (see the ranking section),
246
313
  but the 2× budget itself has never been tuned against a labelled relevance set — there isn't one.
@@ -260,8 +327,9 @@ is the intended way to tune scoring against a real repository before committing
260
327
  `--json` to pipe them somewhere.
261
328
 
262
329
  Every command takes `-C <path>` to target another repository. On `sync`, `--conversation` opts the
263
- transcript source in for one run without persisting it, `--no-embed` skips the vector pass, and
264
- `--rebuild` drops the project's nodes and re-ingests from scratch.
330
+ transcript source in for one run without persisting it, `--no-embed` skips the vector pass,
331
+ `--link-failures` builds the failure fix chains described above, and `--rebuild` drops the
332
+ project's nodes and re-ingests from scratch.
265
333
 
266
334
  ## Recall across projects
267
335
 
@@ -315,8 +383,8 @@ Deleting `.nexusmem/` loses nothing that `sync` cannot rebuild.
315
383
 
316
384
  ## Status
317
385
 
318
- Ingestion, hybrid retrieval, budgeted packing and the MCP server all work and are covered by 315
319
- tests running on Linux and Windows across Node 22 and 24. Phase 3 is complete.
386
+ Ingestion, hybrid retrieval, budgeted packing and the MCP server all work and are covered by 342
387
+ tests running on Linux and Windows across Node 22 and 24.
320
388
 
321
389
  ## Development
322
390