hippo-memory 1.11.1 → 1.11.2

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/dist/src/cli.js CHANGED
@@ -30,7 +30,7 @@ import * as fs from 'fs';
30
30
  import * as os from 'os';
31
31
  import { fileURLToPath } from 'node:url';
32
32
  import { execFileSync, execSync, spawn } from 'child_process';
33
- import { installJsonHooks, uninstallJsonHooks, resolveJsonHookPaths, detectInstalledTools, defaultSleepLogPath, ensureCodexWrapperInstalled, installCodexWrapper, uninstallCodexWrapper, resolveCodexSessionTranscript, resolveCodexWrapperPaths, } from './hooks.js';
33
+ import { installJsonHooks, uninstallJsonHooks, resolveJsonHookPaths, detectInstalledTools, defaultSleepLogPath, ensureCodexWrapperInstalled, installCodexWrapper, uninstallCodexWrapper, resolveCodexSessionTranscript, resolveCodexWrapperPaths, installOpencodePlugin, uninstallOpencodePlugin, resolveOpencodePluginPath, } from './hooks.js';
34
34
  import { createMemory, calculateStrength, calculateRewardFactor, deriveHalfLife, resolveConfidence, applyOutcome, computeSchemaFit, Layer, DECISION_HALF_LIFE_DAYS, } from './memory.js';
35
35
  import { getHippoRoot, isInitialized, initStore, writeEntry, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, RECALL_DEFAULT_DENY_SCOPES, } from './store.js';
36
36
  import { markRetrieved, estimateTokens, hybridSearch, physicsSearch, explainMatch, textOverlap } from './search.js';
@@ -391,10 +391,10 @@ function autoInstallHooks(quiet) {
391
391
  installed.add(targetPath);
392
392
  console.log(` Auto-installed ${hook} hook in ${hookDef.file}`);
393
393
  }
394
- // For JSON-hook tools, also install SessionEnd+SessionStart entries.
395
- // Keeps `hippo init` in lockstep with `hippo hook install <target>` and
396
- // `hippo setup`, which both cover claude-code + opencode now.
397
- if (hook === 'claude-code' || hook === 'opencode') {
394
+ // For Claude Code, also install SessionEnd+SessionStart entries in its
395
+ // settings.json. Keeps `hippo init` in lockstep with `hippo hook install
396
+ // claude-code` and `hippo setup`.
397
+ if (hook === 'claude-code') {
398
398
  const result = installJsonHooks(hook);
399
399
  if (result.installedSessionEnd) {
400
400
  console.log(` Auto-installed hippo session-end SessionEnd hook in ${hook} settings`);
@@ -415,6 +415,21 @@ function autoInstallHooks(quiet) {
415
415
  console.log(` Migrated legacy SessionEnd entry to the new detached form`);
416
416
  }
417
417
  }
418
+ else if (hook === 'opencode') {
419
+ // opencode uses a TS plugin, not Claude Code's JSON-hook schema.
420
+ // See OPENCODE_PLUGIN_SOURCE in src/hooks.ts for the plugin file
421
+ // content + design rationale.
422
+ const result = installOpencodePlugin();
423
+ if (result.installed) {
424
+ console.log(` Auto-installed hippo opencode plugin -> ${result.pluginPath}`);
425
+ }
426
+ if (result.migratedLegacyHooks) {
427
+ console.log(` Removed legacy Claude Code-style hooks block from opencode.json — opencode can now launch`);
428
+ }
429
+ if (result.jsonRepairFailed) {
430
+ console.log(` WARNING: opencode.json is unparseable; legacy hooks block could not be auto-removed. Fix the file manually.`);
431
+ }
432
+ }
418
433
  }
419
434
  }
420
435
  /**
@@ -3780,9 +3795,9 @@ function cmdHook(args, flags) {
3780
3795
  console.log(`${hook.file} not found in ${process.cwd()} — skipping agent-instructions patch.`);
3781
3796
  console.log(` Create ${hook.file} and re-run \`hippo hook install ${target}\` if you want the agent prompt.`);
3782
3797
  }
3783
- // For tools with JSON hook systems, also install SessionEnd+SessionStart
3784
- // entries in their settings file. Currently: claude-code + opencode.
3785
- if (target === 'claude-code' || target === 'opencode') {
3798
+ // For Claude Code, also install SessionEnd+SessionStart entries in its
3799
+ // settings file.
3800
+ if (target === 'claude-code') {
3786
3801
  const result = installJsonHooks(target);
3787
3802
  if (result.installedSessionEnd) {
3788
3803
  console.log(`Installed hippo session-end SessionEnd hook in ${result.target} settings`);
@@ -3803,6 +3818,22 @@ function cmdHook(args, flags) {
3803
3818
  console.log(`Migrated legacy SessionEnd entry to the new detached form`);
3804
3819
  }
3805
3820
  }
3821
+ else if (target === 'opencode') {
3822
+ // opencode uses a TS plugin, not JSON hooks. See src/hooks.ts.
3823
+ const result = installOpencodePlugin();
3824
+ if (result.installed) {
3825
+ console.log(`Installed hippo opencode plugin at ${result.pluginPath}`);
3826
+ }
3827
+ else {
3828
+ console.log(`opencode plugin already up to date at ${result.pluginPath}`);
3829
+ }
3830
+ if (result.migratedLegacyHooks) {
3831
+ console.log(`Removed legacy Claude Code-style hooks block from opencode.json — opencode can now launch`);
3832
+ }
3833
+ if (result.jsonRepairFailed) {
3834
+ console.log(`WARNING: opencode.json is unparseable; legacy hooks block could not be auto-removed. Fix the file manually.`);
3835
+ }
3836
+ }
3806
3837
  else if (target === 'codex') {
3807
3838
  const result = installCodexWrapper();
3808
3839
  console.log(`Installed Codex session-end integration -> ${result.metadataPath}`);
@@ -3832,12 +3863,20 @@ function cmdHook(args, flags) {
3832
3863
  else {
3833
3864
  console.log(`${hook.file} not found, skipping agent-instructions uninstall.`);
3834
3865
  }
3835
- // For JSON-hook tools, also strip their SessionEnd/SessionStart entries.
3836
- if (target === 'claude-code' || target === 'opencode') {
3866
+ // For Claude Code, also strip its SessionEnd/SessionStart entries.
3867
+ if (target === 'claude-code') {
3837
3868
  if (uninstallJsonHooks(target)) {
3838
3869
  console.log(`Removed hippo hooks from ${target} settings`);
3839
3870
  }
3840
3871
  }
3872
+ else if (target === 'opencode') {
3873
+ // opencode uses a TS plugin; uninstall removes the plugin file AND
3874
+ // also runs the legacy-hooks migration so the downgrade/remove path
3875
+ // leaves opencode launchable.
3876
+ if (uninstallOpencodePlugin()) {
3877
+ console.log(`Removed hippo opencode plugin (and any legacy hooks block from opencode.json)`);
3878
+ }
3879
+ }
3841
3880
  else if (target === 'codex') {
3842
3881
  if (uninstallCodexWrapper()) {
3843
3882
  console.log('Removed Codex wrapper integration');
@@ -3866,7 +3905,7 @@ function cmdSetup(flags) {
3866
3905
  const markdownTools = tools.filter((t) => t.kind === 'markdown-instruction' && t.detected);
3867
3906
  const pluginTools = tools.filter((t) => t.kind === 'plugin' && t.detected);
3868
3907
  if (jsonTools.length === 0 && !forceAll) {
3869
- console.log('No JSON-hook-capable tools detected (checked: claude-code, opencode).');
3908
+ console.log('No JSON-hook-capable tools detected (checked: claude-code).');
3870
3909
  console.log('Run with --all to install hooks anyway.');
3871
3910
  }
3872
3911
  for (const tool of jsonTools) {
@@ -3923,7 +3962,31 @@ function cmdSetup(flags) {
3923
3962
  console.log('');
3924
3963
  console.log('Plugin-based tools (hook API via plugin, not JSON):');
3925
3964
  for (const tool of pluginTools) {
3926
- console.log(` ${tool.name.padEnd(14)} ${tool.notes}`);
3965
+ if (tool.name === 'opencode') {
3966
+ if (dryRun) {
3967
+ console.log(` ${tool.name.padEnd(14)} [dry-run] would install hippo plugin at ${resolveOpencodePluginPath()}`);
3968
+ continue;
3969
+ }
3970
+ const result = installOpencodePlugin();
3971
+ const bits = [];
3972
+ if (result.installed)
3973
+ bits.push('installed plugin');
3974
+ if (result.migratedLegacyHooks)
3975
+ bits.push('migrated legacy hooks block');
3976
+ if (result.jsonRepairFailed)
3977
+ bits.push('WARNING: opencode.json unparseable — manual fix needed');
3978
+ if (bits.length === 0) {
3979
+ console.log(` ${tool.name.padEnd(14)} already configured (${result.pluginPath})`);
3980
+ }
3981
+ else {
3982
+ console.log(` ${tool.name.padEnd(14)} ${bits.join(', ')} -> ${result.pluginPath}`);
3983
+ }
3984
+ }
3985
+ else {
3986
+ // Other plugin tools (openclaw) have their own installer; the notes
3987
+ // line points the user at it.
3988
+ console.log(` ${tool.name.padEnd(14)} ${tool.notes}`);
3989
+ }
3927
3990
  }
3928
3991
  }
3929
3992
  if (markdownTools.length > 0) {