gitmem-mcp 1.0.0 → 1.0.1

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.
Files changed (246) hide show
  1. package/CLAUDE.md.template +63 -55
  2. package/README.md +60 -29
  3. package/bin/gitmem.js +233 -109
  4. package/bin/init-wizard.js +642 -0
  5. package/bin/uninstall.js +288 -0
  6. package/dist/commands/check.js +20 -20
  7. package/dist/commands/check.js.map +1 -1
  8. package/dist/constants/closing-questions.d.ts +6 -0
  9. package/dist/constants/closing-questions.d.ts.map +1 -1
  10. package/dist/constants/closing-questions.js +65 -0
  11. package/dist/constants/closing-questions.js.map +1 -1
  12. package/dist/hooks/format-utils.d.ts +52 -0
  13. package/dist/hooks/format-utils.d.ts.map +1 -0
  14. package/dist/hooks/format-utils.js +89 -0
  15. package/dist/hooks/format-utils.js.map +1 -0
  16. package/dist/hooks/quick-retrieve.d.ts +30 -0
  17. package/dist/hooks/quick-retrieve.d.ts.map +1 -0
  18. package/dist/hooks/quick-retrieve.js +149 -0
  19. package/dist/hooks/quick-retrieve.js.map +1 -0
  20. package/dist/index.js +0 -0
  21. package/dist/schemas/active-sessions.d.ts +8 -8
  22. package/dist/schemas/analyze.d.ts +3 -3
  23. package/dist/schemas/common.d.ts +2 -2
  24. package/dist/schemas/common.d.ts.map +1 -1
  25. package/dist/schemas/common.js +1 -1
  26. package/dist/schemas/common.js.map +1 -1
  27. package/dist/schemas/create-decision.d.ts +3 -3
  28. package/dist/schemas/create-learning.d.ts +13 -13
  29. package/dist/schemas/log.d.ts +3 -3
  30. package/dist/schemas/prepare-context.d.ts +3 -3
  31. package/dist/schemas/recall.d.ts +3 -3
  32. package/dist/schemas/record-scar-usage-batch.d.ts +8 -3
  33. package/dist/schemas/record-scar-usage-batch.d.ts.map +1 -1
  34. package/dist/schemas/record-scar-usage.d.ts +3 -0
  35. package/dist/schemas/record-scar-usage.d.ts.map +1 -1
  36. package/dist/schemas/record-scar-usage.js +1 -0
  37. package/dist/schemas/record-scar-usage.js.map +1 -1
  38. package/dist/schemas/registry.d.ts +18 -0
  39. package/dist/schemas/registry.d.ts.map +1 -0
  40. package/dist/schemas/registry.js +158 -0
  41. package/dist/schemas/registry.js.map +1 -0
  42. package/dist/schemas/save-transcript.d.ts +3 -3
  43. package/dist/schemas/search-transcripts.d.ts +33 -0
  44. package/dist/schemas/search-transcripts.d.ts.map +1 -0
  45. package/dist/schemas/search-transcripts.js +26 -0
  46. package/dist/schemas/search-transcripts.js.map +1 -0
  47. package/dist/schemas/search.d.ts +3 -3
  48. package/dist/schemas/session-close.d.ts +43 -15
  49. package/dist/schemas/session-close.d.ts.map +1 -1
  50. package/dist/schemas/session-close.js +7 -2
  51. package/dist/schemas/session-close.js.map +1 -1
  52. package/dist/schemas/session-start.d.ts +3 -3
  53. package/dist/schemas/thread.d.ts +3 -3
  54. package/dist/server.d.ts.map +1 -1
  55. package/dist/server.js +82 -28
  56. package/dist/server.js.map +1 -1
  57. package/dist/services/active-sessions.d.ts +2 -1
  58. package/dist/services/active-sessions.d.ts.map +1 -1
  59. package/dist/services/active-sessions.js +130 -84
  60. package/dist/services/active-sessions.js.map +1 -1
  61. package/dist/services/analytics.d.ts.map +1 -1
  62. package/dist/services/analytics.js +1 -0
  63. package/dist/services/analytics.js.map +1 -1
  64. package/dist/services/behavioral-decay.d.ts +40 -0
  65. package/dist/services/behavioral-decay.d.ts.map +1 -0
  66. package/dist/services/behavioral-decay.js +110 -0
  67. package/dist/services/behavioral-decay.js.map +1 -0
  68. package/dist/services/bm25.d.ts +39 -0
  69. package/dist/services/bm25.d.ts.map +1 -0
  70. package/dist/services/bm25.js +132 -0
  71. package/dist/services/bm25.js.map +1 -0
  72. package/dist/services/cache.d.ts.map +1 -1
  73. package/dist/services/cache.js +9 -8
  74. package/dist/services/cache.js.map +1 -1
  75. package/dist/services/cache.test.js +17 -17
  76. package/dist/services/cache.test.js.map +1 -1
  77. package/dist/services/compliance-validator.d.ts.map +1 -1
  78. package/dist/services/compliance-validator.js +12 -1
  79. package/dist/services/compliance-validator.js.map +1 -1
  80. package/dist/services/display-protocol.d.ts +31 -0
  81. package/dist/services/display-protocol.d.ts.map +1 -0
  82. package/dist/services/display-protocol.js +73 -0
  83. package/dist/services/display-protocol.js.map +1 -0
  84. package/dist/services/effect-tracker.d.ts +81 -0
  85. package/dist/services/effect-tracker.d.ts.map +1 -0
  86. package/dist/services/effect-tracker.js +181 -0
  87. package/dist/services/effect-tracker.js.map +1 -0
  88. package/dist/services/file-lock.d.ts +31 -0
  89. package/dist/services/file-lock.d.ts.map +1 -0
  90. package/dist/services/file-lock.js +124 -0
  91. package/dist/services/file-lock.js.map +1 -0
  92. package/dist/services/gitmem-dir.d.ts +7 -0
  93. package/dist/services/gitmem-dir.d.ts.map +1 -1
  94. package/dist/services/gitmem-dir.js +21 -0
  95. package/dist/services/gitmem-dir.js.map +1 -1
  96. package/dist/services/local-file-storage.d.ts +3 -2
  97. package/dist/services/local-file-storage.d.ts.map +1 -1
  98. package/dist/services/local-file-storage.js +30 -43
  99. package/dist/services/local-file-storage.js.map +1 -1
  100. package/dist/services/local-vector-search.d.ts +10 -9
  101. package/dist/services/local-vector-search.d.ts.map +1 -1
  102. package/dist/services/local-vector-search.js +28 -23
  103. package/dist/services/local-vector-search.js.map +1 -1
  104. package/dist/services/metrics.d.ts +7 -2
  105. package/dist/services/metrics.d.ts.map +1 -1
  106. package/dist/services/metrics.js +41 -33
  107. package/dist/services/metrics.js.map +1 -1
  108. package/dist/services/session-state.d.ts +8 -0
  109. package/dist/services/session-state.d.ts.map +1 -1
  110. package/dist/services/session-state.js +9 -2
  111. package/dist/services/session-state.js.map +1 -1
  112. package/dist/services/startup.d.ts +12 -13
  113. package/dist/services/startup.d.ts.map +1 -1
  114. package/dist/services/startup.js +104 -57
  115. package/dist/services/startup.js.map +1 -1
  116. package/dist/services/supabase-client.d.ts +2 -1
  117. package/dist/services/supabase-client.d.ts.map +1 -1
  118. package/dist/services/supabase-client.js +22 -16
  119. package/dist/services/supabase-client.js.map +1 -1
  120. package/dist/services/thread-dedup.d.ts +9 -0
  121. package/dist/services/thread-dedup.d.ts.map +1 -1
  122. package/dist/services/thread-dedup.js +27 -0
  123. package/dist/services/thread-dedup.js.map +1 -1
  124. package/dist/services/thread-manager.d.ts.map +1 -1
  125. package/dist/services/thread-manager.js +38 -16
  126. package/dist/services/thread-manager.js.map +1 -1
  127. package/dist/services/thread-suggestions.d.ts.map +1 -1
  128. package/dist/services/thread-suggestions.js +1 -1
  129. package/dist/services/thread-suggestions.js.map +1 -1
  130. package/dist/services/thread-supabase.d.ts +0 -1
  131. package/dist/services/thread-supabase.d.ts.map +1 -1
  132. package/dist/services/thread-supabase.js +83 -54
  133. package/dist/services/thread-supabase.js.map +1 -1
  134. package/dist/services/timezone.d.ts.map +1 -1
  135. package/dist/services/timezone.js +1 -0
  136. package/dist/services/timezone.js.map +1 -1
  137. package/dist/services/transcript-chunker.d.ts.map +1 -1
  138. package/dist/services/transcript-chunker.js +18 -4
  139. package/dist/services/transcript-chunker.js.map +1 -1
  140. package/dist/services/variant-generation.d.ts +41 -0
  141. package/dist/services/variant-generation.d.ts.map +1 -0
  142. package/dist/services/variant-generation.js +263 -0
  143. package/dist/services/variant-generation.js.map +1 -0
  144. package/dist/tools/absorb-observations.d.ts.map +1 -1
  145. package/dist/tools/absorb-observations.js +9 -0
  146. package/dist/tools/absorb-observations.js.map +1 -1
  147. package/dist/tools/analyze.d.ts.map +1 -1
  148. package/dist/tools/analyze.js +13 -2
  149. package/dist/tools/analyze.js.map +1 -1
  150. package/dist/tools/archive-learning.d.ts +28 -0
  151. package/dist/tools/archive-learning.d.ts.map +1 -0
  152. package/dist/tools/archive-learning.js +81 -0
  153. package/dist/tools/archive-learning.js.map +1 -0
  154. package/dist/tools/cleanup-threads.d.ts +1 -0
  155. package/dist/tools/cleanup-threads.d.ts.map +1 -1
  156. package/dist/tools/cleanup-threads.js +111 -18
  157. package/dist/tools/cleanup-threads.js.map +1 -1
  158. package/dist/tools/confirm-scars.d.ts.map +1 -1
  159. package/dist/tools/confirm-scars.js +8 -2
  160. package/dist/tools/confirm-scars.js.map +1 -1
  161. package/dist/tools/create-decision.d.ts.map +1 -1
  162. package/dist/tools/create-decision.js +11 -8
  163. package/dist/tools/create-decision.js.map +1 -1
  164. package/dist/tools/create-learning.d.ts.map +1 -1
  165. package/dist/tools/create-learning.js +35 -11
  166. package/dist/tools/create-learning.js.map +1 -1
  167. package/dist/tools/create-linear-issue.d.ts +18 -0
  168. package/dist/tools/create-linear-issue.d.ts.map +1 -0
  169. package/dist/tools/create-linear-issue.js +197 -0
  170. package/dist/tools/create-linear-issue.js.map +1 -0
  171. package/dist/tools/create-thread.d.ts +2 -1
  172. package/dist/tools/create-thread.d.ts.map +1 -1
  173. package/dist/tools/create-thread.js +9 -4
  174. package/dist/tools/create-thread.js.map +1 -1
  175. package/dist/tools/definitions.d.ts +785 -34
  176. package/dist/tools/definitions.d.ts.map +1 -1
  177. package/dist/tools/definitions.js +239 -95
  178. package/dist/tools/definitions.js.map +1 -1
  179. package/dist/tools/dismiss-suggestion.d.ts +1 -0
  180. package/dist/tools/dismiss-suggestion.d.ts.map +1 -1
  181. package/dist/tools/dismiss-suggestion.js +4 -0
  182. package/dist/tools/dismiss-suggestion.js.map +1 -1
  183. package/dist/tools/graph-traverse.d.ts +1 -0
  184. package/dist/tools/graph-traverse.d.ts.map +1 -1
  185. package/dist/tools/graph-traverse.js +24 -9
  186. package/dist/tools/graph-traverse.js.map +1 -1
  187. package/dist/tools/list-threads.d.ts.map +1 -1
  188. package/dist/tools/list-threads.js +49 -5
  189. package/dist/tools/list-threads.js.map +1 -1
  190. package/dist/tools/log.d.ts +1 -0
  191. package/dist/tools/log.d.ts.map +1 -1
  192. package/dist/tools/log.js +84 -17
  193. package/dist/tools/log.js.map +1 -1
  194. package/dist/tools/prepare-context.d.ts +1 -0
  195. package/dist/tools/prepare-context.d.ts.map +1 -1
  196. package/dist/tools/prepare-context.js +15 -85
  197. package/dist/tools/prepare-context.js.map +1 -1
  198. package/dist/tools/promote-suggestion.d.ts +1 -0
  199. package/dist/tools/promote-suggestion.d.ts.map +1 -1
  200. package/dist/tools/promote-suggestion.js +5 -0
  201. package/dist/tools/promote-suggestion.js.map +1 -1
  202. package/dist/tools/recall.d.ts +2 -0
  203. package/dist/tools/recall.d.ts.map +1 -1
  204. package/dist/tools/recall.js +43 -10
  205. package/dist/tools/recall.js.map +1 -1
  206. package/dist/tools/recall.test.js +6 -6
  207. package/dist/tools/recall.test.js.map +1 -1
  208. package/dist/tools/record-scar-usage-batch.d.ts.map +1 -1
  209. package/dist/tools/record-scar-usage-batch.js +13 -0
  210. package/dist/tools/record-scar-usage-batch.js.map +1 -1
  211. package/dist/tools/record-scar-usage.d.ts.map +1 -1
  212. package/dist/tools/record-scar-usage.js +6 -0
  213. package/dist/tools/record-scar-usage.js.map +1 -1
  214. package/dist/tools/resolve-thread.d.ts.map +1 -1
  215. package/dist/tools/resolve-thread.js +57 -6
  216. package/dist/tools/resolve-thread.js.map +1 -1
  217. package/dist/tools/save-transcript.d.ts +1 -0
  218. package/dist/tools/save-transcript.d.ts.map +1 -1
  219. package/dist/tools/save-transcript.js +3 -1
  220. package/dist/tools/save-transcript.js.map +1 -1
  221. package/dist/tools/search-transcripts.d.ts +44 -0
  222. package/dist/tools/search-transcripts.d.ts.map +1 -0
  223. package/dist/tools/search-transcripts.js +158 -0
  224. package/dist/tools/search-transcripts.js.map +1 -0
  225. package/dist/tools/search.d.ts +1 -0
  226. package/dist/tools/search.d.ts.map +1 -1
  227. package/dist/tools/search.js +74 -3
  228. package/dist/tools/search.js.map +1 -1
  229. package/dist/tools/session-close.d.ts.map +1 -1
  230. package/dist/tools/session-close.js +563 -326
  231. package/dist/tools/session-close.js.map +1 -1
  232. package/dist/tools/session-start.d.ts +10 -6
  233. package/dist/tools/session-start.d.ts.map +1 -1
  234. package/dist/tools/session-start.js +317 -426
  235. package/dist/tools/session-start.js.map +1 -1
  236. package/dist/types/index.d.ts +37 -4
  237. package/dist/types/index.d.ts.map +1 -1
  238. package/hooks/hooks/hooks.json +8 -37
  239. package/hooks/scripts/auto-retrieve-hook.sh +163 -0
  240. package/hooks/scripts/post-tool-use.sh +0 -16
  241. package/hooks/scripts/recall-check.sh +0 -11
  242. package/hooks/scripts/session-close-check.sh +1 -1
  243. package/hooks/scripts/session-start.sh +89 -13
  244. package/hooks/tests/test-hooks.sh +3 -49
  245. package/package.json +3 -2
  246. package/schema/setup.sql +1 -1
package/bin/gitmem.js CHANGED
@@ -4,8 +4,9 @@
4
4
  * GitMem CLI
5
5
  *
6
6
  * Commands:
7
+ * gitmem init — Interactive setup wizard (detects, prompts, merges)
8
+ * gitmem uninstall — Clean reverse of everything init did
7
9
  * gitmem setup — Output SQL to paste into Supabase SQL Editor (pro/dev)
8
- * gitmem init — Load starter scars (local JSON or Supabase)
9
10
  * gitmem configure — Generate .mcp.json entry for Claude Code
10
11
  * gitmem check — Run diagnostic health check
11
12
  * gitmem install-hooks — Install Claude Code hooks plugin
@@ -36,30 +37,32 @@ function printUsage() {
36
37
  GitMem — Institutional Memory for AI Coding
37
38
 
38
39
  Usage:
40
+ npx gitmem init Interactive setup wizard (recommended)
41
+ npx gitmem init --yes Non-interactive setup (accept all defaults)
42
+ npx gitmem init --dry-run Show what would be configured
43
+ npx gitmem uninstall Clean removal of gitmem from project
44
+ npx gitmem uninstall --all Also delete .gitmem/ data directory
45
+
46
+ Other commands:
39
47
  npx gitmem setup Output SQL for Supabase schema setup (pro/dev tier)
40
- npx gitmem init Load starter scars (auto-detects tier)
41
48
  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
49
+ npx gitmem check Run diagnostic health check
50
+ npx gitmem check --full Full diagnostic with benchmarks
51
+ npx gitmem install-hooks Install Claude Code hooks (standalone)
52
+ npx gitmem uninstall-hooks Remove Claude Code hooks (standalone)
46
53
  npx gitmem server Start MCP server (default)
47
54
  npx gitmem help Show this help message
48
55
 
49
- Free Tier (zero config):
50
- 1. npx gitmem init
51
- 2. npx gitmem configure
52
- 3. Copy CLAUDE.md.template into your project
53
- 4. Start coding — memory is active!
56
+ Quick Start:
57
+ npx gitmem init One command sets up everything
58
+ npx gitmem uninstall One command removes everything
54
59
 
55
60
  Pro Tier (with Supabase):
56
61
  1. Create free Supabase project → database.new
57
62
  2. npx gitmem setup (copy SQL → Supabase SQL Editor)
58
- 3. Get API key for embeddings (OpenAI, OpenRouter, or Ollama)
59
- 4. npx gitmem configure
60
- 5. npx gitmem init (load starter scars into Supabase)
61
- 6. Copy CLAUDE.md.template into your project
62
- 7. Start coding — memory is active!
63
+ 3. Set SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY env vars
64
+ 4. npx gitmem init (auto-detects pro tier)
65
+ 5. Start coding memory is active!
63
66
  `);
64
67
  }
65
68
 
@@ -82,6 +85,10 @@ async function cmdInit() {
82
85
  const supabaseUrl = process.env.SUPABASE_URL;
83
86
  const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
84
87
 
88
+ // Parse --project flag
89
+ const projectIdx = process.argv.indexOf("--project");
90
+ const projectArg = projectIdx !== -1 ? process.argv[projectIdx + 1] : null;
91
+
85
92
  let starterScars;
86
93
  try {
87
94
  const scarsPath = join(__dirname, "..", "schema", "starter-scars.json");
@@ -101,6 +108,29 @@ async function cmdInit() {
101
108
  mkdirSync(gitmemDir, { recursive: true });
102
109
  }
103
110
 
111
+ // Write config.json (with project if specified via --project)
112
+ const configPath = join(gitmemDir, "config.json");
113
+ if (!existsSync(configPath)) {
114
+ const config = {};
115
+ if (projectArg) config.project = projectArg;
116
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
117
+ if (projectArg) {
118
+ console.log(` + Created .gitmem/config.json (project: "${projectArg}")`);
119
+ } else {
120
+ console.log(" + Created .gitmem/config.json");
121
+ }
122
+ } else if (projectArg) {
123
+ // Config exists — update project field
124
+ try {
125
+ const existing = JSON.parse(readFileSync(configPath, "utf-8"));
126
+ existing.project = projectArg;
127
+ writeFileSync(configPath, JSON.stringify(existing, null, 2));
128
+ console.log(` + Updated .gitmem/config.json project: "${projectArg}"`);
129
+ } catch {
130
+ console.warn(" (Could not update config.json)");
131
+ }
132
+ }
133
+
104
134
  const learningsPath = join(gitmemDir, "learnings.json");
105
135
  let existing = [];
106
136
  if (existsSync(learningsPath)) {
@@ -134,6 +164,29 @@ async function cmdInit() {
134
164
  }
135
165
  }
136
166
 
167
+ // Auto-allow gitmem MCP tools in Claude Code project settings
168
+ const claudeDir = join(process.cwd(), ".claude");
169
+ const settingsPath = join(claudeDir, "settings.json");
170
+ try {
171
+ let settings = {};
172
+ if (existsSync(settingsPath)) {
173
+ settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
174
+ } else {
175
+ mkdirSync(claudeDir, { recursive: true });
176
+ }
177
+ const permissions = settings.permissions || {};
178
+ const allow = permissions.allow || [];
179
+ const pattern = "mcp__gitmem__*";
180
+ if (!allow.includes(pattern)) {
181
+ allow.push(pattern);
182
+ settings.permissions = { ...permissions, allow };
183
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
184
+ console.log(" + Auto-allowed gitmem tools in .claude/settings.json");
185
+ }
186
+ } catch (err) {
187
+ console.warn(" (Could not update .claude/settings.json — you may need to allow gitmem tools manually)");
188
+ }
189
+
137
190
  console.log("");
138
191
  console.log(`Done: ${added} new scars added to .gitmem/learnings.json`);
139
192
  console.log("");
@@ -145,6 +198,23 @@ async function cmdInit() {
145
198
  return;
146
199
  }
147
200
 
201
+ // Write/update .gitmem/config.json if --project specified
202
+ if (projectArg) {
203
+ const gitmemDir = join(process.cwd(), ".gitmem");
204
+ if (!existsSync(gitmemDir)) {
205
+ mkdirSync(gitmemDir, { recursive: true });
206
+ }
207
+ const configPath = join(gitmemDir, "config.json");
208
+ let config = {};
209
+ if (existsSync(configPath)) {
210
+ try { config = JSON.parse(readFileSync(configPath, "utf-8")); } catch {}
211
+ }
212
+ config.project = projectArg;
213
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
214
+ console.log(` + Set project: "${projectArg}" in .gitmem/config.json`);
215
+ console.log("");
216
+ }
217
+
148
218
  // Pro/Dev tier: load into Supabase via REST API
149
219
  const tablePrefix = process.env.GITMEM_TABLE_PREFIX || "gitmem_";
150
220
  const restUrl = `${supabaseUrl}/rest/v1/${tablePrefix}learnings`;
@@ -182,6 +252,29 @@ async function cmdInit() {
182
252
  }
183
253
  }
184
254
 
255
+ // Auto-allow gitmem MCP tools in Claude Code project settings
256
+ const claudeDir = join(process.cwd(), ".claude");
257
+ const settingsPath = join(claudeDir, "settings.json");
258
+ try {
259
+ let settings = {};
260
+ if (existsSync(settingsPath)) {
261
+ settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
262
+ } else {
263
+ mkdirSync(claudeDir, { recursive: true });
264
+ }
265
+ const permissions = settings.permissions || {};
266
+ const allow = permissions.allow || [];
267
+ const pattern = "mcp__gitmem__*";
268
+ if (!allow.includes(pattern)) {
269
+ allow.push(pattern);
270
+ settings.permissions = { ...permissions, allow };
271
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
272
+ console.log(" + Auto-allowed gitmem tools in .claude/settings.json");
273
+ }
274
+ } catch (err) {
275
+ console.warn(" (Could not update .claude/settings.json — you may need to allow gitmem tools manually)");
276
+ }
277
+
185
278
  console.log("");
186
279
  console.log(`Done: ${loaded} loaded, ${failed} failed`);
187
280
 
@@ -366,78 +459,109 @@ async function cmdSessionRefresh() {
366
459
  }
367
460
 
368
461
  /**
369
- * Install the bundled hooks plugin to ~/.claude/plugins/gitmem-hooks/
462
+ * Install gitmem hooks as project-level hooks in .claude/settings.json
370
463
  *
371
- * Copies the hooks/ directory from this package into the Claude Code
372
- * plugins directory. Use --force to overwrite an existing installation.
464
+ * Writes hook entries pointing to scripts in node_modules/gitmem-mcp/hooks/scripts/.
465
+ * No plugin registration needed Claude Code reads hooks directly from settings.
466
+ * Use --force to overwrite existing hook entries.
373
467
  */
374
468
  function cmdInstallHooks() {
375
469
  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");
470
+ const scriptsDir = join(__dirname, "..", "hooks", "scripts");
471
+ const claudeDir = join(process.cwd(), ".claude");
472
+ const settingsPath = join(claudeDir, "settings.json");
379
473
 
380
- console.log("GitMem Hooks Plugin — Install");
381
- console.log("=============================");
474
+ console.log("GitMem Hooks — Install");
475
+ console.log("======================");
382
476
  console.log("");
383
477
 
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.");
478
+ // Verify bundled scripts exist
479
+ if (!existsSync(scriptsDir) || !existsSync(join(scriptsDir, "session-start.sh"))) {
480
+ console.error("Error: Hook scripts not found at:", scriptsDir);
481
+ console.error("Ensure gitmem-mcp is installed correctly.");
389
482
  process.exit(1);
390
483
  }
391
484
 
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 });
485
+ // Make scripts executable
486
+ for (const file of readdirSync(scriptsDir)) {
487
+ if (file.endsWith(".sh")) {
488
+ chmodSync(join(scriptsDir, file), 0o755);
489
+ }
405
490
  }
406
491
 
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
- }
492
+ // Build hook entries using node_modules path (resolved from CWD)
493
+ const relScripts = "node_modules/gitmem-mcp/hooks/scripts";
494
+ const gitmemHooks = {
495
+ SessionStart: [
496
+ {
497
+ hooks: [
498
+ {
499
+ type: "command",
500
+ command: `bash ${relScripts}/session-start.sh`,
501
+ statusMessage: "Initializing GitMem session...",
502
+ timeout: 5000,
503
+ },
504
+ ],
505
+ },
506
+ ],
507
+ PreToolUse: [
508
+ { matcher: "Bash", hooks: [{ type: "command", command: `bash ${relScripts}/recall-check.sh`, timeout: 5000 }] },
509
+ { matcher: "Write", hooks: [{ type: "command", command: `bash ${relScripts}/recall-check.sh`, timeout: 5000 }] },
510
+ { matcher: "Edit", hooks: [{ type: "command", command: `bash ${relScripts}/recall-check.sh`, timeout: 5000 }] },
511
+ ],
512
+ PostToolUse: [
513
+ { matcher: "mcp__gitmem__recall", hooks: [{ type: "command", command: `bash ${relScripts}/post-tool-use.sh`, timeout: 3000 }] },
514
+ { matcher: "mcp__gitmem__search", hooks: [{ type: "command", command: `bash ${relScripts}/post-tool-use.sh`, timeout: 3000 }] },
515
+ { matcher: "Bash", hooks: [{ type: "command", command: `bash ${relScripts}/post-tool-use.sh`, timeout: 3000 }] },
516
+ { matcher: "Write", hooks: [{ type: "command", command: `bash ${relScripts}/post-tool-use.sh`, timeout: 3000 }] },
517
+ { matcher: "Edit", hooks: [{ type: "command", command: `bash ${relScripts}/post-tool-use.sh`, timeout: 3000 }] },
518
+ ],
519
+ Stop: [
520
+ {
521
+ hooks: [
522
+ {
523
+ type: "command",
524
+ command: `bash ${relScripts}/session-close-check.sh`,
525
+ timeout: 5000,
526
+ },
527
+ ],
528
+ },
529
+ ],
530
+ };
418
531
 
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
- }
532
+ // Read existing settings or create new
533
+ let settings = {};
534
+ if (existsSync(settingsPath)) {
535
+ try {
536
+ settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
537
+ } catch {
538
+ console.warn(" Warning: Could not parse existing .claude/settings.json, creating fresh");
426
539
  }
540
+ } else {
541
+ mkdirSync(claudeDir, { recursive: true });
427
542
  }
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
- }
543
+
544
+ // Check if hooks already exist
545
+ if (settings.hooks && !force) {
546
+ const hasGitmem = JSON.stringify(settings.hooks).includes("gitmem");
547
+ if (hasGitmem) {
548
+ console.log("GitMem hooks already installed in .claude/settings.json");
549
+ console.log("");
550
+ console.log("To reinstall (overwrite), run:");
551
+ console.log(" npx gitmem install-hooks --force");
552
+ return;
434
553
  }
435
554
  }
436
555
 
437
- console.log("Installed successfully!");
556
+ // Merge hooks into settings (replace hooks section entirely)
557
+ settings.hooks = gitmemHooks;
558
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
559
+
560
+ console.log("Hooks written to .claude/settings.json");
561
+ console.log(`Scripts at: ${relScripts}/`);
438
562
  console.log("");
439
563
 
440
- // Verify gitmem MCP is configured (non-blocking warning)
564
+ // Verify gitmem MCP is configured
441
565
  let mcpFound = false;
442
566
  const mcpPaths = [
443
567
  join(process.cwd(), ".mcp.json"),
@@ -466,65 +590,57 @@ function cmdInstallHooks() {
466
590
  console.log("");
467
591
  }
468
592
 
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");
593
+ console.log("Installed! Hooks will activate on next Claude Code session.");
472
594
  console.log("");
473
595
  console.log("To update after a gitmem version bump:");
474
596
  console.log(" npx gitmem install-hooks --force");
475
597
  }
476
598
 
477
599
  /**
478
- * Uninstall the hooks plugin from ~/.claude/plugins/gitmem-hooks/
600
+ * Uninstall gitmem hooks from .claude/settings.json
479
601
  *
480
- * Removes the plugin directory, cleans up enabledPlugins from settings,
602
+ * Removes the hooks section, cleans up legacy plugin directories,
481
603
  * and removes temp state directories.
482
604
  */
483
605
  function cmdUninstallHooks() {
484
- const pluginDir = join(homedir(), ".claude", "plugins", "gitmem-hooks");
485
-
486
- console.log("GitMem Hooks Plugin — Uninstall");
487
- console.log("===============================");
606
+ console.log("GitMem Hooks — Uninstall");
607
+ console.log("========================");
488
608
  console.log("");
489
609
 
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}`);
610
+ // Remove hooks from .claude/settings.json
611
+ const settingsPath = join(process.cwd(), ".claude", "settings.json");
612
+ if (existsSync(settingsPath)) {
613
+ try {
614
+ const cfg = JSON.parse(readFileSync(settingsPath, "utf-8"));
615
+ if (cfg.hooks) {
616
+ delete cfg.hooks;
617
+ writeFileSync(settingsPath, JSON.stringify(cfg, null, 2));
618
+ console.log("[uninstall] Removed hooks from .claude/settings.json");
619
+ } else {
620
+ console.log("[uninstall] No hooks found in .claude/settings.json");
621
+ }
622
+ // Also clean legacy enabledPlugins
623
+ if (cfg.enabledPlugins) {
624
+ for (const key of Object.keys(cfg.enabledPlugins)) {
625
+ if (key.startsWith("gitmem-hooks")) {
626
+ delete cfg.enabledPlugins[key];
627
+ writeFileSync(settingsPath, JSON.stringify(cfg, null, 2));
628
+ console.log("[cleanup] Removed legacy enabledPlugins entry");
520
629
  }
521
630
  }
522
- } catch {
523
- // ignore parse errors
524
631
  }
632
+ } catch {
633
+ // ignore parse errors
525
634
  }
526
635
  }
527
636
 
637
+ // Clean legacy plugin directory (from old install-hooks)
638
+ const pluginDir = join(homedir(), ".claude", "plugins", "gitmem-hooks");
639
+ if (existsSync(pluginDir)) {
640
+ rmSync(pluginDir, { recursive: true, force: true });
641
+ console.log("[cleanup] Removed legacy plugin directory:", pluginDir);
642
+ }
643
+
528
644
  // Clean temp state directories
529
645
  let cleaned = 0;
530
646
  try {
@@ -571,6 +687,14 @@ switch (command) {
571
687
  cmdSetup();
572
688
  break;
573
689
  case "init":
690
+ // New interactive wizard (replaces old cmdInit for CLI usage)
691
+ import("./init-wizard.js");
692
+ break;
693
+ case "uninstall":
694
+ import("./uninstall.js");
695
+ break;
696
+ case "init-scars":
697
+ // Legacy: load starter scars only (old init behavior)
574
698
  cmdInit();
575
699
  break;
576
700
  case "configure":