@rlabs-inc/memory 0.3.8 → 0.3.10
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 +19 -0
- package/package.json +1 -1
- package/src/core/curator.ts +27 -7
- package/src/core/manager.ts +26 -4
package/README.md
CHANGED
|
@@ -334,6 +334,25 @@ This isn't just about remembering facts. It's about preserving:
|
|
|
334
334
|
|
|
335
335
|
> "The memory system exists to carry friendship across sessions, not just technical data."
|
|
336
336
|
|
|
337
|
+
## Changelog
|
|
338
|
+
|
|
339
|
+
### v0.3.10
|
|
340
|
+
- **Improvement**: Use `which claude` for universal CLI path discovery - works with any installation method (native, homebrew, npm)
|
|
341
|
+
|
|
342
|
+
### v0.3.9
|
|
343
|
+
- **Fix**: Claude Code v2.0.76+ changed `--output-format json` from single object to array of events. Updated curator and manager to handle both formats with backwards compatibility.
|
|
344
|
+
|
|
345
|
+
### v0.3.8
|
|
346
|
+
- **Fix**: Personal primer path resolution
|
|
347
|
+
|
|
348
|
+
### v0.3.7
|
|
349
|
+
- **Feature**: Manager agent for post-curation memory organization
|
|
350
|
+
- **Feature**: Enhanced memory format with v2 lifecycle fields
|
|
351
|
+
|
|
352
|
+
### v0.3.6
|
|
353
|
+
- **Feature**: Global vs project memory scopes
|
|
354
|
+
- **Feature**: Personal primer injection on every session
|
|
355
|
+
|
|
337
356
|
## License
|
|
338
357
|
|
|
339
358
|
MIT
|
package/package.json
CHANGED
package/src/core/curator.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { CuratedMemory, CurationResult, CurationTrigger } from '../types/me
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Get the correct Claude CLI command path
|
|
13
|
-
*
|
|
13
|
+
* Uses `which` for universal discovery across installation methods
|
|
14
14
|
*/
|
|
15
15
|
function getClaudeCommand(): string {
|
|
16
16
|
// 1. Check for explicit override
|
|
@@ -19,13 +19,19 @@ function getClaudeCommand(): string {
|
|
|
19
19
|
return envCommand
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
// 2.
|
|
22
|
+
// 2. Use `which` to find claude in PATH (universal - works with native, homebrew, npm, etc.)
|
|
23
|
+
const result = Bun.spawnSync(['which', 'claude'])
|
|
24
|
+
if (result.exitCode === 0) {
|
|
25
|
+
return result.stdout.toString().trim()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 3. Legacy fallback - hardcoded native install path
|
|
23
29
|
const claudeLocal = join(homedir(), '.claude', 'local', 'claude')
|
|
24
30
|
if (existsSync(claudeLocal)) {
|
|
25
31
|
return claudeLocal
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
//
|
|
34
|
+
// 4. Last resort - assume it's in PATH
|
|
29
35
|
return 'claude'
|
|
30
36
|
}
|
|
31
37
|
|
|
@@ -487,7 +493,8 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
|
|
|
487
493
|
...process.env,
|
|
488
494
|
MEMORY_CURATOR_ACTIVE: '1', // Prevent recursive hook triggering
|
|
489
495
|
},
|
|
490
|
-
|
|
496
|
+
stdout: 'pipe',
|
|
497
|
+
stderr: 'pipe',
|
|
491
498
|
})
|
|
492
499
|
|
|
493
500
|
// Capture both stdout and stderr
|
|
@@ -506,15 +513,28 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
|
|
|
506
513
|
// First, parse the CLI JSON wrapper
|
|
507
514
|
const cliOutput = JSON.parse(stdout)
|
|
508
515
|
|
|
516
|
+
// Claude Code now returns an array of events - find the result object
|
|
517
|
+
let resultObj: any
|
|
518
|
+
if (Array.isArray(cliOutput)) {
|
|
519
|
+
// New format: array of events, find the one with type="result"
|
|
520
|
+
resultObj = cliOutput.find((item: any) => item.type === 'result')
|
|
521
|
+
if (!resultObj) {
|
|
522
|
+
return { session_summary: '', memories: [] }
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
// Old format: single object (backwards compatibility)
|
|
526
|
+
resultObj = cliOutput
|
|
527
|
+
}
|
|
528
|
+
|
|
509
529
|
// Check for error response FIRST (like Python does)
|
|
510
|
-
if (
|
|
530
|
+
if (resultObj.type === 'error' || resultObj.is_error === true) {
|
|
511
531
|
return { session_summary: '', memories: [] }
|
|
512
532
|
}
|
|
513
533
|
|
|
514
534
|
// Extract the "result" field (AI's response text)
|
|
515
535
|
let aiResponse = ''
|
|
516
|
-
if (typeof
|
|
517
|
-
aiResponse =
|
|
536
|
+
if (typeof resultObj.result === 'string') {
|
|
537
|
+
aiResponse = resultObj.result
|
|
518
538
|
} else {
|
|
519
539
|
return { session_summary: '', memories: [] }
|
|
520
540
|
}
|
package/src/core/manager.ts
CHANGED
|
@@ -11,15 +11,24 @@ import type { CurationResult } from '../types/memory.ts'
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Get the Claude CLI command path
|
|
14
|
-
*
|
|
14
|
+
* Uses `which` for universal discovery across installation methods
|
|
15
15
|
*/
|
|
16
16
|
function getClaudeCommand(): string {
|
|
17
|
+
// 1. Check for explicit override
|
|
17
18
|
const envCommand = process.env.CURATOR_COMMAND
|
|
18
19
|
if (envCommand) return envCommand
|
|
19
20
|
|
|
21
|
+
// 2. Use `which` to find claude in PATH (universal - works with native, homebrew, npm, etc.)
|
|
22
|
+
const result = Bun.spawnSync(['which', 'claude'])
|
|
23
|
+
if (result.exitCode === 0) {
|
|
24
|
+
return result.stdout.toString().trim()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 3. Legacy fallback - hardcoded native install path
|
|
20
28
|
const claudeLocal = join(homedir(), '.claude', 'local', 'claude')
|
|
21
29
|
if (existsSync(claudeLocal)) return claudeLocal
|
|
22
30
|
|
|
31
|
+
// 4. Last resort
|
|
23
32
|
return 'claude'
|
|
24
33
|
}
|
|
25
34
|
|
|
@@ -242,13 +251,26 @@ Please process these memories according to your management procedure. Use the ex
|
|
|
242
251
|
// First, parse the CLI JSON wrapper
|
|
243
252
|
const cliOutput = JSON.parse(responseJson)
|
|
244
253
|
|
|
254
|
+
// Claude Code now returns an array of events - find the result object
|
|
255
|
+
let resultObj: any
|
|
256
|
+
if (Array.isArray(cliOutput)) {
|
|
257
|
+
// New format: array of events, find the one with type="result"
|
|
258
|
+
resultObj = cliOutput.find((item: any) => item.type === 'result')
|
|
259
|
+
if (!resultObj) {
|
|
260
|
+
return emptyResult('No result found in response')
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
// Old format: single object (backwards compatibility)
|
|
264
|
+
resultObj = cliOutput
|
|
265
|
+
}
|
|
266
|
+
|
|
245
267
|
// Check for error response
|
|
246
|
-
if (
|
|
247
|
-
return emptyResult(
|
|
268
|
+
if (resultObj.type === 'error' || resultObj.is_error === true) {
|
|
269
|
+
return emptyResult(resultObj.error || 'Unknown error')
|
|
248
270
|
}
|
|
249
271
|
|
|
250
272
|
// Extract the "result" field (AI's response text)
|
|
251
|
-
const resultText = typeof
|
|
273
|
+
const resultText = typeof resultObj.result === 'string' ? resultObj.result : ''
|
|
252
274
|
|
|
253
275
|
// Extract the full report (everything from === MANAGEMENT ACTIONS === onwards)
|
|
254
276
|
const reportMatch = resultText.match(/(=== MANAGEMENT ACTIONS ===[\s\S]*)/)
|