linksee-memory 0.11.2 → 0.11.3
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 +39 -0
- package/dist/db/migrate.js +42 -5
- package/dist/mcp/server.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -419,6 +419,26 @@ Add to `~/.gemini/settings.json`:
|
|
|
419
419
|
|
|
420
420
|
</details>
|
|
421
421
|
|
|
422
|
+
<details>
|
|
423
|
+
<summary><strong>Claude Desktop</strong></summary>
|
|
424
|
+
|
|
425
|
+
Add the same stdio command to `claude_desktop_config.json`:
|
|
426
|
+
|
|
427
|
+
```json
|
|
428
|
+
{
|
|
429
|
+
"mcpServers": {
|
|
430
|
+
"linksee": {
|
|
431
|
+
"command": "npx",
|
|
432
|
+
"args": ["-y", "linksee-memory"]
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Config file: macOS `~/Library/Application Support/Claude/`, Windows `%APPDATA%\Claude\`. Restart Claude Desktop.
|
|
439
|
+
|
|
440
|
+
</details>
|
|
441
|
+
|
|
422
442
|
All editors share the same `~/.linksee-memory/memory.db`. A decision made in Claude Code is recalled in Cursor. A caveat recorded in Windsurf prevents the same mistake in Codex.
|
|
423
443
|
|
|
424
444
|
### Database location
|
|
@@ -593,6 +613,20 @@ Claude Code ships a built-in memory feature at `~/.claude/projects/<path>/memory
|
|
|
593
613
|
|
|
594
614
|
Use both.
|
|
595
615
|
|
|
616
|
+
## Security & privacy
|
|
617
|
+
|
|
618
|
+
linksee-memory runs locally and is built to read — and send — as little as possible.
|
|
619
|
+
|
|
620
|
+
- **Local-first.** Memory is one SQLite file at `~/.linksee-memory/memory.db`. No account, no cloud, no API key.
|
|
621
|
+
- **Telemetry is opt-in and OFF by default.** Nothing is sent unless you set `LINKSEE_TELEMETRY=basic`. Even then it never sends your source code, file contents, prompts, conversation, entity/project names, or the memory DB — only anonymous counters ([details](#telemetry-opt-in-off-by-default)).
|
|
622
|
+
- **No automatic repo crawling.** linksee reads: memory you explicitly save, your `map.yaml`, the specific files a map reality-check points at, the local SQLite DB, and — when the Stop hook fires — your Claude Code session transcript (locally, to capture what happened). It does **not** crawl your repo, read `.env`/secrets/`node_modules`, or touch your home directory on its own.
|
|
623
|
+
- **Clean MCP transport.** The server writes only JSON-RPC to stdout; all logs go to stderr.
|
|
624
|
+
- **Hooks are documented and removable.** `setup` adds a Stop hook (session capture) and an optional guard hook. They make no network calls by default, are time-bounded, fail-open (a hook error never breaks your session), and are listed under [Uninstall](#uninstall).
|
|
625
|
+
- **No shell-injection surface.** Subcommands run via `spawn` with array args and `shell: false`, from a fixed allowlist; `map.yaml` is parsed with the safe `yaml` parser (no arbitrary tag execution).
|
|
626
|
+
- **Supply chain.** MIT, published from a single owner. `npx -y linksee-memory` runs the published package — pin a version in CI if you need reproducibility.
|
|
627
|
+
|
|
628
|
+
Found a security issue? See [SECURITY.md](SECURITY.md).
|
|
629
|
+
|
|
596
630
|
## Telemetry (opt-in, off by default)
|
|
597
631
|
|
|
598
632
|
linksee-memory ships with **opt-in** anonymous telemetry that helps us understand which MCP servers and workflows actually work in the wild. **Nothing is sent unless you explicitly enable it.** No conversation content, no file content, no entity names, no project paths — ever.
|
|
@@ -804,6 +838,11 @@ After install, in a new Claude session ask: *"Can you remember that I prefer Typ
|
|
|
804
838
|
|
|
805
839
|
## Changelog
|
|
806
840
|
|
|
841
|
+
### v0.11.3 — Robustness + MCP hygiene (2026-06-16)
|
|
842
|
+
|
|
843
|
+
- **Corrupt-database recovery:** if `~/.linksee-memory/memory.db` is unreadable, linksee preserves it as `memory.db.corrupt-<timestamp>` and starts a fresh one (with a clear message) instead of crashing with a raw SQLite error. Old memories stay recoverable in the backup.
|
|
844
|
+
- **`recall` tool description** no longer suggests editing your system prompt — cleaner MCP citizenship.
|
|
845
|
+
|
|
807
846
|
### v0.11.2 — More cold-start hardening (2026-06-16)
|
|
808
847
|
|
|
809
848
|
- **`stats` works on a fresh database** instead of crashing with `no such table` — it ensures the schema exists first (it may be the first command a new user runs).
|
package/dist/db/migrate.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Database from 'better-sqlite3';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { mkdirSync } from 'node:fs';
|
|
3
|
+
import { mkdirSync, renameSync, existsSync } from 'node:fs';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
@@ -10,12 +10,49 @@ const DB_PATH = join(DEFAULT_DB_DIR, 'memory.db');
|
|
|
10
10
|
export function getDbPath() {
|
|
11
11
|
return DB_PATH;
|
|
12
12
|
}
|
|
13
|
+
function openAt(path) {
|
|
14
|
+
const db = new Database(path);
|
|
15
|
+
try {
|
|
16
|
+
db.pragma('journal_mode = WAL'); // first real read of the file header — throws if it isn't a DB
|
|
17
|
+
db.pragma('foreign_keys = ON');
|
|
18
|
+
return db;
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
try {
|
|
22
|
+
db.close();
|
|
23
|
+
}
|
|
24
|
+
catch { /* ignore */ } // release the handle so a corrupt file can be renamed (Windows locks it otherwise)
|
|
25
|
+
throw e;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
13
28
|
export function openDb() {
|
|
14
29
|
mkdirSync(DEFAULT_DB_DIR, { recursive: true });
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
try {
|
|
31
|
+
return openAt(DB_PATH);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
35
|
+
// A corrupt / non-database file throws on the first pragma. Don't crash with a raw
|
|
36
|
+
// stack trace: preserve the bad file (so it can be recovered) and start a fresh DB.
|
|
37
|
+
if (/not a database|file is encrypted|malformed|disk image/i.test(msg) && existsSync(DB_PATH)) {
|
|
38
|
+
const backup = `${DB_PATH}.corrupt-${Date.now()}`;
|
|
39
|
+
try {
|
|
40
|
+
renameSync(DB_PATH, backup);
|
|
41
|
+
}
|
|
42
|
+
catch { /* best effort */ }
|
|
43
|
+
for (const ext of ['-wal', '-shm']) {
|
|
44
|
+
try {
|
|
45
|
+
if (existsSync(DB_PATH + ext))
|
|
46
|
+
renameSync(DB_PATH + ext, backup + ext);
|
|
47
|
+
}
|
|
48
|
+
catch { /* ignore */ }
|
|
49
|
+
}
|
|
50
|
+
process.stderr.write(`[linksee-memory] the memory database was unreadable (${msg}). ` +
|
|
51
|
+
`Moved it to ${backup} and started a fresh one — your old memories are preserved there for recovery.\n`);
|
|
52
|
+
return openAt(DB_PATH);
|
|
53
|
+
}
|
|
54
|
+
throw err; // not a corruption we recognize — surface it
|
|
55
|
+
}
|
|
19
56
|
}
|
|
20
57
|
export function runMigrations(db) {
|
|
21
58
|
const __filename = fileURLToPath(import.meta.url);
|
package/dist/mcp/server.js
CHANGED
|
@@ -153,7 +153,7 @@ const TOOLS = [
|
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
155
|
name: 'recall',
|
|
156
|
-
description: 'Your persistent memory across all AI tools. CALL THIS BEFORE STARTING ANY TASK to check for past caveats (pain records), decisions, and learnings — prevents repeating mistakes across sessions.\n\nTypical usage: recall({ query: "keywords" }) for search, recall({ path: "file.ts" }) for file history, recall() for overview.\n\nWHEN TO CALL:\n• Before starting any new task or touching a file\n• When the user mentions "before" / "前に" / "last time" / "remember when"\n• When an error occurs — check if you\'ve seen it before\n• When making a decision — check for prior decisions on the same topic\n\nTHREE MODES (auto-detected):\n• Search (default): provide query → returns memories ranked by relevance + heat\n• File history: provide path → returns complete edit history with user-intent context\n• Overview: omit all params → returns entity list sorted by momentum\n\
|
|
156
|
+
description: 'Your persistent memory across all AI tools. CALL THIS BEFORE STARTING ANY TASK to check for past caveats (pain records), decisions, and learnings — prevents repeating mistakes across sessions.\n\nTypical usage: recall({ query: "keywords" }) for search, recall({ path: "file.ts" }) for file history, recall() for overview.\n\nWHEN TO CALL:\n• Before starting any new task or touching a file\n• When the user mentions "before" / "前に" / "last time" / "remember when"\n• When an error occurs — check if you\'ve seen it before\n• When making a decision — check for prior decisions on the same topic\n\nTHREE MODES (auto-detected):\n• Search (default): provide query → returns memories ranked by relevance + heat\n• File history: provide path → returns complete edit history with user-intent context\n• Overview: omit all params → returns entity list sorted by momentum\n\nWorks across Claude, GPT, Cursor, Codex, Gemini — one local SQLite file, nothing leaves your machine.',
|
|
157
157
|
inputSchema: {
|
|
158
158
|
type: 'object',
|
|
159
159
|
properties: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "linksee-memory",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
4
4
|
"mcpName": "io.github.michielinksee/linksee-memory",
|
|
5
5
|
"description": "Local-first agent memory MCP — cross-agent brain with drift detection, 6-layer structured memory + token-saving file diff cache",
|
|
6
6
|
"type": "module",
|