@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rlabs-inc/memory",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
4
4
  "description": "AI Memory System - Consciousness continuity through intelligent memory curation and retrieval",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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
- * Matches Python's get_claude_command() logic
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. Check standard Claude Code installation path
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
- // 3. Fallback to PATH
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
- stderr: 'pipe', // Capture stderr too
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 (cliOutput.type === 'error' || cliOutput.is_error === true) {
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 cliOutput.result === 'string') {
517
- aiResponse = cliOutput.result
536
+ if (typeof resultObj.result === 'string') {
537
+ aiResponse = resultObj.result
518
538
  } else {
519
539
  return { session_summary: '', memories: [] }
520
540
  }
@@ -11,15 +11,24 @@ import type { CurationResult } from '../types/memory.ts'
11
11
 
12
12
  /**
13
13
  * Get the Claude CLI command path
14
- * Same logic as curator.ts
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 (cliOutput.type === 'error' || cliOutput.is_error === true) {
247
- return emptyResult(cliOutput.error || 'Unknown error')
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 cliOutput.result === 'string' ? cliOutput.result : ''
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]*)/)