chore: bump version to 9.1.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "9.1.0",
|
||||
"version": "9.1.1",
|
||||
"description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions",
|
||||
"author": {
|
||||
"name": "Alex Newman"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "claude-mem-plugin",
|
||||
"version": "9.1.0",
|
||||
"version": "9.1.1",
|
||||
"private": true,
|
||||
"description": "Runtime dependencies for claude-mem bundled hooks",
|
||||
"type": "module",
|
||||
|
||||
@@ -37,7 +37,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?u=`
|
||||
memory_session_id TEXT NOT NULL,
|
||||
project TEXT NOT NULL,
|
||||
text TEXT NOT NULL,
|
||||
type TEXT NOT NULL CHECK(type IN ('decision', 'bugfix', 'feature', 'refactor', 'discovery')),
|
||||
type TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
created_at_epoch INTEGER NOT NULL,
|
||||
FOREIGN KEY(memory_session_id) REFERENCES sdk_sessions(memory_session_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
@@ -110,7 +110,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?u=`
|
||||
memory_session_id TEXT NOT NULL,
|
||||
project TEXT NOT NULL,
|
||||
text TEXT,
|
||||
type TEXT NOT NULL CHECK(type IN ('decision', 'bugfix', 'feature', 'refactor', 'discovery', 'change')),
|
||||
type TEXT NOT NULL,
|
||||
title TEXT,
|
||||
subtitle TEXT,
|
||||
facts TEXT,
|
||||
@@ -192,13 +192,13 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?u=`
|
||||
completed_at_epoch INTEGER,
|
||||
FOREIGN KEY (session_db_id) REFERENCES sdk_sessions(id) ON DELETE CASCADE
|
||||
)
|
||||
`),this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_session ON pending_messages(session_db_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_status ON pending_messages(status)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_claude_session ON pending_messages(content_session_id)"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(16,new Date().toISOString()),m.debug("DB","pending_messages table created successfully")}renameSessionIdColumns(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(17))return;m.debug("DB","Checking session ID columns for semantic clarity rename");let t=0,s=(n,o,i)=>{let a=this.db.query(`PRAGMA table_info(${n})`).all(),d=a.some(u=>u.name===o);return a.some(u=>u.name===i)?!1:d?(this.db.run(`ALTER TABLE ${n} RENAME COLUMN ${o} TO ${i}`),m.debug("DB",`Renamed ${n}.${o} to ${i}`),!0):(m.warn("DB",`Column ${o} not found in ${n}, skipping rename`),!1)};s("sdk_sessions","claude_session_id","content_session_id")&&t++,s("sdk_sessions","sdk_session_id","memory_session_id")&&t++,s("pending_messages","claude_session_id","content_session_id")&&t++,s("observations","sdk_session_id","memory_session_id")&&t++,s("session_summaries","sdk_session_id","memory_session_id")&&t++,s("user_prompts","claude_session_id","content_session_id")&&t++,this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(17,new Date().toISOString()),t>0?m.debug("DB",`Successfully renamed ${t} session ID columns`):m.debug("DB","No session ID column renames needed (already up to date)")}repairSessionIdColumnRename(){this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(19)||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(19,new Date().toISOString())}addFailedAtEpochColumn(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(20))return;this.db.query("PRAGMA table_info(pending_messages)").all().some(n=>n.name==="failed_at_epoch")||(this.db.run("ALTER TABLE pending_messages ADD COLUMN failed_at_epoch INTEGER"),m.debug("DB","Added failed_at_epoch column to pending_messages table")),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(20,new Date().toISOString())}addOnUpdateCascadeToForeignKeys(){if(!this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(21)){m.debug("DB","Adding ON UPDATE CASCADE to FK constraints on observations and session_summaries"),this.db.run("BEGIN TRANSACTION");try{this.db.run("DROP TRIGGER IF EXISTS observations_ai"),this.db.run("DROP TRIGGER IF EXISTS observations_ad"),this.db.run("DROP TRIGGER IF EXISTS observations_au"),this.db.run(`
|
||||
`),this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_session ON pending_messages(session_db_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_status ON pending_messages(status)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_claude_session ON pending_messages(content_session_id)"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(16,new Date().toISOString()),m.debug("DB","pending_messages table created successfully")}renameSessionIdColumns(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(17))return;m.debug("DB","Checking session ID columns for semantic clarity rename");let t=0,s=(n,o,i)=>{let a=this.db.query(`PRAGMA table_info(${n})`).all(),d=a.some(u=>u.name===o);return a.some(u=>u.name===i)?!1:d?(this.db.run(`ALTER TABLE ${n} RENAME COLUMN ${o} TO ${i}`),m.debug("DB",`Renamed ${n}.${o} to ${i}`),!0):(m.warn("DB",`Column ${o} not found in ${n}, skipping rename`),!1)};s("sdk_sessions","claude_session_id","content_session_id")&&t++,s("sdk_sessions","sdk_session_id","memory_session_id")&&t++,s("pending_messages","claude_session_id","content_session_id")&&t++,s("observations","sdk_session_id","memory_session_id")&&t++,s("session_summaries","sdk_session_id","memory_session_id")&&t++,s("user_prompts","claude_session_id","content_session_id")&&t++,this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(17,new Date().toISOString()),t>0?m.debug("DB",`Successfully renamed ${t} session ID columns`):m.debug("DB","No session ID column renames needed (already up to date)")}repairSessionIdColumnRename(){this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(19)||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(19,new Date().toISOString())}addFailedAtEpochColumn(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(20))return;this.db.query("PRAGMA table_info(pending_messages)").all().some(n=>n.name==="failed_at_epoch")||(this.db.run("ALTER TABLE pending_messages ADD COLUMN failed_at_epoch INTEGER"),m.debug("DB","Added failed_at_epoch column to pending_messages table")),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(20,new Date().toISOString())}addOnUpdateCascadeToForeignKeys(){if(!this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(21)){m.debug("DB","Adding ON UPDATE CASCADE to FK constraints on observations and session_summaries"),this.db.run("PRAGMA foreign_keys = OFF"),this.db.run("BEGIN TRANSACTION");try{this.db.run("DROP TRIGGER IF EXISTS observations_ai"),this.db.run("DROP TRIGGER IF EXISTS observations_ad"),this.db.run("DROP TRIGGER IF EXISTS observations_au"),this.db.run(`
|
||||
CREATE TABLE observations_new (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
memory_session_id TEXT NOT NULL,
|
||||
project TEXT NOT NULL,
|
||||
text TEXT,
|
||||
type TEXT NOT NULL CHECK(type IN ('decision', 'bugfix', 'feature', 'refactor', 'discovery', 'change')),
|
||||
type TEXT NOT NULL,
|
||||
title TEXT,
|
||||
subtitle TEXT,
|
||||
facts TEXT,
|
||||
@@ -286,7 +286,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?u=`
|
||||
INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes)
|
||||
VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes);
|
||||
END;
|
||||
`),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(21,new Date().toISOString()),this.db.run("COMMIT"),m.debug("DB","Successfully added ON UPDATE CASCADE to FK constraints")}catch(t){throw this.db.run("ROLLBACK"),t}}}updateMemorySessionId(e,t){this.db.prepare(`
|
||||
`),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(21,new Date().toISOString()),this.db.run("COMMIT"),this.db.run("PRAGMA foreign_keys = ON"),m.debug("DB","Successfully added ON UPDATE CASCADE to FK constraints")}catch(t){throw this.db.run("ROLLBACK"),this.db.run("PRAGMA foreign_keys = ON"),t}}}updateMemorySessionId(e,t){this.db.prepare(`
|
||||
UPDATE sdk_sessions
|
||||
SET memory_session_id = ?
|
||||
WHERE id = ?
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,141 @@
|
||||
---
|
||||
name: mem-search
|
||||
description: Search claude-mem's persistent cross-session memory database. Use when user asks "did we already solve this?", "how did we do X last time?", or needs work from previous sessions.
|
||||
---
|
||||
|
||||
# Memory Search
|
||||
|
||||
Search past work across all sessions. Simple workflow: search -> filter -> fetch.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use when users ask about PREVIOUS sessions (not current conversation):
|
||||
|
||||
- "Did we already fix this?"
|
||||
- "How did we solve X last time?"
|
||||
- "What happened last week?"
|
||||
|
||||
## 3-Layer Workflow (ALWAYS Follow)
|
||||
|
||||
**NEVER fetch full details without filtering first. 10x token savings.**
|
||||
|
||||
### Step 1: Search - Get Index with IDs
|
||||
|
||||
Use the `search` MCP tool:
|
||||
|
||||
```
|
||||
search(query="authentication", limit=20, project="my-project")
|
||||
```
|
||||
|
||||
**Returns:** Table with IDs, timestamps, types, titles (~50-100 tokens/result)
|
||||
|
||||
```
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #11131 | 3:48 PM | 🟣 | Added JWT authentication | ~75 |
|
||||
| #10942 | 2:15 PM | 🔴 | Fixed auth token expiration | ~50 |
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `query` (string) - Search term
|
||||
- `limit` (number) - Max results, default 20, max 100
|
||||
- `project` (string) - Project name filter
|
||||
- `type` (string, optional) - "observations", "sessions", or "prompts"
|
||||
- `obs_type` (string, optional) - Comma-separated: bugfix, feature, decision, discovery, change
|
||||
- `dateStart` (string, optional) - YYYY-MM-DD or epoch ms
|
||||
- `dateEnd` (string, optional) - YYYY-MM-DD or epoch ms
|
||||
- `offset` (number, optional) - Skip N results
|
||||
- `orderBy` (string, optional) - "date_desc" (default), "date_asc", "relevance"
|
||||
|
||||
### Step 2: Timeline - Get Context Around Interesting Results
|
||||
|
||||
Use the `timeline` MCP tool:
|
||||
|
||||
```
|
||||
timeline(anchor=11131, depth_before=3, depth_after=3, project="my-project")
|
||||
```
|
||||
|
||||
Or find anchor automatically from query:
|
||||
|
||||
```
|
||||
timeline(query="authentication", depth_before=3, depth_after=3, project="my-project")
|
||||
```
|
||||
|
||||
**Returns:** `depth_before + 1 + depth_after` items in chronological order with observations, sessions, and prompts interleaved around the anchor.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `anchor` (number, optional) - Observation ID to center around
|
||||
- `query` (string, optional) - Find anchor automatically if anchor not provided
|
||||
- `depth_before` (number, optional) - Items before anchor, default 5, max 20
|
||||
- `depth_after` (number, optional) - Items after anchor, default 5, max 20
|
||||
- `project` (string) - Project name filter
|
||||
|
||||
### Step 3: Fetch - Get Full Details ONLY for Filtered IDs
|
||||
|
||||
Review titles from Step 1 and context from Step 2. Pick relevant IDs. Discard the rest.
|
||||
|
||||
Use the `get_observations` MCP tool:
|
||||
|
||||
```
|
||||
get_observations(ids=[11131, 10942])
|
||||
```
|
||||
|
||||
**ALWAYS use `get_observations` for 2+ observations - single request vs N requests.**
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `ids` (array of numbers, required) - Observation IDs to fetch
|
||||
- `orderBy` (string, optional) - "date_desc" (default), "date_asc"
|
||||
- `limit` (number, optional) - Max observations to return
|
||||
- `project` (string, optional) - Project name filter
|
||||
|
||||
**Returns:** Complete observation objects with title, subtitle, narrative, facts, concepts, files (~500-1000 tokens each)
|
||||
|
||||
## Saving Memories
|
||||
|
||||
Use the `save_memory` MCP tool to store manual observations:
|
||||
|
||||
```
|
||||
save_memory(text="Important discovery about the auth system", title="Auth Architecture", project="my-project")
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `text` (string, required) - Content to remember
|
||||
- `title` (string, optional) - Short title, auto-generated if omitted
|
||||
- `project` (string, optional) - Project name, defaults to "claude-mem"
|
||||
|
||||
## Examples
|
||||
|
||||
**Find recent bug fixes:**
|
||||
|
||||
```
|
||||
search(query="bug", type="observations", obs_type="bugfix", limit=20, project="my-project")
|
||||
```
|
||||
|
||||
**Find what happened last week:**
|
||||
|
||||
```
|
||||
search(type="observations", dateStart="2025-11-11", limit=20, project="my-project")
|
||||
```
|
||||
|
||||
**Understand context around a discovery:**
|
||||
|
||||
```
|
||||
timeline(anchor=11131, depth_before=5, depth_after=5, project="my-project")
|
||||
```
|
||||
|
||||
**Batch fetch details:**
|
||||
|
||||
```
|
||||
get_observations(ids=[11131, 10942, 10855], orderBy="date_desc")
|
||||
```
|
||||
|
||||
## Why This Workflow?
|
||||
|
||||
- **Search index:** ~50-100 tokens per result
|
||||
- **Full observation:** ~500-1000 tokens each
|
||||
- **Batch fetch:** 1 HTTP request vs N individual requests
|
||||
- **10x token savings** by filtering before fetching
|
||||
Reference in New Issue
Block a user