hippo-memory 0.11.2 → 0.13.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.
Files changed (43) hide show
  1. package/README.md +9 -0
  2. package/dist/autolearn.d.ts.map +1 -1
  3. package/dist/autolearn.js +3 -1
  4. package/dist/autolearn.js.map +1 -1
  5. package/dist/cli.js +11 -6
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +4 -1
  9. package/dist/config.js.map +1 -1
  10. package/dist/embeddings.d.ts.map +1 -1
  11. package/dist/embeddings.js +45 -22
  12. package/dist/embeddings.js.map +1 -1
  13. package/dist/importers.d.ts.map +1 -1
  14. package/dist/importers.js +5 -1
  15. package/dist/importers.js.map +1 -1
  16. package/dist/mcp/server.js +18 -14
  17. package/dist/mcp/server.js.map +1 -1
  18. package/dist/memory.d.ts +1 -1
  19. package/dist/memory.d.ts.map +1 -1
  20. package/dist/memory.js +9 -5
  21. package/dist/memory.js.map +1 -1
  22. package/dist/physics-state.d.ts +1 -1
  23. package/dist/physics-state.d.ts.map +1 -1
  24. package/dist/physics-state.js +5 -2
  25. package/dist/physics-state.js.map +1 -1
  26. package/dist/physics.d.ts.map +1 -1
  27. package/dist/physics.js +16 -4
  28. package/dist/physics.js.map +1 -1
  29. package/dist/search.d.ts.map +1 -1
  30. package/dist/search.js +18 -15
  31. package/dist/search.js.map +1 -1
  32. package/dist/shared.d.ts +4 -2
  33. package/dist/shared.d.ts.map +1 -1
  34. package/dist/shared.js +16 -8
  35. package/dist/shared.js.map +1 -1
  36. package/dist/store.d.ts.map +1 -1
  37. package/dist/store.js +24 -6
  38. package/dist/store.js.map +1 -1
  39. package/extensions/openclaw-plugin/index.ts +39 -33
  40. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  41. package/extensions/openclaw-plugin/package.json +1 -1
  42. package/openclaw.plugin.json +1 -1
  43. package/package.json +1 -1
@@ -7,7 +7,7 @@
7
7
  * Config lives under plugins.entries.hippo-memory.config
8
8
  */
9
9
 
10
- import { execSync } from 'child_process';
10
+ import { execFileSync } from 'child_process';
11
11
  import { existsSync } from 'fs';
12
12
  import { join } from 'path';
13
13
  import { basename as posixBasename, dirname as posixDirname } from 'path/posix';
@@ -77,10 +77,13 @@ function getConfig(api: any): HippoConfig {
77
77
  function findHippoRoot(workspace?: string, configRoot?: string): string | null {
78
78
  if (configRoot && existsSync(configRoot)) return configRoot;
79
79
 
80
+ const home = process.env.USERPROFILE || process.env.HOME || '';
80
81
  const candidates = [
81
82
  workspace ? join(workspace, '.hippo') : null,
83
+ process.env.HIPPO_HOME,
82
84
  process.env.HIPPO_ROOT,
83
- join(process.env.USERPROFILE || process.env.HOME || '', '.hippo'),
85
+ process.env.XDG_DATA_HOME ? join(process.env.XDG_DATA_HOME, 'hippo') : null,
86
+ home ? join(home, '.hippo') : null,
84
87
  ].filter(Boolean) as string[];
85
88
 
86
89
  for (const candidate of candidates) {
@@ -164,15 +167,15 @@ function hippoRememberSucceeded(result: string): boolean {
164
167
  return result.includes('Remembered [');
165
168
  }
166
169
 
167
- function runHippo(args: string, cwd?: string): string {
170
+ function runHippo(args: readonly string[], cwd?: string): string {
168
171
  try {
169
- const result = execSync(`hippo ${args}`, {
172
+ const result = execFileSync('hippo', args, {
170
173
  cwd: cwd || process.cwd(),
171
- timeout: 30000,
172
- encoding: 'utf-8',
174
+ encoding: 'utf8',
175
+ timeout: 30_000,
173
176
  stdio: ['pipe', 'pipe', 'pipe'],
174
177
  });
175
- return result.trim();
178
+ return typeof result === 'string' ? result.trim() : '';
176
179
  } catch (err: any) {
177
180
  return err.stdout?.trim() || err.message || 'hippo command failed';
178
181
  }
@@ -206,7 +209,7 @@ export default function register(api: any) {
206
209
  const framing = cfg.framing ?? 'observe';
207
210
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
208
211
  const result = runHippo(
209
- `recall "${params.query.replace(/"/g, '\\"')}" --budget ${budget} --framing ${framing}`,
212
+ ['recall', params.query, '--budget', String(budget), '--framing', framing],
210
213
  hippoCwd,
211
214
  );
212
215
  return { content: [{ type: 'text', text: result || 'No relevant memories found.' }] };
@@ -246,10 +249,13 @@ export default function register(api: any) {
246
249
  ) {
247
250
  const cfg = getConfig(api);
248
251
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
249
- let args = `remember "${params.text.replace(/"/g, '\\"')}"`;
250
- if (params.error) args += ' --error';
251
- if (params.pin) args += ' --pin';
252
- if (params.tag) args += ` --tag ${params.tag}`;
252
+ const args: string[] = ['remember', params.text];
253
+ if (params.error) args.push('--error');
254
+ if (params.pin) args.push('--pin');
255
+ if (params.tag) {
256
+ const safe = sanitizeTag(params.tag);
257
+ if (safe) args.push('--tag', safe);
258
+ }
253
259
  const result = runHippo(args, hippoCwd);
254
260
  if (hippoRememberSucceeded(result)) {
255
261
  recordSessionMemory(ctx);
@@ -277,7 +283,7 @@ export default function register(api: any) {
277
283
  const cfg = getConfig(api);
278
284
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
279
285
  const flag = params.good ? '--good' : '--bad';
280
- const result = runHippo(`outcome ${flag}`, hippoCwd);
286
+ const result = runHippo(['outcome', flag], hippoCwd);
281
287
  return { content: [{ type: 'text', text: result || 'Outcome recorded.' }] };
282
288
  },
283
289
  }));
@@ -295,7 +301,7 @@ export default function register(api: any) {
295
301
  async execute() {
296
302
  const cfg = getConfig(api);
297
303
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
298
- const result = runHippo('status', hippoCwd);
304
+ const result = runHippo(['status'], hippoCwd);
299
305
  return { content: [{ type: 'text', text: result || 'No hippo store found.' }] };
300
306
  },
301
307
  }),
@@ -323,7 +329,7 @@ export default function register(api: any) {
323
329
  const framing = cfg.framing ?? 'observe';
324
330
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
325
331
  const result = runHippo(
326
- `context --auto --budget ${budget} --framing ${framing}`,
332
+ ['context', '--auto', '--budget', String(budget), '--framing', framing],
327
333
  hippoCwd,
328
334
  );
329
335
  return { content: [{ type: 'text', text: result || 'No context available.' }] };
@@ -350,7 +356,7 @@ export default function register(api: any) {
350
356
  async execute(_id: string, params: { json?: boolean }) {
351
357
  const cfg = getConfig(api);
352
358
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
353
- const args = params.json ? 'conflicts --json' : 'conflicts';
359
+ const args: string[] = params.json ? ['conflicts', '--json'] : ['conflicts'];
354
360
  const result = runHippo(args, hippoCwd);
355
361
  return { content: [{ type: 'text', text: result || 'No conflicts found.' }] };
356
362
  },
@@ -388,8 +394,8 @@ export default function register(api: any) {
388
394
  ) {
389
395
  const cfg = getConfig(api);
390
396
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
391
- let args = `resolve ${params.conflict_id} --keep ${params.keep}`;
392
- if (params.forget) args += ' --forget';
397
+ const args: string[] = ['resolve', String(params.conflict_id), '--keep', params.keep];
398
+ if (params.forget) args.push('--forget');
393
399
  const result = runHippo(args, hippoCwd);
394
400
  return { content: [{ type: 'text', text: result || 'Conflict resolved.' }] };
395
401
  },
@@ -423,12 +429,12 @@ export default function register(api: any) {
423
429
  ) {
424
430
  const cfg = getConfig(api);
425
431
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
426
- let args: string;
432
+ const args: string[] = ['share'];
427
433
  if (params.id === 'auto') {
428
- args = 'share --auto';
434
+ args.push('--auto');
429
435
  } else {
430
- args = `share ${params.id}`;
431
- if (params.force) args += ' --force';
436
+ args.push(params.id);
437
+ if (params.force) args.push('--force');
432
438
  }
433
439
  const result = runHippo(args, hippoCwd);
434
440
  return { content: [{ type: 'text', text: result || 'Share complete.' }] };
@@ -450,7 +456,7 @@ export default function register(api: any) {
450
456
  async execute() {
451
457
  const cfg = getConfig(api);
452
458
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
453
- const result = runHippo('peers', hippoCwd);
459
+ const result = runHippo(['peers'], hippoCwd);
454
460
  return { content: [{ type: 'text', text: result || 'No peers found.' }] };
455
461
  },
456
462
  }),
@@ -489,9 +495,8 @@ export default function register(api: any) {
489
495
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
490
496
  const scope = params.scope ?? 'repo';
491
497
  const importance = params.importance ?? 0.5;
492
- const escapedContent = params.content.replace(/"/g, '\\"');
493
498
  const result = runHippo(
494
- `wm push --scope ${scope} --content "${escapedContent}" --importance ${importance}`,
499
+ ['wm', 'push', '--scope', scope, '--content', params.content, '--importance', String(importance)],
495
500
  hippoCwd,
496
501
  );
497
502
  return { content: [{ type: 'text', text: result || 'Working memory entry pushed.' }] };
@@ -521,7 +526,7 @@ export default function register(api: any) {
521
526
  // Record session_start event
522
527
  try {
523
528
  runHippo(
524
- `session log --id "${sessionKey}" --type session_start --content "Session started" --source openclaw`,
529
+ ['session', 'log', '--id', sessionKey, '--type', 'session_start', '--content', 'Session started', '--source', 'openclaw'],
525
530
  hippoCwd,
526
531
  );
527
532
  } catch (err) {
@@ -530,7 +535,7 @@ export default function register(api: any) {
530
535
 
531
536
  try {
532
537
  const context = runHippo(
533
- `context --auto --budget ${budget} --framing ${framing}`,
538
+ ['context', '--auto', '--budget', String(budget), '--framing', framing],
534
539
  hippoCwd,
535
540
  );
536
541
  if (context && context.length > 10 && !context.includes('No hippo store')) {
@@ -580,10 +585,11 @@ export default function register(api: any) {
580
585
 
581
586
  const hippoCwd = resolveHippoCwdFromContext(api, ctx, cfg.root);
582
587
  const toolTag = sanitizeTag(event.toolName);
583
- let args =
584
- `remember "${formatToolErrorMemory(event.toolName, event.error).replace(/"/g, '\\"')}"` +
585
- ' --error --observed --tag openclaw';
586
- if (toolTag) args += ` --tag ${toolTag}`;
588
+ const args: string[] = [
589
+ 'remember', formatToolErrorMemory(event.toolName, event.error),
590
+ '--error', '--observed', '--tag', 'openclaw',
591
+ ];
592
+ if (toolTag) args.push('--tag', toolTag);
587
593
 
588
594
  const result = runHippo(args, hippoCwd);
589
595
  if (hippoRememberSucceeded(result)) {
@@ -612,7 +618,7 @@ export default function register(api: any) {
612
618
  // Record session_end event
613
619
  try {
614
620
  runHippo(
615
- `session log --id "${sessionKey}" --type session_end --content "Session ended" --source openclaw`,
621
+ ['session', 'log', '--id', sessionKey, '--type', 'session_end', '--content', 'Session ended', '--source', 'openclaw'],
616
622
  hippoCwd,
617
623
  );
618
624
  } catch (err) {
@@ -621,7 +627,7 @@ export default function register(api: any) {
621
627
 
622
628
  const newMemories = consumeSessionMemoryCount(ctx);
623
629
  if (!cfg.autoSleep || newMemories < AUTO_SLEEP_SESSION_THRESHOLD) return;
624
- const result = runHippo('sleep', hippoCwd);
630
+ const result = runHippo(['sleep'], hippoCwd);
625
631
  logger.info?.(
626
632
  `[hippo] autoSleep ran for session ${ctx.sessionId ?? ctx.sessionKey ?? 'unknown'} ` +
627
633
  `after ${newMemories} new memories`,
@@ -2,7 +2,7 @@
2
2
  "id": "hippo-memory",
3
3
  "name": "Hippo Memory",
4
4
  "description": "Biologically-inspired memory for AI agents. Decay by default, retrieval strengthening, sleep consolidation.",
5
- "version": "0.11.2",
5
+ "version": "0.13.0",
6
6
 
7
7
  "configSchema": {
8
8
  "type": "object",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hippo-memory",
3
- "version": "0.11.2",
3
+ "version": "0.13.0",
4
4
  "description": "Hippo Memory plugin for OpenClaw - biologically-inspired agent memory",
5
5
  "main": "index.ts",
6
6
  "openclaw": {
@@ -2,7 +2,7 @@
2
2
  "id": "hippo-memory",
3
3
  "name": "Hippo Memory",
4
4
  "description": "Biologically-inspired memory for AI agents. Decay by default, retrieval strengthening, sleep consolidation.",
5
- "version": "0.11.2",
5
+ "version": "0.13.0",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hippo-memory",
3
- "version": "0.11.2",
3
+ "version": "0.13.0",
4
4
  "description": "Biologically-inspired memory system for AI agents. Decay by default, strength through use.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",