@saleem11kh/repomem 0.3.1 → 0.4.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.
package/README.md CHANGED
@@ -37,7 +37,8 @@ your-project/
37
37
  ├── decisions/ ← architectural choices + why
38
38
  ├── sessions/ ← what was done, what's next
39
39
  ├── patterns/ ← reusable conventions for this codebase
40
- └── issues/ ← known gotchas, do-not-repeat mistakes
40
+ ├── issues/ ← known gotchas, do-not-repeat mistakes
41
+ └── REPOMEM.md ← auto-generated index of everything above
41
42
  ```
42
43
 
43
44
  Plain markdown files. No database. No cloud. No vendor lock-in.
@@ -48,63 +49,277 @@ Switch agents → same memory, because it's in the repo, not the tool.
48
49
 
49
50
  ---
50
51
 
51
- ## How it works
52
+ ## Quick start
52
53
 
53
- repomem runs as an MCP server. Your AI agent gets 4 tools:
54
+ ```bash
55
+ # 1. Install
56
+ npm install -g @saleem11kh/repomem
54
57
 
55
- | Tool | What it does |
56
- |---|---|
57
- | `mem_save` | Save a decision, pattern, issue, or session note (with a one-line summary + `[[links]]`) |
58
- | `mem_search` | Search across all memory files instantly (BM25 + recency ranked) |
59
- | `mem_context` | Get a lean context packet at session start — summaries, not full bodies |
60
- | `mem_get` | Expand a single entry (by file or `[[wikilink]]`) only when you need it |
61
- | `mem_handoff` | Write today's session file, ready to commit |
62
- | `mem_prime` | Bootstrap memory on an existing repo from its CLAUDE.md / docs |
63
-
64
- At the start of every session, your agent calls `mem_context()` and immediately knows:
65
- - What was worked on last session
66
- - Key architectural decisions and why they were made
67
- - Patterns and conventions for this specific codebase
68
- - Known issues to avoid repeating
69
- - What's next
70
-
71
- To keep context small, `mem_context` returns **one-line summaries**; the agent expands
72
- only what it needs with `mem_get`. Entries can cross-link with `[[wikilinks]]`, so related
73
- decisions, patterns, and issues travel together. Already have a context-rich repo? Run
74
- `mem_prime` once to seed memory from your existing `CLAUDE.md` and `docs/`.
58
+ # 2. Scaffold .repomem/ in your project
59
+ cd your-project
60
+ repomem init
61
+
62
+ # 3. Wire it to your agent
63
+ repomem setup claude-code # or: cursor | gemini | codex
64
+
65
+ # 4. Restart the agent, then approve the server when prompted
66
+ ```
67
+
68
+ **Step 4 is not optional.** MCP servers are loaded when the agent starts, so a server
69
+ wired mid-session does not exist in that session. Claude Code additionally requires
70
+ you to approve any server declared in a project's `.mcp.json` the first time you
71
+ launch with it.
72
+
73
+ Verify with `/mcp` — you should see `repomem` connected with six tools. There are no
74
+ slash commands to look for; MCP servers contribute **tools**, which never appear in
75
+ the `/` menu.
75
76
 
76
77
  ---
77
78
 
78
- ## Quick start
79
+ ## Usage
80
+
81
+ ### The six tools
82
+
83
+ Your agent calls these; you don't type them.
84
+
85
+ | Tool | Arguments | What it does |
86
+ |---|---|---|
87
+ | `mem_context` | `brief?` | Session-start packet: the last session, plus one-line summaries of decisions, patterns, and issues. Call it first. |
88
+ | `mem_get` | `file` | Expand one entry in full — by `type/filename`, bare filename, or `[[wikilink]]` slug. |
89
+ | `mem_search` | `query`, `linked?` | BM25 + recency ranked search across all memory. `linked=true` also searches linked repos and the workspace. |
90
+ | `mem_save` | `type`, `title`, `content`, `summary?`, `tags?`, `links?`, `supersedes?`, `session?` | Write a `decision`, `pattern`, `issue`, or `session` note. |
91
+ | `mem_handoff` | `summary`, `done?`, `next?`, `blockers?`, `session?`, `git?` | Close out a session so the next one picks up exactly where you left off. Fills in what changed from git. |
92
+ | `mem_prime` | — | Bootstrap memory on an existing repo from its `CLAUDE.md` / `README.md` / `docs/`. Run once when adopting. |
93
+
94
+ ### Progressive disclosure — why context stays small
95
+
96
+ `mem_context` deliberately returns **one-line summaries**, not full bodies. It runs at
97
+ the start of every session; if it dumped everything, a repo with 50 memories would
98
+ burn thousands of tokens before your first message.
99
+
100
+ ```
101
+ ## Recent decisions
102
+ - BM25 + recency ranking instead of embeddings — Search is BM25 over raw markdown
103
+ with an exponential recency boost — no embeddings, zero extra deps.
104
+ (decisions/2026-07-26-bm25-recency-ranking-instead-of-embeddings.md)
105
+ ```
106
+
107
+ The agent expands only what it needs with `mem_get`. This is why **every entry should
108
+ have a `summary`** — it's the only thing most future sessions will ever read.
109
+
110
+ ### A normal session
111
+
112
+ **At the start**, the agent calls `mem_context` and immediately knows what was worked
113
+ on last, the key decisions and why, the conventions for this codebase, and known
114
+ gotchas.
115
+
116
+ **During work**, you capture things as they happen:
117
+
118
+ > "Save that as a decision — include why we rejected the alternative."
119
+
120
+ **At the end:**
121
+
122
+ > "Run mem_handoff."
123
+
124
+ Then commit. Nothing is shared with your team until you do:
79
125
 
80
126
  ```bash
81
- # Install
82
- npm install -g @saleem11kh/repomem
127
+ git add .repomem/ && git commit -m "chore: update memory"
128
+ ```
83
129
 
84
- # Initialize in your project
85
- cd your-project
86
- repomem init
130
+ ### What to say
131
+
132
+ repomem has no slash commands. You talk to your agent normally; it picks the tool.
87
133
 
88
- # Wire to Claude Code
134
+ | You want | Say |
135
+ |---|---|
136
+ | Load context | *"What's in repomem for this project?"* |
137
+ | Capture a choice | *"Save that as a decision, with why we rejected X"* |
138
+ | Capture a convention | *"Save that as a pattern"* |
139
+ | Capture a gotcha | *"Save that as an issue, with the guard against it"* |
140
+ | Replace a stale decision | *"Save this as a decision that supersedes `<filename>`"* |
141
+ | Sweep the whole session | *"Update repomem with what we did — skip anything obvious from the code"* |
142
+ | Close out | *"Run mem_handoff"* |
143
+ | Recall | *"Search repomem for how we handle retries"* |
144
+
145
+ Adding **"skip anything obvious from the code"** matters — otherwise you accumulate
146
+ entries restating function signatures, and the signal-to-noise ratio that makes memory
147
+ worth loading degrades.
148
+
149
+ ### Adopting on an existing project
150
+
151
+ `repomem init` gives you empty folders. To seed them from a repo that already has
152
+ years of context:
153
+
154
+ ```bash
155
+ cd your-existing-project
156
+ repomem init
89
157
  repomem setup claude-code
158
+ # restart the agent
159
+ ```
160
+
161
+ Then, in the agent:
162
+
163
+ > "Call `mem_prime`, then save what it surfaces as decisions, patterns, and issues."
164
+
165
+ `mem_prime` gathers `CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `README.md`, and
166
+ `docs/**.md` (up to 12 files) and returns them with instructions to distil them into
167
+ memory. **It writes nothing itself** — it needs an agent in the loop. Re-running it is
168
+ safe: it reads the existing count first and is told not to duplicate.
169
+
170
+ If your project has no docs, the higher-value move is to point the agent at the code:
171
+
172
+ > "Read the source under `src/`, then save what you learned as decisions, patterns,
173
+ > and issues. Give every entry a one-line summary and cross-link related entries."
174
+
175
+ Aim for 5–12 entries. Fewer and `mem_context` says nothing useful; many more in one
176
+ sitting and quality drops.
177
+
178
+ ### Handoffs are half-derived
179
+
180
+ `mem_handoff` does not rely on the agent remembering what it touched. Since the
181
+ session knows when it started, repomem asks git directly:
182
+
183
+ ```markdown
184
+ ## 2026-07-26 14:30 — Handoff
185
+
186
+ Reworked how sessions are identified.
187
+
188
+ _branch: master_
189
+
190
+ **Committed this session:**
191
+ - 1038eb6 fix(cli): route MCP config through cmd.exe on Windows
192
+ - ce365ab chore(repomem): record the Windows MCP spawn gotcha
90
193
 
91
- # Wire to Cursor
92
- repomem setup cursor
194
+ **Still uncommitted:**
195
+ - M src/tools/mem-context.ts
196
+ - ?? src/store/git.ts
93
197
 
94
- # Wire to Gemini CLI
95
- repomem setup gemini
198
+ **Next:**
199
+ - push the tag
96
200
  ```
97
201
 
98
- That's it. Your agent now has persistent memory that lives in your repo.
202
+ The agent supplies only what git cannot know *why*, and *what's next*. Commits and
203
+ uncommitted files are facts, and deriving them is both cheaper and more reliable than
204
+ asking a model to recall them.
99
205
 
206
+ Notes:
207
+ - Changes under `.repomem/` are filtered out; the handoff is writing there as it runs.
208
+ - Long lists are capped at 20 with an explicit `…and N more`, never silently truncated.
209
+ - Non-git projects, missing `git`, and empty repos all degrade quietly to a handoff
210
+ with no git detail. Pass `git: false` to skip it deliberately.
211
+ - Commits are matched by *time*, so parallel sessions each report the same commits.
212
+ Time is the only signal available without asking agents to tag their own work.
213
+
214
+ ### Sessions and parallel agents
215
+
216
+ Each session owns one file:
217
+
218
+ ```
219
+ .repomem/sessions/2026-07-26-0917-windows-mcp-fix.md
220
+ .repomem/sessions/2026-07-26-1430-auth-refactor.md
221
+ ```
222
+
223
+ `YYYY-MM-DD-HHMM-<name>.md`, where the timestamp is when the session *started* — so it
224
+ stays put as the session appends, and because it's zero-padded, filename order is
225
+ chronological order.
226
+
227
+ Name a session by passing `session` to `mem_save` or `mem_handoff` (*"run mem_handoff,
228
+ call this session auth-refactor"*). Unnamed sessions are `untitled`; naming one later
229
+ renames the file in place, so one session always maps to one file.
230
+
231
+ This matters most when **more than one session runs at once** — two terminals, two
232
+ agents, or two teammates:
233
+
234
+ - Separate files mean no interleaving and **no git merge conflicts**
235
+ - Sessions are linkable: a decision can point at `[[auth-refactor]]`
236
+ - `mem_context` inlines the newest session and lists the others under **Also today**,
237
+ so parallel work is visible without being loaded in full
238
+ - The connecting agent is recorded automatically (`agent: claude-code`), taken from the
239
+ MCP handshake — so parallel sessions from different tools are tellable apart
240
+
241
+ ### Anatomy of a memory file
242
+
243
+ ```markdown
100
244
  ---
245
+ date: 2026-07-26
246
+ summary: Search is BM25 over raw markdown with a recency boost — no embeddings.
247
+ tags: [search, ranking]
248
+ ---
249
+ # BM25 + recency ranking instead of embeddings
101
250
 
102
- ## Multi-repo support
251
+ Why not embeddings: they add a model dependency and a cache to invalidate, which
252
+ breaks the "plain files, no infra" promise.
103
253
 
104
- Working across microservices or a multi-repo setup? repomem handles it.
254
+ Related: [[memory-lives-in-the-repo-as-plain-markdown]]
255
+ ```
105
256
 
106
- ```json
107
- // repomem.config.json
257
+ - **`summary`** — the one line `mem_context` and `mem_search` show. Always set it.
258
+ - **`tags`** — free-form, for retrieval.
259
+ - **`supersedes`** — on a decision, the filename it replaces. Keeps the history.
260
+ - **`[[wikilinks]]`** — resolve by slug regardless of date prefix. `mem_search` and
261
+ `mem_context` traverse them and show `→ related:`, so linked entries travel together.
262
+
263
+ Filenames are `YYYY-MM-DD-<slug>.md`. The date prefix is load-bearing: it drives
264
+ newest-first ordering and the search recency boost.
265
+
266
+ ### Editing and correcting
267
+
268
+ There's no update tool. Two paths:
269
+
270
+ - **Superseding a decision** — `mem_save` with `supersedes: <filename>` records the
271
+ replacement and keeps the history. This is the intended path.
272
+ - **Fixing a mistake** — just edit the markdown file. It's plain text in your repo.
273
+
274
+ ⚠️ Saving twice on the same day with the same title **overwrites silently** — the
275
+ filename is `date-slug` and `slugify` truncates at 60 characters, so two long titles
276
+ sharing a prefix collide. Use short, distinct titles.
277
+
278
+ ---
279
+
280
+ ## CLI reference
281
+
282
+ ```
283
+ repomem Start the MCP server (stdio) — how agents invoke it
284
+ repomem init Scaffold .repomem/ and repomem.config.json
285
+ repomem setup <agent> Wire repomem into claude-code | cursor | gemini | codex
286
+ repomem status Show memory counts, configured agents, linked repos
287
+ repomem sync Export all memory to stdout
288
+ repomem import [file] Import a sync bundle (file or stdin) into .repomem/
289
+ repomem pull Fetch remote linked repos' memory from GitHub
290
+ repomem help Show this help
291
+ ```
292
+
293
+ `init` is idempotent — re-running it regenerates `REPOMEM.md` without touching config.
294
+
295
+ `sync` and `import` are inverses, for airgapped transfer:
296
+
297
+ ```bash
298
+ repomem sync > bundle.md # on the connected machine
299
+ repomem import bundle.md # on the airgapped one
300
+ ```
301
+
302
+ Where `setup` writes each agent's config:
303
+
304
+ | Agent | File |
305
+ |---|---|
306
+ | Claude Code | `.mcp.json` (repo root — **not** `.claude/mcp.json`) |
307
+ | Cursor | `.cursor/mcp.json` |
308
+ | Gemini CLI | `.gemini/settings.json` |
309
+ | Codex | `.codex/config.toml` |
310
+
311
+ On Windows the generated command is wrapped in `cmd /c`, because agents spawn MCP
312
+ servers without a shell and `npx` is a `.cmd` shim there. That makes the generated
313
+ config **host-specific** — a teammate on macOS or Linux should re-run `repomem setup`
314
+ to rewrite it.
315
+
316
+ ---
317
+
318
+ ## Multi-repo
319
+
320
+ Working across microservices? Declare related repos in `repomem.config.json`:
321
+
322
+ ```jsonc
108
323
  {
109
324
  "project": "payments-service",
110
325
  "workspace": "../repomem-workspace",
@@ -117,19 +332,44 @@ Working across microservices or a multi-repo setup? repomem handles it.
117
332
  ```
118
333
 
119
334
  Linked repos can be **local paths** or **remote GitHub repos** (`github:owner/name`,
120
- optionally `#ref`). For remotes, run `repomem pull` once to fetch their `.repomem/`
121
- into a local, gitignored cache no full clone needed. A `GITHUB_TOKEN`/`GH_TOKEN`
122
- env var is used for private repos and higher rate limits.
335
+ optionally `#ref`). For remotes, run `repomem pull` once it fetches only their
336
+ `.repomem/` subtree through the GitHub API into a local, gitignored cache. No full
337
+ clone. Set `GITHUB_TOKEN`/`GH_TOKEN` for private repos and higher rate limits.
338
+
339
+ Then `mem_search` with `linked=true` searches current + linked + remote + workspace,
340
+ ranked together and labelled by source:
123
341
 
124
- When your agent calls `mem_search` with `linked=true`, repomem searches:
125
- 1. Current repo memory
126
- 2. Linked repo memory — local paths and pulled remotes (contracts, shared patterns)
127
- 3. Workspace memory (org-wide decisions)
342
+ ```
343
+ [current] [linked:auth-service] [remote:billing-svc] [workspace]
344
+ ```
345
+
346
+ Pull is explicit and manual — nothing refreshes in the background.
347
+
348
+ ---
349
+
350
+ ## Troubleshooting
351
+
352
+ **"I don't see any repomem commands."**
353
+ Expected. MCP servers contribute tools, not slash commands. Check `/mcp` instead — it
354
+ should list `repomem` as connected with six tools.
128
355
 
129
- Results are ranked (TF-IDF + recency) and labelled by source:
130
- `[current] [linked:auth-service] [remote:billing-svc] [workspace]`
356
+ **`/mcp` shows repomem as failed or missing.**
357
+ Three causes, in order of likelihood:
358
+ 1. You haven't restarted the agent since running `repomem setup`.
359
+ 2. The project's `.mcp.json` was never approved — the prompt only fires at startup.
360
+ 3. You're on Windows with a config generated by repomem ≤ 0.3.0, which used a bare
361
+ `npx` command that cannot be spawned without a shell. Re-run `repomem setup`.
131
362
 
132
- Cross-repository context that actually travels with the code — not locked in a personal tool on one machine.
363
+ **Tools appear but every call says `.repomem/ not found`.**
364
+ The server resolves the project root by walking up for `.repomem/` or
365
+ `repomem.config.json`. Run `repomem init` at the repo root.
366
+
367
+ **Working on repomem itself?** Point `.mcp.json` at your local build so you exercise
368
+ your changes rather than the published package:
369
+
370
+ ```json
371
+ { "mcpServers": { "repomem": { "command": "node", "args": ["dist/cli.js"] } } }
372
+ ```
133
373
 
134
374
  ---
135
375
 
@@ -149,38 +389,49 @@ Cross-repository context that actually travels with the code — not locked in a
149
389
 
150
390
  ## Roadmap
151
391
 
152
- - [x] npm package claimed
153
392
  - [x] `repomem init` — scaffold `.repomem/` in any project
154
- - [x] 4 core MCP tools (`mem_save`, `mem_search`, `mem_context`, `mem_handoff`)
155
- - [x] Claude Code wiring (`repomem setup claude-code`)
156
- - [x] Cursor wiring
157
- - [x] Gemini CLI / Codex wiring
158
- - [x] Multi-repo `linked` support (local paths)
393
+ - [x] Six MCP tools (`mem_save`, `mem_search`, `mem_context`, `mem_get`, `mem_handoff`, `mem_prime`)
394
+ - [x] Claude Code, Cursor, Gemini CLI, and Codex wiring
395
+ - [x] Multi-repo `linked` support — local paths and remote GitHub repos
159
396
  - [x] Workspace scope (cross-org shared memory repo)
160
- - [x] `repomem sync` export `.repomem/` to stdout for sharing
161
- - [x] Remote linked repos (read `.repomem/` from GitHub without cloning, via `repomem pull`)
162
- - [x] `repomem import` — import a sync bundle for airgapped environments
163
- - [x] Smarter search ranking (BM25 + recency weighting)
397
+ - [x] `repomem sync` / `import` for airgapped transfer
398
+ - [x] BM25 + recency search ranking
164
399
  - [x] Progressive disclosure — `mem_context` summaries + `mem_get` to expand
165
- - [x] `[[wikilink]]` graph between memories (traversed by search + context)
400
+ - [x] `[[wikilink]]` graph between memories
166
401
  - [x] `mem_prime` — bootstrap memory from an existing repo's docs
402
+ - [x] One file per session, with names, timestamps, and agent attribution
403
+ - [x] Git-derived handoffs — "what changed" comes from commits, not recollection
404
+ - [ ] `init` learns the repo — stack, commands, layout, ADRs, and git conventions, without an LLM
405
+ - [ ] `repomem prime` as a CLI, so onboarding can be scripted end-to-end
406
+ - [ ] Auto-capture hooks, so memory does not depend on remembering to ask
407
+ - [ ] Task-scoped `mem_context` and a token budget, for repos with lots of memory
167
408
  - [ ] Optional semantic search layer (off by default, local embedding cache)
168
409
 
169
410
  ---
170
411
 
171
412
  ## Status
172
413
 
173
- **v0.2 — working.** `init`, `setup`, `status`, `sync`, `import`, `pull`, and six
174
- MCP tools (`mem_save`, `mem_search`, `mem_context`, `mem_get`, `mem_handoff`,
175
- `mem_prime`) are implemented and tested. Context is token-lean by default
176
- (summaries + `mem_get` to expand), memories cross-link with `[[wikilinks]]`, and
177
- `mem_prime` bootstraps an existing repo from its docs. Multi-repo search spans
178
- local `linked` paths, remote GitHub repos (pulled into a local cache), and a
179
- shared `workspace`, ranked by BM25 with a recency boost.
414
+ **v0.3.1 — working.** `init`, `setup`, `status`, `sync`, `import`, `pull`, and six MCP
415
+ tools are implemented and covered by tests. Context is token-lean by default, memories
416
+ cross-link with `[[wikilinks]]`, `mem_prime` bootstraps an existing repo from its docs,
417
+ and multi-repo search spans local paths, pulled GitHub remotes, and a shared workspace.
418
+
419
+ **On `master`, not yet published:** one file per session
420
+ (`YYYY-MM-DD-HHMM-<name>.md`) with front matter, session naming, agent attribution
421
+ from the MCP handshake, `mem_context` listing parallel same-day sessions, and
422
+ git-derived handoffs. Landing in v0.4.
423
+
424
+ **The known gap:** nothing is recorded unless the agent is asked. MCP servers are
425
+ passive — they act only when a tool is called. Git-derived handoffs remove the recall
426
+ burden once a handoff is requested, but *requesting* it is still manual. Auto-capture
427
+ hooks are the planned fix.
180
428
 
181
- If this solves a problem you have, **star the repo** — it helps validate that this is worth building and tells me which features to prioritise first.
429
+ If this solves a problem you have, **star the repo** — it helps validate that this is
430
+ worth building and tells me which features to prioritise.
182
431
 
183
- Have this exact problem on your team? Open an [issue](https://github.com/saleem786khan/repomem/issues) describing your setup — I'm using real use cases to shape the v0.1 feature set.
432
+ Have this exact problem on your team? Open an
433
+ [issue](https://github.com/saleem786khan/repomem/issues) describing your setup — I'm
434
+ using real use cases to shape the roadmap.
184
435
 
185
436
  ---
186
437
 
@@ -192,11 +443,10 @@ repomem is being built in public. Contributions welcome at any stage.
192
443
  git clone https://github.com/saleem786khan/repomem
193
444
  cd repomem
194
445
  npm install
195
- npm run dev
446
+ npm test # builds, then runs the suite
196
447
  ```
197
448
 
198
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
199
- Good first issues will be labelled once the scaffold is up.
449
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
200
450
 
201
451
  ---
202
452
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA4BA,yDAAyD;AACzD,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAgDjD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA6BA,yDAAyD;AACzD,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAwDjD"}
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ const mem_context_js_1 = require("./tools/mem-context.js");
11
11
  const mem_handoff_js_1 = require("./tools/mem-handoff.js");
12
12
  const mem_get_js_1 = require("./tools/mem-get.js");
13
13
  const mem_prime_js_1 = require("./tools/mem-prime.js");
14
+ const session_js_1 = require("./tools/session.js");
14
15
  const TOOLS = [
15
16
  mem_save_js_1.memSave,
16
17
  mem_search_js_1.memSearch,
@@ -20,7 +21,7 @@ const TOOLS = [
20
21
  mem_prime_js_1.memPrime,
21
22
  ];
22
23
  const TOOL_MAP = new Map(TOOLS.map((t) => [t.name, t]));
23
- const VERSION = "0.3.1";
24
+ const VERSION = "0.4.0";
24
25
  /** Build and start the repomem MCP server over stdio. */
25
26
  async function startServer() {
26
27
  const server = new index_js_1.Server({ name: "repomem", version: VERSION }, {
@@ -32,6 +33,14 @@ async function startServer() {
32
33
  "recall, and mem_handoff to close out a session. On a project new to " +
33
34
  "repomem, call mem_prime once to bootstrap memory from existing docs.",
34
35
  });
36
+ // Attribute session memory to whichever agent connected. The client announces
37
+ // itself in `initialize`, so this costs nothing and makes parallel sessions
38
+ // from different agents tellable apart.
39
+ server.oninitialized = () => {
40
+ const client = server.getClientVersion();
41
+ if (client?.name)
42
+ (0, session_js_1.setSessionAgent)(client.name);
43
+ };
35
44
  server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
36
45
  tools: TOOLS.map((t) => ({
37
46
  name: t.name,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -18,7 +18,7 @@ export declare function getRepomemRoot(projectRoot?: string): string;
18
18
  export declare function isInitialized(projectRoot?: string): boolean;
19
19
  /**
20
20
  * List relative file paths (from .repomem/) of a given memory type, sorted
21
- * newest-first by filename. Returns [] when uninitialised or empty.
21
+ * newest-first. Returns [] when uninitialised or empty.
22
22
  */
23
23
  export declare function listFiles(type: MemoryType, projectRoot?: string): string[];
24
24
  /** Read a memory file by type + filename. Returns null when missing. */
@@ -1 +1 @@
1
- {"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../../src/store/file-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../../src/store/file-store.ts"],"names":[],"mappings":"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"}
@@ -70,9 +70,24 @@ function getRepomemRoot(projectRoot = (0, config_js_1.findProjectRoot)()) {
70
70
  function isInitialized(projectRoot = (0, config_js_1.findProjectRoot)()) {
71
71
  return fs.existsSync(getRepomemRoot(projectRoot));
72
72
  }
73
+ /**
74
+ * Chronological sort key for a memory filename: its `YYYY-MM-DD` prefix plus the
75
+ * `HHMM` that session files carry.
76
+ *
77
+ * Sorting raw names would be wrong here: `-` (0x2D) sorts before `.` (0x2E), so
78
+ * a legacy whole-day `2026-07-26.md` would outrank `2026-07-26-0917-x.md` from
79
+ * the same date and be mistaken for the newer file. Legacy day files get `0000`
80
+ * so any timed session that day counts as newer.
81
+ */
82
+ function fileOrderKey(filename) {
83
+ const m = filename.match(/^(\d{4}-\d{2}-\d{2})(?:-(\d{4})(?=-|\.))?/);
84
+ if (!m)
85
+ return "0000-00-00-0000";
86
+ return `${m[1]}-${m[2] ?? "0000"}`;
87
+ }
73
88
  /**
74
89
  * List relative file paths (from .repomem/) of a given memory type, sorted
75
- * newest-first by filename. Returns [] when uninitialised or empty.
90
+ * newest-first. Returns [] when uninitialised or empty.
76
91
  */
77
92
  function listFiles(type, projectRoot = (0, config_js_1.findProjectRoot)()) {
78
93
  const dir = path.join(getRepomemRoot(projectRoot), type);
@@ -80,7 +95,11 @@ function listFiles(type, projectRoot = (0, config_js_1.findProjectRoot)()) {
80
95
  return fs
81
96
  .readdirSync(dir)
82
97
  .filter((f) => f.endsWith(".md"))
83
- .sort()
98
+ .sort((a, b) => {
99
+ const ka = fileOrderKey(a);
100
+ const kb = fileOrderKey(b);
101
+ return ka === kb ? a.localeCompare(b) : ka < kb ? -1 : 1;
102
+ })
84
103
  .reverse();
85
104
  }
86
105
  catch {
@@ -169,9 +188,15 @@ function parseLinks(raw) {
169
188
  out.add(m[1].trim());
170
189
  return [...out];
171
190
  }
172
- /** Strip the date prefix and extension from a memory filename to get its slug. */
191
+ /**
192
+ * Strip the date (and, for session files, the HHMM) prefix and the extension to
193
+ * get a memory's slug — the thing [[wikilinks]] match against.
194
+ */
173
195
  function fileSlug(filename) {
174
- return filename.replace(/\.md$/i, "").replace(/^\d{4}-\d{2}-\d{2}-?/, "").toLowerCase();
196
+ return filename
197
+ .replace(/\.md$/i, "")
198
+ .replace(/^\d{4}-\d{2}-\d{2}-?(?:\d{4}-)?/, "")
199
+ .toLowerCase();
175
200
  }
176
201
  /**
177
202
  * Resolve a `[[target]]` to a memory file. Matches an exact filename, an exact