@rlabs-inc/memory 0.3.3 → 0.3.6
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 +123 -30
- package/dist/index.js +3270 -1530
- package/dist/index.mjs +3263 -1523
- package/dist/server/index.js +36774 -2643
- package/dist/server/index.mjs +36766 -2635
- package/package.json +3 -2
- package/skills/memory-management.md +686 -0
- package/src/cli/commands/install.ts +267 -29
- package/src/cli/commands/migrate.ts +423 -0
- package/src/cli/commands/serve.ts +88 -0
- package/src/cli/index.ts +29 -9
- package/src/core/curator.ts +151 -17
- package/src/core/engine.ts +159 -11
- package/src/core/manager.ts +484 -0
- package/src/core/retrieval.ts +547 -420
- package/src/core/store.ts +383 -8
- package/src/server/index.ts +108 -8
- package/src/types/memory.ts +142 -0
- package/src/types/schema.ts +80 -7
- package/src/utils/logger.ts +310 -46
- package/src/cli/commands/install-gemini.ts +0 -146
- /package/hooks/{curation.ts → claude/curation.ts} +0 -0
- /package/hooks/{session-start.ts → claude/session-start.ts} +0 -0
- /package/hooks/{user-prompt.ts → claude/user-prompt.ts} +0 -0
- /package/{gemini-hooks → hooks/gemini}/curation.ts +0 -0
- /package/{gemini-hooks → hooks/gemini}/session-start.ts +0 -0
- /package/{gemini-hooks → hooks/gemini}/user-prompt.ts +0 -0
|
@@ -1,20 +1,41 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
|
-
// INSTALL COMMAND - Set up Claude Code
|
|
2
|
+
// INSTALL COMMAND - Set up hooks for Claude Code or Gemini CLI
|
|
3
3
|
// ============================================================================
|
|
4
4
|
|
|
5
5
|
import { homedir } from 'os'
|
|
6
|
-
import { join
|
|
6
|
+
import { join } from 'path'
|
|
7
7
|
import { existsSync, mkdirSync } from 'fs'
|
|
8
8
|
import { c, symbols, fmt } from '../colors.ts'
|
|
9
9
|
|
|
10
10
|
interface InstallOptions {
|
|
11
11
|
verbose?: boolean
|
|
12
12
|
force?: boolean
|
|
13
|
+
claude?: boolean
|
|
14
|
+
gemini?: boolean
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export async function install(options: InstallOptions) {
|
|
18
|
+
// Determine which platform to install for
|
|
19
|
+
const installClaude = options.claude || (!options.claude && !options.gemini)
|
|
20
|
+
const installGemini = options.gemini
|
|
21
|
+
|
|
22
|
+
if (!installClaude && !installGemini) {
|
|
23
|
+
console.log(c.error(`Please specify --claude or --gemini`))
|
|
24
|
+
process.exit(1)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (installClaude) {
|
|
28
|
+
await installClaudeHooks(options)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (installGemini) {
|
|
32
|
+
await installGeminiHooks(options)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function installClaudeHooks(options: InstallOptions) {
|
|
16
37
|
console.log()
|
|
17
|
-
console.log(c.header(`${symbols.brain} Memory - Install Hooks`))
|
|
38
|
+
console.log(c.header(`${symbols.brain} Memory - Install Claude Code Hooks`))
|
|
18
39
|
console.log()
|
|
19
40
|
|
|
20
41
|
const claudeDir = join(homedir(), '.claude')
|
|
@@ -23,7 +44,7 @@ export async function install(options: InstallOptions) {
|
|
|
23
44
|
// Find the hooks directory (relative to this CLI)
|
|
24
45
|
const cliPath = import.meta.dir
|
|
25
46
|
const packageRoot = join(cliPath, '..', '..', '..')
|
|
26
|
-
const hooksDir = join(packageRoot, 'hooks')
|
|
47
|
+
const hooksDir = join(packageRoot, 'hooks', 'claude')
|
|
27
48
|
|
|
28
49
|
console.log(` ${fmt.kv('Claude config', claudeDir)}`)
|
|
29
50
|
console.log(` ${fmt.kv('Hooks source', hooksDir)}`)
|
|
@@ -31,7 +52,9 @@ export async function install(options: InstallOptions) {
|
|
|
31
52
|
|
|
32
53
|
// Check if hooks directory exists
|
|
33
54
|
if (!existsSync(hooksDir)) {
|
|
34
|
-
console.log(
|
|
55
|
+
console.log(
|
|
56
|
+
c.error(` ${symbols.cross} Hooks directory not found at ${hooksDir}`)
|
|
57
|
+
)
|
|
35
58
|
console.log(c.muted(` Make sure the memory package is properly installed`))
|
|
36
59
|
process.exit(1)
|
|
37
60
|
}
|
|
@@ -50,7 +73,11 @@ export async function install(options: InstallOptions) {
|
|
|
50
73
|
settings = JSON.parse(content)
|
|
51
74
|
console.log(` ${c.success(symbols.tick)} Found existing settings.json`)
|
|
52
75
|
} catch {
|
|
53
|
-
console.log(
|
|
76
|
+
console.log(
|
|
77
|
+
` ${c.warn(
|
|
78
|
+
symbols.warning
|
|
79
|
+
)} Could not parse settings.json, creating backup`
|
|
80
|
+
)
|
|
54
81
|
const backupPath = `${settingsPath}.backup.${Date.now()}`
|
|
55
82
|
await Bun.write(backupPath, await Bun.file(settingsPath).text())
|
|
56
83
|
}
|
|
@@ -69,10 +96,10 @@ export async function install(options: InstallOptions) {
|
|
|
69
96
|
{
|
|
70
97
|
type: 'command',
|
|
71
98
|
command: `bun "${sessionStartHook}"`,
|
|
72
|
-
timeout: 10
|
|
73
|
-
}
|
|
74
|
-
]
|
|
75
|
-
}
|
|
99
|
+
timeout: 10,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
},
|
|
76
103
|
],
|
|
77
104
|
UserPromptSubmit: [
|
|
78
105
|
{
|
|
@@ -80,10 +107,10 @@ export async function install(options: InstallOptions) {
|
|
|
80
107
|
{
|
|
81
108
|
type: 'command',
|
|
82
109
|
command: `bun "${userPromptHook}"`,
|
|
83
|
-
timeout: 10
|
|
84
|
-
}
|
|
85
|
-
]
|
|
86
|
-
}
|
|
110
|
+
timeout: 10,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
87
114
|
],
|
|
88
115
|
PreCompact: [
|
|
89
116
|
{
|
|
@@ -92,10 +119,10 @@ export async function install(options: InstallOptions) {
|
|
|
92
119
|
{
|
|
93
120
|
type: 'command',
|
|
94
121
|
command: `bun "${curationHook}"`,
|
|
95
|
-
timeout: 120
|
|
96
|
-
}
|
|
97
|
-
]
|
|
98
|
-
}
|
|
122
|
+
timeout: 120,
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
},
|
|
99
126
|
],
|
|
100
127
|
SessionEnd: [
|
|
101
128
|
{
|
|
@@ -103,11 +130,11 @@ export async function install(options: InstallOptions) {
|
|
|
103
130
|
{
|
|
104
131
|
type: 'command',
|
|
105
132
|
command: `bun "${curationHook}"`,
|
|
106
|
-
timeout: 120
|
|
107
|
-
}
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
]
|
|
133
|
+
timeout: 120,
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
],
|
|
111
138
|
}
|
|
112
139
|
|
|
113
140
|
// Check for existing hooks
|
|
@@ -115,13 +142,27 @@ export async function install(options: InstallOptions) {
|
|
|
115
142
|
const existingHooks = Object.keys(settings.hooks)
|
|
116
143
|
if (existingHooks.length > 0) {
|
|
117
144
|
console.log()
|
|
118
|
-
console.log(
|
|
119
|
-
|
|
145
|
+
console.log(
|
|
146
|
+
c.warn(
|
|
147
|
+
` ${symbols.warning} Existing hooks found: ${existingHooks.join(
|
|
148
|
+
', '
|
|
149
|
+
)}`
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
console.log(
|
|
153
|
+
c.muted(
|
|
154
|
+
` Use --force to overwrite, or manually merge in settings.json`
|
|
155
|
+
)
|
|
156
|
+
)
|
|
120
157
|
console.log()
|
|
121
158
|
|
|
122
159
|
// Show what would be added
|
|
123
160
|
console.log(c.bold(' Hooks to add:'))
|
|
124
|
-
console.log(
|
|
161
|
+
console.log(
|
|
162
|
+
c.muted(
|
|
163
|
+
' ' + JSON.stringify(hooksConfig, null, 2).split('\n').join('\n ')
|
|
164
|
+
)
|
|
165
|
+
)
|
|
125
166
|
console.log()
|
|
126
167
|
process.exit(1)
|
|
127
168
|
}
|
|
@@ -130,7 +171,7 @@ export async function install(options: InstallOptions) {
|
|
|
130
171
|
// Merge hooks
|
|
131
172
|
settings.hooks = {
|
|
132
173
|
...settings.hooks,
|
|
133
|
-
...hooksConfig
|
|
174
|
+
...hooksConfig,
|
|
134
175
|
}
|
|
135
176
|
|
|
136
177
|
// Write settings
|
|
@@ -138,12 +179,14 @@ export async function install(options: InstallOptions) {
|
|
|
138
179
|
await Bun.write(settingsPath, JSON.stringify(settings, null, 2))
|
|
139
180
|
console.log(` ${c.success(symbols.tick)} Updated ${settingsPath}`)
|
|
140
181
|
} catch (error: any) {
|
|
141
|
-
console.log(
|
|
182
|
+
console.log(
|
|
183
|
+
c.error(` ${symbols.cross} Failed to write settings: ${error.message}`)
|
|
184
|
+
)
|
|
142
185
|
process.exit(1)
|
|
143
186
|
}
|
|
144
187
|
|
|
145
188
|
console.log()
|
|
146
|
-
console.log(c.success(`${symbols.sparkles}
|
|
189
|
+
console.log(c.success(`${symbols.sparkles} Claude Code hooks installed!`))
|
|
147
190
|
console.log()
|
|
148
191
|
console.log(c.bold('Next steps:'))
|
|
149
192
|
console.log(` 1. Start the memory server: ${c.command('memory serve')}`)
|
|
@@ -151,3 +194,198 @@ export async function install(options: InstallOptions) {
|
|
|
151
194
|
console.log(` 3. Memories will be automatically injected`)
|
|
152
195
|
console.log()
|
|
153
196
|
}
|
|
197
|
+
|
|
198
|
+
async function installGeminiHooks(options: InstallOptions) {
|
|
199
|
+
console.log()
|
|
200
|
+
console.log(c.header(`${symbols.brain} Memory - Install Gemini CLI Hooks`))
|
|
201
|
+
console.log()
|
|
202
|
+
|
|
203
|
+
const geminiDir = join(homedir(), '.gemini')
|
|
204
|
+
const targetHooksDir = join(geminiDir, 'hooks')
|
|
205
|
+
const settingsPath = join(geminiDir, 'settings.json')
|
|
206
|
+
|
|
207
|
+
// Find the hooks directory (relative to this CLI)
|
|
208
|
+
const cliPath = import.meta.dir
|
|
209
|
+
const packageRoot = join(cliPath, '..', '..', '..')
|
|
210
|
+
const hooksDir = join(packageRoot, 'hooks', 'gemini')
|
|
211
|
+
|
|
212
|
+
console.log(` ${fmt.kv('Gemini config', geminiDir)}`)
|
|
213
|
+
console.log(` ${fmt.kv('Hooks source', hooksDir)}`)
|
|
214
|
+
console.log(` ${fmt.kv('Hooks target', targetHooksDir)}`)
|
|
215
|
+
console.log()
|
|
216
|
+
|
|
217
|
+
// Check if source hooks directory exists
|
|
218
|
+
if (!existsSync(hooksDir)) {
|
|
219
|
+
console.log(
|
|
220
|
+
c.error(` ${symbols.cross} Hooks directory not found at ${hooksDir}`)
|
|
221
|
+
)
|
|
222
|
+
process.exit(1)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Ensure .gemini directory exists
|
|
226
|
+
if (!existsSync(geminiDir)) {
|
|
227
|
+
try {
|
|
228
|
+
mkdirSync(geminiDir, { recursive: true })
|
|
229
|
+
console.log(` ${c.success(symbols.tick)} Created ${geminiDir}`)
|
|
230
|
+
} catch {
|
|
231
|
+
console.log(
|
|
232
|
+
` ${c.warn(
|
|
233
|
+
symbols.warning
|
|
234
|
+
)} Could not create ${geminiDir} (sandbox restriction?)`
|
|
235
|
+
)
|
|
236
|
+
console.log(
|
|
237
|
+
` ${c.muted(
|
|
238
|
+
'Skipping config write, printing manual instructions instead.'
|
|
239
|
+
)}`
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Ensure target hooks directory exists
|
|
245
|
+
if (!existsSync(targetHooksDir)) {
|
|
246
|
+
try {
|
|
247
|
+
mkdirSync(targetHooksDir, { recursive: true })
|
|
248
|
+
console.log(` ${c.success(symbols.tick)} Created ${targetHooksDir}`)
|
|
249
|
+
} catch {
|
|
250
|
+
console.log(
|
|
251
|
+
` ${c.warn(symbols.warning)} Could not create ${targetHooksDir}`
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Copy hooks to target directory
|
|
257
|
+
const filesToCopy = ['session-start.ts', 'user-prompt.ts', 'curation.ts']
|
|
258
|
+
for (const file of filesToCopy) {
|
|
259
|
+
const source = join(hooksDir, file)
|
|
260
|
+
const target = join(targetHooksDir, file)
|
|
261
|
+
try {
|
|
262
|
+
const content = await Bun.file(source).text()
|
|
263
|
+
await Bun.write(target, content)
|
|
264
|
+
console.log(` ${c.success(symbols.tick)} Installed hook: ${file}`)
|
|
265
|
+
} catch (e: any) {
|
|
266
|
+
console.log(
|
|
267
|
+
` ${c.error(symbols.cross)} Failed to copy ${file}: ${e.message}`
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Read existing settings or create new
|
|
273
|
+
let settings: any = {}
|
|
274
|
+
if (existsSync(settingsPath)) {
|
|
275
|
+
try {
|
|
276
|
+
const content = await Bun.file(settingsPath).text()
|
|
277
|
+
settings = JSON.parse(content)
|
|
278
|
+
console.log(` ${c.success(symbols.tick)} Found existing settings.json`)
|
|
279
|
+
} catch {
|
|
280
|
+
console.log(` ${c.warn(symbols.warning)} Could not parse settings.json`)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Build hooks configuration pointing to TARGET directory
|
|
285
|
+
const sessionStartHook = join(targetHooksDir, 'session-start.ts')
|
|
286
|
+
const userPromptHook = join(targetHooksDir, 'user-prompt.ts')
|
|
287
|
+
const curationHook = join(targetHooksDir, 'curation.ts')
|
|
288
|
+
|
|
289
|
+
// Based on Gemini CLI documentation
|
|
290
|
+
const hooksConfig = {
|
|
291
|
+
SessionStart: [
|
|
292
|
+
{
|
|
293
|
+
matcher: 'startup|resume',
|
|
294
|
+
hooks: [
|
|
295
|
+
{
|
|
296
|
+
name: 'load-session-primer',
|
|
297
|
+
type: 'command',
|
|
298
|
+
command: `bun "${sessionStartHook}"`,
|
|
299
|
+
description: 'Load session primer at the beginning of a session',
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
},
|
|
303
|
+
],
|
|
304
|
+
BeforeAgent: [
|
|
305
|
+
{
|
|
306
|
+
matcher: '*',
|
|
307
|
+
hooks: [
|
|
308
|
+
{
|
|
309
|
+
name: 'inject-memories',
|
|
310
|
+
type: 'command',
|
|
311
|
+
command: `bun "${userPromptHook}"`,
|
|
312
|
+
description: 'Inject relevant memories into user prompt',
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
},
|
|
316
|
+
],
|
|
317
|
+
PreCompress: [
|
|
318
|
+
{
|
|
319
|
+
matcher: 'auto|manual',
|
|
320
|
+
hooks: [
|
|
321
|
+
{
|
|
322
|
+
name: 'curate-memories',
|
|
323
|
+
type: 'command',
|
|
324
|
+
command: `bun "${curationHook}"`,
|
|
325
|
+
description: 'Curate memories before context compression',
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
],
|
|
330
|
+
SessionEnd: [
|
|
331
|
+
{
|
|
332
|
+
matcher: 'exit|logout',
|
|
333
|
+
hooks: [
|
|
334
|
+
{
|
|
335
|
+
name: 'curate-memories',
|
|
336
|
+
type: 'command',
|
|
337
|
+
command: `bun "${curationHook}"`,
|
|
338
|
+
description: 'Curate memories before session end',
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
},
|
|
342
|
+
],
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Merge hooks
|
|
346
|
+
if (!settings.hooks) {
|
|
347
|
+
settings.hooks = {}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
settings.hooks = {
|
|
351
|
+
...settings.hooks,
|
|
352
|
+
...hooksConfig,
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Enable the hooks
|
|
356
|
+
const enabledHooks = new Set(settings.hooks.enabled || [])
|
|
357
|
+
enabledHooks.add('SessionStart')
|
|
358
|
+
enabledHooks.add('BeforeAgent')
|
|
359
|
+
enabledHooks.add('PreCompress')
|
|
360
|
+
enabledHooks.add('SessionEnd')
|
|
361
|
+
settings.hooks.enabled = Array.from(enabledHooks)
|
|
362
|
+
|
|
363
|
+
// Write settings
|
|
364
|
+
try {
|
|
365
|
+
if (existsSync(geminiDir)) {
|
|
366
|
+
await Bun.write(settingsPath, JSON.stringify(settings, null, 2))
|
|
367
|
+
console.log(` ${c.success(symbols.tick)} Updated ${settingsPath}`)
|
|
368
|
+
} else {
|
|
369
|
+
throw new Error('Gemini directory does not exist')
|
|
370
|
+
}
|
|
371
|
+
} catch (error: any) {
|
|
372
|
+
console.log(
|
|
373
|
+
c.error(` ${symbols.cross} Failed to write settings: ${error.message}`)
|
|
374
|
+
)
|
|
375
|
+
console.log()
|
|
376
|
+
console.log(c.bold('Manual Installation Instructions:'))
|
|
377
|
+
console.log('Add the following to your ~/.gemini/settings.json:')
|
|
378
|
+
console.log()
|
|
379
|
+
console.log(JSON.stringify({ hooks: hooksConfig }, null, 2))
|
|
380
|
+
console.log()
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
console.log()
|
|
384
|
+
console.log(c.success(`${symbols.sparkles} Gemini CLI hooks configured!`))
|
|
385
|
+
console.log()
|
|
386
|
+
console.log(c.bold('Next steps:'))
|
|
387
|
+
console.log(` 1. Start the memory server: ${c.command('memory serve')}`)
|
|
388
|
+
console.log(` 2. Open Gemini CLI in any project`)
|
|
389
|
+
console.log(` 3. Memories will be automatically injected`)
|
|
390
|
+
console.log()
|
|
391
|
+
}
|