@scitrera/memorylayer-cc-plugin 0.0.5
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 +233 -0
- package/dist/bin/memorylayer-hook.d.ts +3 -0
- package/dist/bin/memorylayer-hook.d.ts.map +1 -0
- package/dist/bin/memorylayer-hook.js +267 -0
- package/dist/bin/memorylayer-hook.js.map +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +7 -0
- package/dist/src/index.js.map +1 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# MemoryLayer Plugin for Claude Code
|
|
2
|
+
|
|
3
|
+
Persistent memory for Claude Code - never lose context to compaction again.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
This plugin integrates [MemoryLayer](https://memorylayer.ai) with Claude Code to provide:
|
|
8
|
+
|
|
9
|
+
- **PreCompact Memory Capture** - Automatically saves important information before context window compaction
|
|
10
|
+
- **Session Briefings** - Recalls relevant context at session start
|
|
11
|
+
- **Automatic Memory Triggers** - Suggests storing memories after git commits and significant events
|
|
12
|
+
- **Knowledge Graph** - Links related memories with typed relationships
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### From the Marketplace
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Add the marketplace (one-time setup)
|
|
20
|
+
claude plugin marketplace add scitrera/memorylayer
|
|
21
|
+
|
|
22
|
+
# Install the plugin
|
|
23
|
+
claude plugin install memorylayer@memorylayer.ai
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Manual Installation
|
|
27
|
+
|
|
28
|
+
Clone or copy this plugin to your Claude Code plugins directory:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Global plugins
|
|
32
|
+
cp -r memorylayer-cc-plugin ~/.claude/plugins/memorylayer
|
|
33
|
+
|
|
34
|
+
# Or project-local
|
|
35
|
+
cp -r memorylayer-cc-plugin .claude/plugins/memorylayer
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Prerequisites
|
|
39
|
+
|
|
40
|
+
### MemoryLayer Server
|
|
41
|
+
|
|
42
|
+
The plugin requires a running MemoryLayer server. For local development:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Install and run the server
|
|
46
|
+
pip install memorylayer-server
|
|
47
|
+
memorylayer serve
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The server runs on `http://localhost:61001` by default.
|
|
51
|
+
|
|
52
|
+
### Configuration
|
|
53
|
+
|
|
54
|
+
Set environment variables to customize:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Custom server URL
|
|
58
|
+
export MEMORYLAYER_URL="http://your-server:61001"
|
|
59
|
+
|
|
60
|
+
# Custom workspace (default: auto-detected from git repo)
|
|
61
|
+
export MEMORYLAYER_WORKSPACE_ID="my-project"
|
|
62
|
+
|
|
63
|
+
# Disable session/working memory (default: enabled)
|
|
64
|
+
export MEMORYLAYER_SESSION_MODE="false"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## What Gets Installed
|
|
68
|
+
|
|
69
|
+
### MCP Server
|
|
70
|
+
|
|
71
|
+
The plugin configures the `@scitrera/memorylayer-mcp-server` which provides these tools:
|
|
72
|
+
|
|
73
|
+
#### Core Memory Tools
|
|
74
|
+
|
|
75
|
+
| Tool | Description |
|
|
76
|
+
|------|-------------|
|
|
77
|
+
| `memory_remember` | Store new memories |
|
|
78
|
+
| `memory_recall` | Search memories by query |
|
|
79
|
+
| `memory_reflect` | Synthesize insights across memories |
|
|
80
|
+
| `memory_forget` | Delete outdated information |
|
|
81
|
+
| `memory_associate` | Link related memories |
|
|
82
|
+
| `memory_briefing` | Get session context summary |
|
|
83
|
+
| `memory_statistics` | View workspace analytics |
|
|
84
|
+
| `memory_graph_query` | Traverse memory relationships |
|
|
85
|
+
| `memory_audit` | Find contradictions |
|
|
86
|
+
|
|
87
|
+
#### Session Management Tools
|
|
88
|
+
|
|
89
|
+
| Tool | Description |
|
|
90
|
+
|------|-------------|
|
|
91
|
+
| `memory_session_start` | Initialize session and server-side sandbox |
|
|
92
|
+
| `memory_session_end` | End session, optionally commit to long-term storage |
|
|
93
|
+
| `memory_session_commit` | Checkpoint working memory without ending session |
|
|
94
|
+
| `memory_session_status` | Check current session state |
|
|
95
|
+
|
|
96
|
+
#### Context Environment Tools (Server-Side Sandbox)
|
|
97
|
+
|
|
98
|
+
These tools provide a persistent Python execution environment on the server. Sandbox state survives context compaction — call `memory_context_inspect` after compaction to re-orient.
|
|
99
|
+
|
|
100
|
+
| Tool | Description |
|
|
101
|
+
|------|-------------|
|
|
102
|
+
| `memory_context_exec` | Execute Python code in the sandbox |
|
|
103
|
+
| `memory_context_inspect` | Inspect sandbox variables (call after compaction) |
|
|
104
|
+
| `memory_context_load` | Load memories into a sandbox variable via search |
|
|
105
|
+
| `memory_context_inject` | Inject a value into the sandbox |
|
|
106
|
+
| `memory_context_query` | Ask the server LLM using sandbox context |
|
|
107
|
+
| `memory_context_rlm` | Run a Recursive Language Model (RLM) loop |
|
|
108
|
+
| `memory_context_status` | Get sandbox environment status |
|
|
109
|
+
| `memory_context_checkpoint` | Persist sandbox state for enterprise hooks |
|
|
110
|
+
|
|
111
|
+
Working memory persists within a session and survives context compaction. At session end, important context is automatically extracted to long-term memory.
|
|
112
|
+
|
|
113
|
+
### Slash Commands
|
|
114
|
+
|
|
115
|
+
| Command | Description |
|
|
116
|
+
|---------|-------------|
|
|
117
|
+
| `/memorylayer-status` | Check connection and workspace info |
|
|
118
|
+
| `/memorylayer-setup` | Guided setup and troubleshooting |
|
|
119
|
+
| `/memorylayer-remember <content>` | Quick memory storage |
|
|
120
|
+
| `/memorylayer-recall <query>` | Quick memory search |
|
|
121
|
+
|
|
122
|
+
### Hooks
|
|
123
|
+
|
|
124
|
+
| Hook | Trigger | Behavior |
|
|
125
|
+
|------|---------|----------|
|
|
126
|
+
| `PreCompact` | Before context compaction | **Critical** - Stores important information, checkpoints sandbox state, and commits working memory before context is lost |
|
|
127
|
+
| `SessionStart` | Session begins | Loads context briefing, directives, and starts server-side session for workspace resolution |
|
|
128
|
+
| `Stop` | Session ends | Commits working memory to long-term storage and ends the server session |
|
|
129
|
+
| `PreToolUse` | Before Task/Edit/Write | Injects recalled context relevant to the operation (query-aware dedup) |
|
|
130
|
+
| `PostToolUse` | After Bash/Edit/Write/Task | Captures outcomes (commit summaries, file changes, new file creation, agent results) |
|
|
131
|
+
| `UserPromptSubmit` | On user input | Recalls relevant memories for recall/review/implement/error-related prompts |
|
|
132
|
+
|
|
133
|
+
## How It Works
|
|
134
|
+
|
|
135
|
+
### Context Compaction Protection
|
|
136
|
+
|
|
137
|
+
Without MemoryLayer:
|
|
138
|
+
```
|
|
139
|
+
[Long conversation with decisions, fixes, learnings]
|
|
140
|
+
↓ context window full
|
|
141
|
+
[COMPACTION - history truncated]
|
|
142
|
+
↓
|
|
143
|
+
[Claude forgets everything not in remaining context]
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
With MemoryLayer:
|
|
147
|
+
```
|
|
148
|
+
[Long conversation with decisions, fixes, learnings]
|
|
149
|
+
↓ context window full
|
|
150
|
+
[PreCompact hook fires]
|
|
151
|
+
↓
|
|
152
|
+
[Claude stores key information to MemoryLayer]
|
|
153
|
+
↓
|
|
154
|
+
[COMPACTION - history truncated]
|
|
155
|
+
↓
|
|
156
|
+
[Claude can recall stored memories when needed]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Workspace Isolation
|
|
160
|
+
|
|
161
|
+
Each project automatically gets its own workspace based on:
|
|
162
|
+
1. Git repository name (from remote origin)
|
|
163
|
+
2. Git root directory name
|
|
164
|
+
3. Current working directory name
|
|
165
|
+
|
|
166
|
+
This means memories are isolated per-project by default.
|
|
167
|
+
|
|
168
|
+
## Usage Tips
|
|
169
|
+
|
|
170
|
+
### Explicit Memory Commands
|
|
171
|
+
|
|
172
|
+
You can always ask Claude directly:
|
|
173
|
+
|
|
174
|
+
- "Remember that we decided to use PostgreSQL for the database"
|
|
175
|
+
- "What do you remember about the authentication system?"
|
|
176
|
+
- "Store this bug fix for future reference"
|
|
177
|
+
|
|
178
|
+
### Memory Types
|
|
179
|
+
|
|
180
|
+
- **episodic** - Events, what happened
|
|
181
|
+
- **semantic** - Facts, concepts, knowledge
|
|
182
|
+
- **procedural** - How-to, solutions, patterns
|
|
183
|
+
- **working** - Current task context (auto-expires)
|
|
184
|
+
|
|
185
|
+
### Importance Levels
|
|
186
|
+
|
|
187
|
+
- **0.9** - Critical decisions, breaking changes
|
|
188
|
+
- **0.7-0.8** - Bug fixes, architecture decisions
|
|
189
|
+
- **0.5-0.6** - General knowledge, minor features
|
|
190
|
+
- **0.3-0.4** - Temporary notes
|
|
191
|
+
|
|
192
|
+
## Troubleshooting
|
|
193
|
+
|
|
194
|
+
### MCP Server Not Connecting
|
|
195
|
+
|
|
196
|
+
1. Check the server is running:
|
|
197
|
+
```bash
|
|
198
|
+
curl http://localhost:61001/health
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
2. Check environment variable:
|
|
202
|
+
```bash
|
|
203
|
+
echo $MEMORYLAYER_URL
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Hooks Not Firing
|
|
207
|
+
|
|
208
|
+
1. Verify plugin is installed:
|
|
209
|
+
```bash
|
|
210
|
+
claude plugin list
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
2. Check hooks are loaded:
|
|
214
|
+
```bash
|
|
215
|
+
claude hooks list
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Wrong Workspace
|
|
219
|
+
|
|
220
|
+
The workspace is auto-detected from the git repo or directory name. To override:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
export MEMORYLAYER_WORKSPACE_ID="my-custom-workspace"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Links
|
|
227
|
+
|
|
228
|
+
- [MemoryLayer Documentation](https://docs.memorylayer.ai)
|
|
229
|
+
- [MCP Server README](../memorylayer-mcp-typescript/README.md)
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
Apache 2.0 License -- see [LICENSE](../LICENSE) for details.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memorylayer-hook.d.ts","sourceRoot":"","sources":["../../bin/memorylayer-hook.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// noinspection ES6PreferShortImport
|
|
3
|
+
/**
|
|
4
|
+
* CLI entry point for MemoryLayer Claude Code hooks
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* memorylayer-hook <hook-type>
|
|
8
|
+
*
|
|
9
|
+
* Reads HookInput JSON from stdin, writes HookOutput JSON to stdout.
|
|
10
|
+
*
|
|
11
|
+
* Hook types:
|
|
12
|
+
* SessionStart - Called at session start
|
|
13
|
+
* UserPromptSubmit - Called when user submits a prompt
|
|
14
|
+
* PreToolUse - Called before a tool is used
|
|
15
|
+
* PostToolUse - Called after a tool is used
|
|
16
|
+
* PreCompact - Called before context compaction
|
|
17
|
+
* Stop - Called when session ends
|
|
18
|
+
*/
|
|
19
|
+
import { appendFileSync, readFileSync, existsSync, unlinkSync } from "fs";
|
|
20
|
+
import { join } from "path";
|
|
21
|
+
import { tmpdir } from "os";
|
|
22
|
+
import { HookEvent } from "../src/hooks/types.js";
|
|
23
|
+
import { handleSessionStart } from "../src/hooks/handlers/session-start.js";
|
|
24
|
+
import { handleUserPromptSubmit } from "../src/hooks/handlers/user-prompt.js";
|
|
25
|
+
import { handlePreToolUse } from "../src/hooks/handlers/pre-tool.js";
|
|
26
|
+
import { handlePostToolUse } from "../src/hooks/handlers/post-tool.js";
|
|
27
|
+
import { handleStop } from "../src/hooks/handlers/stop.js";
|
|
28
|
+
import { resetRecallStatus, updateSessionInfo } from "../src/hooks/state.js";
|
|
29
|
+
import { getClient } from "../src/hooks/client.js";
|
|
30
|
+
/**
|
|
31
|
+
* Read all input from stdin
|
|
32
|
+
*/
|
|
33
|
+
async function readStdin() {
|
|
34
|
+
const chunks = [];
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
37
|
+
process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
|
|
38
|
+
process.stdin.on("error", reject);
|
|
39
|
+
// Timeout after 5 seconds if no input
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
if (chunks.length === 0) {
|
|
42
|
+
resolve("{}");
|
|
43
|
+
}
|
|
44
|
+
}, 5000);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse hook type from command line
|
|
49
|
+
*/
|
|
50
|
+
function parseHookType(arg) {
|
|
51
|
+
if (!arg)
|
|
52
|
+
return null;
|
|
53
|
+
const normalized = arg.toLowerCase();
|
|
54
|
+
switch (normalized) {
|
|
55
|
+
case "sessionstart":
|
|
56
|
+
return HookEvent.SessionStart;
|
|
57
|
+
case "userpromptsubmit":
|
|
58
|
+
return HookEvent.UserPromptSubmit;
|
|
59
|
+
case "pretooluse":
|
|
60
|
+
return HookEvent.PreToolUse;
|
|
61
|
+
case "posttooluse":
|
|
62
|
+
return HookEvent.PostToolUse;
|
|
63
|
+
case "precompact":
|
|
64
|
+
return HookEvent.PreCompact;
|
|
65
|
+
case "stop":
|
|
66
|
+
return HookEvent.Stop;
|
|
67
|
+
default:
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Hooks that support hookSpecificOutput with additionalContext */
|
|
72
|
+
const HOOKS_WITH_ADDITIONAL_CONTEXT = new Set([
|
|
73
|
+
HookEvent.SessionStart, // Works empirically even though not in schema
|
|
74
|
+
HookEvent.PreToolUse,
|
|
75
|
+
HookEvent.PostToolUse,
|
|
76
|
+
HookEvent.UserPromptSubmit,
|
|
77
|
+
]);
|
|
78
|
+
/**
|
|
79
|
+
* Build properly formatted hook output
|
|
80
|
+
*/
|
|
81
|
+
function buildOutput(hookType, additionalContext, block = false, reason) {
|
|
82
|
+
const output = {
|
|
83
|
+
continue: !block, // Always continue unless blocking
|
|
84
|
+
};
|
|
85
|
+
// For PreToolUse, we can block
|
|
86
|
+
if (hookType === HookEvent.PreToolUse && block) {
|
|
87
|
+
output.continue = false;
|
|
88
|
+
output.decision = "block";
|
|
89
|
+
output.reason = reason || "Blocked by MemoryLayer hook";
|
|
90
|
+
}
|
|
91
|
+
// Only add hookSpecificOutput for hooks that support it
|
|
92
|
+
// SessionStart, Stop, PreCompact do NOT support hookSpecificOutput
|
|
93
|
+
if (additionalContext && HOOKS_WITH_ADDITIONAL_CONTEXT.has(hookType)) {
|
|
94
|
+
output.hookSpecificOutput = {
|
|
95
|
+
hookEventName: hookType,
|
|
96
|
+
additionalContext,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return output;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Build error output
|
|
103
|
+
*/
|
|
104
|
+
function buildErrorOutput(hookType, error) {
|
|
105
|
+
return {
|
|
106
|
+
hookSpecificOutput: {
|
|
107
|
+
hookEventName: hookType,
|
|
108
|
+
additionalContext: `MemoryLayer hook error: ${error}`,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Convert legacy HookOutput to HandlerResult
|
|
114
|
+
*/
|
|
115
|
+
function legacyToResult(output) {
|
|
116
|
+
// Handle new format (has hookSpecificOutput)
|
|
117
|
+
if (output.hookSpecificOutput) {
|
|
118
|
+
return {
|
|
119
|
+
additionalContext: output.hookSpecificOutput.additionalContext,
|
|
120
|
+
block: output.decision === "block",
|
|
121
|
+
reason: output.reason,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Handle legacy format (has additionalContext at top level)
|
|
125
|
+
return {
|
|
126
|
+
additionalContext: output.additionalContext,
|
|
127
|
+
block: output.block,
|
|
128
|
+
reason: output.blockReason,
|
|
129
|
+
error: output.error,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Dispatch to appropriate handler
|
|
134
|
+
*/
|
|
135
|
+
async function dispatch(hookType, input) {
|
|
136
|
+
switch (hookType) {
|
|
137
|
+
case HookEvent.SessionStart: {
|
|
138
|
+
// Reset recall status at session start
|
|
139
|
+
resetRecallStatus();
|
|
140
|
+
const envFile = process.env.CLAUDE_ENV_FILE;
|
|
141
|
+
// Try to read the session from the MCP server's handoff file
|
|
142
|
+
const handoffDir = join(tmpdir(), "memorylayer");
|
|
143
|
+
const handoffFile = join(handoffDir, `session-${process.ppid}.json`);
|
|
144
|
+
let sessionId;
|
|
145
|
+
let workspaceId;
|
|
146
|
+
try {
|
|
147
|
+
if (existsSync(handoffFile)) {
|
|
148
|
+
const data = JSON.parse(readFileSync(handoffFile, "utf-8"));
|
|
149
|
+
sessionId = data.sessionId;
|
|
150
|
+
workspaceId = data.workspaceId;
|
|
151
|
+
// Clean up the handoff file
|
|
152
|
+
unlinkSync(handoffFile);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Handoff file not available, fall through
|
|
157
|
+
}
|
|
158
|
+
// Fallback: if no handoff file, create session directly (backward compat)
|
|
159
|
+
if (!sessionId) {
|
|
160
|
+
try {
|
|
161
|
+
const client = getClient();
|
|
162
|
+
workspaceId = client.getWorkspaceId();
|
|
163
|
+
const sessionResult = await client.startSession({ ttl_seconds: 3600 });
|
|
164
|
+
sessionId = sessionResult.session_id;
|
|
165
|
+
console.error(`[session-start] created hook session=${sessionId} workspace=${workspaceId} (direct, no handoff)`);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// Ignore - memory features will still work via MCP tools
|
|
169
|
+
console.error("[session-start] failed to create hook session (server unreachable?)");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
console.error(`[session-start] got hook session=${sessionId} workspace=${workspaceId} (from handoff file)`);
|
|
174
|
+
}
|
|
175
|
+
// Write to CLAUDE_ENV_FILE so subsequent hook processes get the session.
|
|
176
|
+
// Each Claude Code session has its own env file, providing session isolation.
|
|
177
|
+
if (envFile) {
|
|
178
|
+
try {
|
|
179
|
+
if (workspaceId) {
|
|
180
|
+
appendFileSync(envFile, `export MEMORYLAYER_WORKSPACE_ID="${workspaceId}"\n`);
|
|
181
|
+
}
|
|
182
|
+
if (sessionId) {
|
|
183
|
+
appendFileSync(envFile, `export MEMORYLAYER_SESSION_ID="${sessionId}"\n`);
|
|
184
|
+
}
|
|
185
|
+
console.error(`[session-start] wrote to CLAUDE_ENV_FILE=${envFile} sessionId=${sessionId || "(none)"} workspaceId=${workspaceId || "(none)"}`);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
console.error(`[session-start] failed to write CLAUDE_ENV_FILE=${envFile}:`, err);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.error("[session-start] CLAUDE_ENV_FILE not set -- env propagation unavailable, falling back to hook-state.json only");
|
|
193
|
+
}
|
|
194
|
+
// Save to hook state as fallback (singleton -- will be superseded by env propagation)
|
|
195
|
+
if (workspaceId) {
|
|
196
|
+
updateSessionInfo(workspaceId, sessionId);
|
|
197
|
+
}
|
|
198
|
+
return legacyToResult(await handleSessionStart(input));
|
|
199
|
+
}
|
|
200
|
+
case HookEvent.UserPromptSubmit:
|
|
201
|
+
// Reset recall status for new user turn
|
|
202
|
+
resetRecallStatus();
|
|
203
|
+
return legacyToResult(await handleUserPromptSubmit(input));
|
|
204
|
+
case HookEvent.PreToolUse:
|
|
205
|
+
return legacyToResult(await handlePreToolUse(input));
|
|
206
|
+
case HookEvent.PostToolUse:
|
|
207
|
+
return legacyToResult(await handlePostToolUse(input));
|
|
208
|
+
case HookEvent.PreCompact:
|
|
209
|
+
// PreCompact: Can't inject instructions at this point, just continue
|
|
210
|
+
return {};
|
|
211
|
+
case HookEvent.Stop:
|
|
212
|
+
// Stop: commit working memory and end session (side effects only, no context injection)
|
|
213
|
+
return legacyToResult(await handleStop());
|
|
214
|
+
default:
|
|
215
|
+
return {};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Main entry point
|
|
220
|
+
*/
|
|
221
|
+
async function main() {
|
|
222
|
+
const hookTypeArg = process.argv[2];
|
|
223
|
+
const hookType = parseHookType(hookTypeArg);
|
|
224
|
+
if (!hookType) {
|
|
225
|
+
const output = {
|
|
226
|
+
error: `Invalid or missing hook type. Usage: memorylayer-hook <hook-type>\nValid types: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PreCompact, Stop`,
|
|
227
|
+
};
|
|
228
|
+
console.log(JSON.stringify(output));
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
// Read input from stdin
|
|
233
|
+
const stdinData = await readStdin();
|
|
234
|
+
let input;
|
|
235
|
+
try {
|
|
236
|
+
input = stdinData.trim() ? JSON.parse(stdinData) : { hook_type: hookType };
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
input = { hook_type: hookType };
|
|
240
|
+
}
|
|
241
|
+
// Add hook type to input
|
|
242
|
+
input.hook_type = hookType;
|
|
243
|
+
// Dispatch to handler
|
|
244
|
+
const result = await dispatch(hookType, input);
|
|
245
|
+
// Handle errors from handlers
|
|
246
|
+
if (result.error) {
|
|
247
|
+
const output = buildErrorOutput(hookType, result.error);
|
|
248
|
+
console.log(JSON.stringify(output));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// Build properly formatted output
|
|
252
|
+
const output = buildOutput(hookType, result.additionalContext, result.block, result.reason);
|
|
253
|
+
// Write output to stdout
|
|
254
|
+
console.log(JSON.stringify(output));
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
const output = buildErrorOutput(hookType, error instanceof Error ? error.message : String(error));
|
|
258
|
+
console.log(JSON.stringify(output));
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Run
|
|
263
|
+
main().catch((error) => {
|
|
264
|
+
console.error("Fatal error:", error);
|
|
265
|
+
process.exit(1);
|
|
266
|
+
});
|
|
267
|
+
//# sourceMappingURL=memorylayer-hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memorylayer-hook.js","sourceRoot":"","sources":["../../bin/memorylayer-hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scitrera/memorylayer-cc-plugin",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "Claude Code plugin for MemoryLayer.ai - persistent memory hooks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/src/index.js",
|
|
7
|
+
"types": "dist/src/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"memorylayer-hook": "dist/bin/memorylayer-hook.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"author": "Scitrera LLC",
|
|
17
|
+
"license": "Apache-2.0",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@scitrera/memorylayer-mcp-server": "^0.0.5"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^20.0.0",
|
|
23
|
+
"typescript": "^5.3.0"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
}
|
|
28
|
+
}
|