gitmem-mcp 0.2.0 → 1.0.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/CHANGELOG.md +17 -1
- package/README.md +116 -118
- package/bin/gitmem.js +242 -14
- package/hooks/.claude-plugin/plugin.json +8 -0
- package/hooks/README.md +107 -0
- package/hooks/hooks/hooks.json +152 -0
- package/hooks/scripts/post-tool-use.sh +128 -0
- package/hooks/scripts/recall-check.sh +224 -0
- package/hooks/scripts/session-close-check.sh +116 -0
- package/hooks/scripts/session-start.sh +157 -0
- package/hooks/tests/test-hooks.sh +623 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.0] - 2026-02-10
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Hooks plugin bundled**: `gitmem install-hooks` / `uninstall-hooks` CLI commands (OD-605, OD-606)
|
|
14
|
+
- **CLI `check` command wired**: `gitmem check` now reachable from CLI (was defined but unreachable)
|
|
15
|
+
- **Fresh-install E2E tests**: 16 integration tests covering CLI commands, hooks, and MCP server lifecycle (OD-607)
|
|
16
|
+
- **README rewrite**: External-developer-facing docs with no internal jargon (OD-608)
|
|
17
|
+
- **CONTRIBUTING.md**: Dev setup, testing tiers, and PR guidelines
|
|
18
|
+
- **First public npm release** (OD-609)
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Package name standardized to `gitmem-mcp` for npm
|
|
22
|
+
- `gitmem configure` output uses `gitmem-mcp` (matching npm package name)
|
|
23
|
+
- Removed internal project defaults from CLI commands
|
|
24
|
+
|
|
10
25
|
## [0.2.0] - 2026-02-08
|
|
11
26
|
|
|
12
27
|
### Added
|
|
@@ -42,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
42
57
|
- Cache management (status, flush, health)
|
|
43
58
|
- Agent identity detection
|
|
44
59
|
|
|
45
|
-
[Unreleased]: https://github.com/nTEG-dev/gitmem/compare/
|
|
60
|
+
[Unreleased]: https://github.com/nTEG-dev/gitmem/compare/v1.0.0...HEAD
|
|
61
|
+
[1.0.0]: https://github.com/nTEG-dev/gitmem/compare/v0.2.0...v1.0.0
|
|
46
62
|
[0.2.0]: https://github.com/nTEG-dev/gitmem/compare/v0.1.0...v0.2.0
|
|
47
63
|
[0.1.0]: https://github.com/nTEG-dev/gitmem/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -2,85 +2,88 @@
|
|
|
2
2
|
|
|
3
3
|
Institutional memory for AI coding agents. Never repeat the same mistake.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
GitMem is an [MCP server](https://modelcontextprotocol.io/) that gives your AI coding agent persistent memory across sessions. It remembers mistakes (scars), successes (wins), and architectural decisions — so your agent learns from experience instead of starting from scratch every time.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Session Start**: Initialize session, detect agent identity, load last session context, retrieve relevant learnings, load recent decisions
|
|
9
|
-
- **Session Close**: Persist session with compliance validation (standard/quick/autonomous close types)
|
|
10
|
-
- **Learning Capture**: Create scars, wins, patterns, and anti-patterns in institutional memory
|
|
11
|
-
- **Decision Logging**: Log architectural and operational decisions
|
|
12
|
-
- **Scar Usage Tracking**: Track scar application for effectiveness measurement
|
|
13
|
-
- **[Threads](docs/threads.md)**: Persistent work items that carry across sessions — create, list, resolve
|
|
14
|
-
- **[Doc-Debt Tracking](docs/doc-debt-tracking.md)**: Detect when decisions outpace documentation updates
|
|
7
|
+
## How It Works
|
|
15
8
|
|
|
16
|
-
|
|
9
|
+
1. **Before each task**, the agent calls `recall` with a plan — GitMem surfaces relevant warnings from past sessions
|
|
10
|
+
2. **When mistakes happen**, the agent captures them as "scars" — failures with context and counter-arguments
|
|
11
|
+
3. **When things go well**, the agent captures wins and patterns to replicate
|
|
12
|
+
4. **At session close**, the agent reflects on what worked, what broke, and what to do differently
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
- **Scars** — Failures to avoid (critical institutional memory)
|
|
20
|
-
- **Patterns** — Neutral observations and recurring patterns
|
|
21
|
-
- **Wins** — Successes to replicate
|
|
22
|
-
- **Anti-patterns** — Known bad approaches
|
|
14
|
+
Over time, your agent builds institutional memory that prevents repeated mistakes and reinforces good patterns.
|
|
23
15
|
|
|
24
|
-
|
|
16
|
+
### Two Tiers
|
|
17
|
+
|
|
18
|
+
| | Free Tier | Pro Tier |
|
|
19
|
+
|---|-----------|----------|
|
|
20
|
+
| **Storage** | Local `.gitmem/` directory | Supabase (PostgreSQL + pgvector) |
|
|
21
|
+
| **Search** | Keyword matching | Semantic vector search |
|
|
22
|
+
| **Setup** | Zero config | Supabase project + embedding API key |
|
|
23
|
+
| **Best for** | Solo projects | Teams, cross-project memory |
|
|
25
24
|
|
|
26
25
|
## Quick Start
|
|
27
26
|
|
|
28
27
|
### Free Tier (zero config)
|
|
29
28
|
|
|
30
29
|
```bash
|
|
31
|
-
npx gitmem init
|
|
32
|
-
npx gitmem configure
|
|
30
|
+
npx gitmem-mcp init
|
|
31
|
+
npx gitmem-mcp configure
|
|
33
32
|
```
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
This creates a `.gitmem/` directory with starter scars and prints the MCP config to add to your editor.
|
|
35
|
+
|
|
36
|
+
Add the config to your project's `.mcp.json` (Claude Code) or IDE settings (Cursor, Windsurf), then copy `CLAUDE.md.template` into your project root. Start coding — memory is active.
|
|
36
37
|
|
|
37
38
|
### Pro Tier (with Supabase)
|
|
38
39
|
|
|
39
40
|
1. Create a free Supabase project at [database.new](https://database.new)
|
|
40
|
-
2. `npx gitmem setup` — copy the SQL output into Supabase SQL Editor
|
|
41
|
+
2. `npx gitmem-mcp setup` — copy the SQL output into Supabase SQL Editor
|
|
41
42
|
3. Get an API key for embeddings (OpenAI, OpenRouter, or Ollama)
|
|
42
|
-
4. `
|
|
43
|
-
5. `npx gitmem
|
|
44
|
-
6.
|
|
45
|
-
7.
|
|
43
|
+
4. Set `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` as environment variables
|
|
44
|
+
5. `npx gitmem-mcp configure` — generates your MCP config with env vars
|
|
45
|
+
6. `npx gitmem-mcp init` — loads starter scars into Supabase
|
|
46
|
+
7. Copy `CLAUDE.md.template` into your project
|
|
47
|
+
8. Start coding — memory is active!
|
|
46
48
|
|
|
47
49
|
## Installation
|
|
48
50
|
|
|
49
|
-
###
|
|
51
|
+
### npx (no install required)
|
|
50
52
|
|
|
51
53
|
```bash
|
|
52
|
-
|
|
54
|
+
npx gitmem-mcp init
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
###
|
|
57
|
+
### Global install
|
|
56
58
|
|
|
57
59
|
```bash
|
|
58
|
-
|
|
60
|
+
npm install -g gitmem-mcp
|
|
61
|
+
gitmem init
|
|
59
62
|
```
|
|
60
63
|
|
|
61
|
-
### MCP
|
|
64
|
+
### MCP Configuration
|
|
62
65
|
|
|
63
|
-
Add to your project's `.mcp.json` (Claude Code) or IDE settings (Cursor, Windsurf):
|
|
66
|
+
Add to your project's `.mcp.json` (Claude Code) or IDE MCP settings (Cursor, Windsurf):
|
|
64
67
|
|
|
68
|
+
**Free Tier:**
|
|
65
69
|
```json
|
|
66
70
|
{
|
|
67
71
|
"mcpServers": {
|
|
68
72
|
"gitmem": {
|
|
69
73
|
"command": "npx",
|
|
70
|
-
"args": ["-y", "gitmem"]
|
|
74
|
+
"args": ["-y", "gitmem-mcp"]
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
```
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
**Pro Tier:**
|
|
78
81
|
```json
|
|
79
82
|
{
|
|
80
83
|
"mcpServers": {
|
|
81
84
|
"gitmem": {
|
|
82
85
|
"command": "npx",
|
|
83
|
-
"args": ["-y", "gitmem"],
|
|
86
|
+
"args": ["-y", "gitmem-mcp"],
|
|
84
87
|
"env": {
|
|
85
88
|
"SUPABASE_URL": "https://your-project.supabase.co",
|
|
86
89
|
"SUPABASE_SERVICE_ROLE_KEY": "eyJ...",
|
|
@@ -91,131 +94,126 @@ For Pro tier, add environment variables:
|
|
|
91
94
|
}
|
|
92
95
|
```
|
|
93
96
|
|
|
97
|
+
Alternative embedding providers (set instead of `OPENAI_API_KEY`):
|
|
98
|
+
- `OPENROUTER_API_KEY` — OpenRouter (multiple models)
|
|
99
|
+
- `OLLAMA_URL` — Local Ollama instance (no API key needed)
|
|
100
|
+
|
|
94
101
|
### Verify
|
|
95
102
|
|
|
96
103
|
```bash
|
|
104
|
+
# Claude Code
|
|
97
105
|
claude mcp list
|
|
98
|
-
# Should show: gitmem:
|
|
106
|
+
# Should show: gitmem: connected
|
|
99
107
|
```
|
|
100
108
|
|
|
101
109
|
## CLI Commands
|
|
102
110
|
|
|
103
111
|
| Command | Description |
|
|
104
112
|
|---------|-------------|
|
|
105
|
-
| `gitmem init` | Initialize memory
|
|
106
|
-
| `gitmem setup` | Output SQL for Supabase schema setup |
|
|
107
|
-
| `gitmem configure` | Generate
|
|
108
|
-
| `gitmem
|
|
113
|
+
| `gitmem init` | Initialize memory — loads starter scars (auto-detects tier) |
|
|
114
|
+
| `gitmem setup` | Output SQL for Supabase schema setup (Pro tier) |
|
|
115
|
+
| `gitmem configure` | Generate MCP config for your editor |
|
|
116
|
+
| `gitmem check` | Run diagnostic health check |
|
|
117
|
+
| `gitmem check --full` | Full diagnostic with benchmarks |
|
|
118
|
+
| `gitmem install-hooks` | Install Claude Code hooks plugin |
|
|
119
|
+
| `gitmem uninstall-hooks` | Remove Claude Code hooks plugin |
|
|
120
|
+
| `gitmem server` | Start MCP server (default when no command given) |
|
|
109
121
|
| `gitmem help` | Show help |
|
|
110
122
|
|
|
111
123
|
## MCP Tools
|
|
112
124
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
Check institutional memory for relevant learnings before taking action.
|
|
116
|
-
|
|
117
|
-
**Parameters:**
|
|
118
|
-
- `plan` (required) - What you're about to do (e.g., "deploy to production")
|
|
119
|
-
- `project?` - Project scope (default: "orchestra_dev")
|
|
120
|
-
- `match_count?` - Number of learnings to return (default: 3)
|
|
121
|
-
|
|
122
|
-
### `session_start`
|
|
123
|
-
|
|
124
|
-
Initialize session and load institutional context.
|
|
125
|
-
|
|
126
|
-
**Parameters:**
|
|
127
|
-
- `agent_identity?` - Override agent identity (auto-detects if not provided)
|
|
128
|
-
- `linear_issue?` - Current Linear issue identifier
|
|
129
|
-
- `project?` - Project scope
|
|
130
|
-
|
|
131
|
-
### `session_close`
|
|
125
|
+
GitMem exposes tools via the Model Context Protocol. Your AI agent calls these automatically based on the instructions in `CLAUDE.md.template`.
|
|
132
126
|
|
|
133
|
-
|
|
127
|
+
### Core Tools
|
|
134
128
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
129
|
+
| Tool | Purpose |
|
|
130
|
+
|------|---------|
|
|
131
|
+
| `recall` | Check memory for relevant warnings before taking action |
|
|
132
|
+
| `session_start` | Initialize session, load context from last session |
|
|
133
|
+
| `session_close` | Persist session with reflection |
|
|
134
|
+
| `create_learning` | Capture scars (failures), wins (successes), or patterns |
|
|
135
|
+
| `create_decision` | Log architectural/operational decisions |
|
|
136
|
+
| `record_scar_usage` | Track which scars were applied |
|
|
137
|
+
| `search` | Search institutional memory (exploration, no side effects) |
|
|
138
|
+
| `log` | List recent learnings chronologically |
|
|
140
139
|
|
|
141
|
-
###
|
|
140
|
+
### Thread Tools
|
|
142
141
|
|
|
143
|
-
|
|
142
|
+
Threads are persistent work items that carry across sessions.
|
|
144
143
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
144
|
+
| Tool | Purpose |
|
|
145
|
+
|------|---------|
|
|
146
|
+
| `list_threads` | List open threads |
|
|
147
|
+
| `create_thread` | Create a new thread |
|
|
148
|
+
| `resolve_thread` | Mark a thread as resolved |
|
|
150
149
|
|
|
151
|
-
###
|
|
150
|
+
### Pro Tier Tools
|
|
152
151
|
|
|
153
|
-
|
|
152
|
+
Available when Supabase is configured:
|
|
154
153
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
| Tool | Purpose |
|
|
155
|
+
|------|---------|
|
|
156
|
+
| `analyze` | Session analytics and pattern detection |
|
|
157
|
+
| `prepare_context` | Multi-agent context preparation |
|
|
158
|
+
| `absorb_observations` | Multi-agent observation absorption |
|
|
159
|
+
| Cache tools | `cache_status`, `cache_flush`, `cache_health` |
|
|
161
160
|
|
|
162
|
-
|
|
161
|
+
## Learning Types
|
|
163
162
|
|
|
164
|
-
|
|
163
|
+
GitMem tracks four types of institutional knowledge:
|
|
165
164
|
|
|
166
|
-
**
|
|
167
|
-
-
|
|
168
|
-
-
|
|
169
|
-
-
|
|
165
|
+
- **Scars** — Failures to avoid. Include severity and counter-arguments (why someone might think the mistake is OK). These are the core of GitMem.
|
|
166
|
+
- **Wins** — Successes to replicate. Capture what worked and why.
|
|
167
|
+
- **Patterns** — Neutral observations and recurring approaches.
|
|
168
|
+
- **Anti-patterns** — Known bad approaches to flag.
|
|
170
169
|
|
|
171
|
-
|
|
170
|
+
All types are searched together when `recall` is called, giving the agent comprehensive context.
|
|
172
171
|
|
|
173
|
-
|
|
172
|
+
## Hooks Plugin
|
|
174
173
|
|
|
175
|
-
|
|
176
|
-
- `status?` - Filter: "open" (default) or "resolved"
|
|
177
|
-
- `include_resolved?` - Include recently resolved threads
|
|
174
|
+
GitMem includes a Claude Code hooks plugin that automates memory protocols:
|
|
178
175
|
|
|
179
|
-
|
|
176
|
+
- **SessionStart** — Automatically calls `session_start` when a session begins
|
|
177
|
+
- **PreToolUse** — Reminds the agent to call `recall` before consequential actions
|
|
178
|
+
- **PostToolUse** — Tracks scar acknowledgment
|
|
179
|
+
- **Stop** — Reminds the agent to close sessions properly
|
|
180
180
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
### `resolve_thread`
|
|
187
|
-
|
|
188
|
-
Mark a thread as resolved.
|
|
181
|
+
Install:
|
|
182
|
+
```bash
|
|
183
|
+
npx gitmem-mcp install-hooks
|
|
184
|
+
```
|
|
189
185
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
Uninstall:
|
|
187
|
+
```bash
|
|
188
|
+
npx gitmem-mcp uninstall-hooks
|
|
189
|
+
```
|
|
194
190
|
|
|
195
191
|
## Agent Detection
|
|
196
192
|
|
|
197
|
-
|
|
198
|
-
- `CLAUDE_CODE_ENTRYPOINT` environment variable
|
|
199
|
-
- Docker container presence (`/.dockerenv`)
|
|
200
|
-
- Hostname
|
|
193
|
+
GitMem automatically detects the AI agent identity based on environment:
|
|
201
194
|
|
|
202
|
-
|
|
|
203
|
-
|
|
204
|
-
|
|
|
205
|
-
|
|
|
206
|
-
|
|
|
207
|
-
|
|
|
208
|
-
|
|
195
|
+
| Environment | Identity |
|
|
196
|
+
|-------------|----------|
|
|
197
|
+
| Claude Code in Docker | CLI |
|
|
198
|
+
| Claude Desktop app | DAC |
|
|
199
|
+
| Claude.ai with filesystem | Brain_Local |
|
|
200
|
+
| Claude.ai without filesystem | Brain_Cloud |
|
|
201
|
+
|
|
202
|
+
Override with `agent_identity` parameter in `session_start`.
|
|
209
203
|
|
|
210
204
|
## Development
|
|
211
205
|
|
|
212
206
|
```bash
|
|
207
|
+
git clone https://github.com/nTEG-dev/gitmem.git
|
|
208
|
+
cd gitmem
|
|
213
209
|
npm install
|
|
214
|
-
npm run build
|
|
215
|
-
npm run dev
|
|
216
|
-
npm test
|
|
210
|
+
npm run build # Compile TypeScript + run unit tests
|
|
211
|
+
npm run dev # Watch mode
|
|
212
|
+
npm test # Run unit tests
|
|
217
213
|
```
|
|
218
214
|
|
|
215
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing tiers, and PR guidelines.
|
|
216
|
+
|
|
219
217
|
## License
|
|
220
218
|
|
|
221
|
-
MIT
|
|
219
|
+
MIT — see [LICENSE](LICENSE).
|
package/bin/gitmem.js
CHANGED
|
@@ -4,15 +4,29 @@
|
|
|
4
4
|
* GitMem CLI
|
|
5
5
|
*
|
|
6
6
|
* Commands:
|
|
7
|
-
* gitmem setup
|
|
8
|
-
* gitmem init
|
|
9
|
-
* gitmem configure
|
|
10
|
-
* gitmem
|
|
7
|
+
* gitmem setup — Output SQL to paste into Supabase SQL Editor (pro/dev)
|
|
8
|
+
* gitmem init — Load starter scars (local JSON or Supabase)
|
|
9
|
+
* gitmem configure — Generate .mcp.json entry for Claude Code
|
|
10
|
+
* gitmem check — Run diagnostic health check
|
|
11
|
+
* gitmem install-hooks — Install Claude Code hooks plugin
|
|
12
|
+
* gitmem uninstall-hooks — Remove Claude Code hooks plugin
|
|
13
|
+
* gitmem server — Start MCP server (default)
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
readFileSync,
|
|
18
|
+
writeFileSync,
|
|
19
|
+
mkdirSync,
|
|
20
|
+
existsSync,
|
|
21
|
+
cpSync,
|
|
22
|
+
rmSync,
|
|
23
|
+
readdirSync,
|
|
24
|
+
chmodSync,
|
|
25
|
+
statSync,
|
|
26
|
+
} from "fs";
|
|
14
27
|
import { dirname, join } from "path";
|
|
15
28
|
import { fileURLToPath } from "url";
|
|
29
|
+
import { homedir } from "os";
|
|
16
30
|
|
|
17
31
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
32
|
const command = process.argv[2];
|
|
@@ -22,11 +36,15 @@ function printUsage() {
|
|
|
22
36
|
GitMem — Institutional Memory for AI Coding
|
|
23
37
|
|
|
24
38
|
Usage:
|
|
25
|
-
npx gitmem setup
|
|
26
|
-
npx gitmem init
|
|
27
|
-
npx gitmem configure
|
|
28
|
-
npx gitmem
|
|
29
|
-
npx gitmem
|
|
39
|
+
npx gitmem setup Output SQL for Supabase schema setup (pro/dev tier)
|
|
40
|
+
npx gitmem init Load starter scars (auto-detects tier)
|
|
41
|
+
npx gitmem configure Generate .mcp.json config for Claude Code
|
|
42
|
+
npx gitmem check Run diagnostic health check
|
|
43
|
+
npx gitmem check --full Full diagnostic with benchmarks
|
|
44
|
+
npx gitmem install-hooks Install Claude Code hooks plugin
|
|
45
|
+
npx gitmem uninstall-hooks Remove Claude Code hooks plugin
|
|
46
|
+
npx gitmem server Start MCP server (default)
|
|
47
|
+
npx gitmem help Show this help message
|
|
30
48
|
|
|
31
49
|
Free Tier (zero config):
|
|
32
50
|
1. npx gitmem init
|
|
@@ -183,7 +201,7 @@ function cmdConfigure() {
|
|
|
183
201
|
mcpServers: {
|
|
184
202
|
gitmem: {
|
|
185
203
|
command: "npx",
|
|
186
|
-
args: ["-y", "
|
|
204
|
+
args: ["-y", "gitmem-mcp"],
|
|
187
205
|
},
|
|
188
206
|
},
|
|
189
207
|
};
|
|
@@ -202,7 +220,7 @@ function cmdConfigure() {
|
|
|
202
220
|
mcpServers: {
|
|
203
221
|
gitmem: {
|
|
204
222
|
command: "npx",
|
|
205
|
-
args: ["-y", "
|
|
223
|
+
args: ["-y", "gitmem-mcp"],
|
|
206
224
|
env: {
|
|
207
225
|
SUPABASE_URL: "https://YOUR_PROJECT.supabase.co",
|
|
208
226
|
SUPABASE_SERVICE_ROLE_KEY: "eyJ...",
|
|
@@ -238,7 +256,7 @@ function cmdConfigure() {
|
|
|
238
256
|
*/
|
|
239
257
|
async function cmdSessionStart() {
|
|
240
258
|
const args = process.argv.slice(3);
|
|
241
|
-
let project =
|
|
259
|
+
let project = undefined;
|
|
242
260
|
let agentIdentity = undefined;
|
|
243
261
|
|
|
244
262
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -347,6 +365,207 @@ async function cmdSessionRefresh() {
|
|
|
347
365
|
}
|
|
348
366
|
}
|
|
349
367
|
|
|
368
|
+
/**
|
|
369
|
+
* Install the bundled hooks plugin to ~/.claude/plugins/gitmem-hooks/
|
|
370
|
+
*
|
|
371
|
+
* Copies the hooks/ directory from this package into the Claude Code
|
|
372
|
+
* plugins directory. Use --force to overwrite an existing installation.
|
|
373
|
+
*/
|
|
374
|
+
function cmdInstallHooks() {
|
|
375
|
+
const force = process.argv.includes("--force");
|
|
376
|
+
const hooksSource = join(__dirname, "..", "hooks");
|
|
377
|
+
const pluginsDir = join(homedir(), ".claude", "plugins");
|
|
378
|
+
const targetDir = join(pluginsDir, "gitmem-hooks");
|
|
379
|
+
|
|
380
|
+
console.log("GitMem Hooks Plugin — Install");
|
|
381
|
+
console.log("=============================");
|
|
382
|
+
console.log("");
|
|
383
|
+
|
|
384
|
+
// Check that bundled hooks exist
|
|
385
|
+
if (!existsSync(hooksSource) || !existsSync(join(hooksSource, ".claude-plugin", "plugin.json"))) {
|
|
386
|
+
console.error("Error: Bundled hooks directory not found.");
|
|
387
|
+
console.error("Expected at:", hooksSource);
|
|
388
|
+
console.error("Ensure the package is installed correctly.");
|
|
389
|
+
process.exit(1);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Check if already installed
|
|
393
|
+
if (existsSync(targetDir) && !force) {
|
|
394
|
+
console.log("Hooks plugin is already installed at:");
|
|
395
|
+
console.log(` ${targetDir}`);
|
|
396
|
+
console.log("");
|
|
397
|
+
console.log("To reinstall (overwrite), run:");
|
|
398
|
+
console.log(" npx gitmem install-hooks --force");
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Create plugins directory if needed
|
|
403
|
+
if (!existsSync(pluginsDir)) {
|
|
404
|
+
mkdirSync(pluginsDir, { recursive: true });
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Copy hooks to target
|
|
408
|
+
console.log(`Source: ${hooksSource}`);
|
|
409
|
+
console.log(`Target: ${targetDir}`);
|
|
410
|
+
console.log("");
|
|
411
|
+
|
|
412
|
+
try {
|
|
413
|
+
cpSync(hooksSource, targetDir, { recursive: true });
|
|
414
|
+
} catch (err) {
|
|
415
|
+
console.error("Error copying hooks plugin:", err.message);
|
|
416
|
+
process.exit(1);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Make shell scripts executable
|
|
420
|
+
const scriptsDir = join(targetDir, "scripts");
|
|
421
|
+
if (existsSync(scriptsDir)) {
|
|
422
|
+
for (const file of readdirSync(scriptsDir)) {
|
|
423
|
+
if (file.endsWith(".sh")) {
|
|
424
|
+
chmodSync(join(scriptsDir, file), 0o755);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
const testsDir = join(targetDir, "tests");
|
|
429
|
+
if (existsSync(testsDir)) {
|
|
430
|
+
for (const file of readdirSync(testsDir)) {
|
|
431
|
+
if (file.endsWith(".sh")) {
|
|
432
|
+
chmodSync(join(testsDir, file), 0o755);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
console.log("Installed successfully!");
|
|
438
|
+
console.log("");
|
|
439
|
+
|
|
440
|
+
// Verify gitmem MCP is configured (non-blocking warning)
|
|
441
|
+
let mcpFound = false;
|
|
442
|
+
const mcpPaths = [
|
|
443
|
+
join(process.cwd(), ".mcp.json"),
|
|
444
|
+
join(process.cwd(), ".claude", "mcp.json"),
|
|
445
|
+
join(homedir(), ".claude.json"),
|
|
446
|
+
];
|
|
447
|
+
for (const p of mcpPaths) {
|
|
448
|
+
if (existsSync(p)) {
|
|
449
|
+
try {
|
|
450
|
+
const cfg = JSON.parse(readFileSync(p, "utf-8"));
|
|
451
|
+
const servers = cfg.mcpServers || {};
|
|
452
|
+
if (servers.gitmem || servers["gitmem-mcp"]) {
|
|
453
|
+
mcpFound = true;
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
} catch {
|
|
457
|
+
// ignore parse errors
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (!mcpFound) {
|
|
463
|
+
console.log("WARNING: gitmem MCP server not detected in .mcp.json.");
|
|
464
|
+
console.log(" Hooks will be silent until gitmem MCP is configured.");
|
|
465
|
+
console.log(" Run: npx gitmem configure");
|
|
466
|
+
console.log("");
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
console.log("Next steps:");
|
|
470
|
+
console.log(" 1. Restart Claude Code (exit and re-open)");
|
|
471
|
+
console.log(" 2. The plugin hooks will activate on next session");
|
|
472
|
+
console.log("");
|
|
473
|
+
console.log("To update after a gitmem version bump:");
|
|
474
|
+
console.log(" npx gitmem install-hooks --force");
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Uninstall the hooks plugin from ~/.claude/plugins/gitmem-hooks/
|
|
479
|
+
*
|
|
480
|
+
* Removes the plugin directory, cleans up enabledPlugins from settings,
|
|
481
|
+
* and removes temp state directories.
|
|
482
|
+
*/
|
|
483
|
+
function cmdUninstallHooks() {
|
|
484
|
+
const pluginDir = join(homedir(), ".claude", "plugins", "gitmem-hooks");
|
|
485
|
+
|
|
486
|
+
console.log("GitMem Hooks Plugin — Uninstall");
|
|
487
|
+
console.log("===============================");
|
|
488
|
+
console.log("");
|
|
489
|
+
|
|
490
|
+
// Remove plugin directory
|
|
491
|
+
if (existsSync(pluginDir)) {
|
|
492
|
+
rmSync(pluginDir, { recursive: true, force: true });
|
|
493
|
+
console.log("[uninstall] Removed plugin directory:", pluginDir);
|
|
494
|
+
} else {
|
|
495
|
+
console.log("[uninstall] Plugin directory not found (already removed)");
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Clean enabledPlugins from .claude/settings.json
|
|
499
|
+
// (Key scar: claude plugin uninstall doesn't always clean this up)
|
|
500
|
+
const settingsFiles = [
|
|
501
|
+
join(process.cwd(), ".claude", "settings.json"),
|
|
502
|
+
join(process.cwd(), ".claude", "settings.local.json"),
|
|
503
|
+
];
|
|
504
|
+
|
|
505
|
+
for (const settingsPath of settingsFiles) {
|
|
506
|
+
if (existsSync(settingsPath)) {
|
|
507
|
+
try {
|
|
508
|
+
const cfg = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
509
|
+
if (cfg.enabledPlugins) {
|
|
510
|
+
let cleaned = false;
|
|
511
|
+
for (const key of Object.keys(cfg.enabledPlugins)) {
|
|
512
|
+
if (key.startsWith("gitmem-hooks")) {
|
|
513
|
+
delete cfg.enabledPlugins[key];
|
|
514
|
+
cleaned = true;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (cleaned) {
|
|
518
|
+
writeFileSync(settingsPath, JSON.stringify(cfg, null, 2) + "\n");
|
|
519
|
+
console.log(`[cleanup] Removed enabledPlugins entry from ${settingsPath}`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
} catch {
|
|
523
|
+
// ignore parse errors
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Clean temp state directories
|
|
529
|
+
let cleaned = 0;
|
|
530
|
+
try {
|
|
531
|
+
const tmpDir = "/tmp";
|
|
532
|
+
for (const entry of readdirSync(tmpDir)) {
|
|
533
|
+
if (entry.startsWith("gitmem-hooks-")) {
|
|
534
|
+
const fullPath = join(tmpDir, entry);
|
|
535
|
+
try {
|
|
536
|
+
if (statSync(fullPath).isDirectory()) {
|
|
537
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
538
|
+
cleaned++;
|
|
539
|
+
}
|
|
540
|
+
} catch {
|
|
541
|
+
// ignore permission errors on other users' temp dirs
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
} catch {
|
|
546
|
+
// /tmp read error — not critical
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (cleaned > 0) {
|
|
550
|
+
console.log(`[cleanup] Removed ${cleaned} temp state director(ies) from /tmp/`);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Clean debug log
|
|
554
|
+
const debugLog = "/tmp/gitmem-hooks-plugin-debug.log";
|
|
555
|
+
if (existsSync(debugLog)) {
|
|
556
|
+
rmSync(debugLog, { force: true });
|
|
557
|
+
console.log("[cleanup] Removed debug log");
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
console.log("");
|
|
561
|
+
console.log("Uninstall complete.");
|
|
562
|
+
console.log("");
|
|
563
|
+
console.log("Notes:");
|
|
564
|
+
console.log(" - gitmem MCP server config (.mcp.json) was NOT modified");
|
|
565
|
+
console.log(" - Restart Claude Code for changes to take effect");
|
|
566
|
+
console.log(" - To reinstall: npx gitmem install-hooks");
|
|
567
|
+
}
|
|
568
|
+
|
|
350
569
|
switch (command) {
|
|
351
570
|
case "setup":
|
|
352
571
|
cmdSetup();
|
|
@@ -357,6 +576,15 @@ switch (command) {
|
|
|
357
576
|
case "configure":
|
|
358
577
|
cmdConfigure();
|
|
359
578
|
break;
|
|
579
|
+
case "check":
|
|
580
|
+
import("../dist/commands/check.js").then((m) => m.main(process.argv.slice(3)));
|
|
581
|
+
break;
|
|
582
|
+
case "install-hooks":
|
|
583
|
+
cmdInstallHooks();
|
|
584
|
+
break;
|
|
585
|
+
case "uninstall-hooks":
|
|
586
|
+
cmdUninstallHooks();
|
|
587
|
+
break;
|
|
360
588
|
case "session-start":
|
|
361
589
|
cmdSessionStart();
|
|
362
590
|
break;
|
|
@@ -373,7 +601,7 @@ switch (command) {
|
|
|
373
601
|
printUsage();
|
|
374
602
|
break;
|
|
375
603
|
case undefined:
|
|
376
|
-
// Default: start MCP server (npx
|
|
604
|
+
// Default: start MCP server (npx gitmem-mcp should start serving)
|
|
377
605
|
import("../dist/index.js");
|
|
378
606
|
break;
|
|
379
607
|
default:
|