hippo-memory 0.8.1 → 0.9.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.
- package/README.md +71 -2
- package/dist/cli.d.ts +5 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +581 -211
- package/dist/cli.js.map +1 -1
- package/dist/consolidate.d.ts.map +1 -1
- package/dist/consolidate.js +12 -5
- package/dist/consolidate.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +149 -100
- package/dist/db.js.map +1 -1
- package/dist/handoff.d.ts +29 -0
- package/dist/handoff.d.ts.map +1 -0
- package/dist/handoff.js +30 -0
- package/dist/handoff.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/search.d.ts +19 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +35 -1
- package/dist/search.js.map +1 -1
- package/dist/store.d.ts +18 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +209 -99
- package/dist/store.js.map +1 -1
- package/dist/working-memory.d.ts +59 -0
- package/dist/working-memory.d.ts.map +1 -0
- package/dist/working-memory.js +149 -0
- package/dist/working-memory.js.map +1 -0
- package/extensions/openclaw-plugin/index.ts +569 -495
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
* Commands:
|
|
6
6
|
* hippo init [--global]
|
|
7
7
|
* hippo remember <text> [--tag <t>] [--error] [--pin] [--global]
|
|
8
|
-
* hippo recall <query> [--budget <n>] [--json]
|
|
8
|
+
* hippo recall <query> [--budget <n>] [--json] [--why]
|
|
9
9
|
* hippo sleep [--dry-run]
|
|
10
10
|
* hippo status
|
|
11
11
|
* hippo outcome --good | --bad [--id <id>]
|
|
12
12
|
* hippo conflicts [--status <status>] [--json]
|
|
13
13
|
* hippo snapshot <save|show|clear>
|
|
14
|
-
* hippo session <log|show>
|
|
14
|
+
* hippo session <log|show|latest|resume>
|
|
15
|
+
* hippo handoff <create|latest|show>
|
|
16
|
+
* hippo current <show>
|
|
15
17
|
* hippo forget <id>
|
|
16
18
|
* hippo inspect <id>
|
|
17
19
|
* hippo embed [--status]
|
|
@@ -19,22 +21,30 @@
|
|
|
19
21
|
* hippo learn --git [--days <n>] [--repos <paths>]
|
|
20
22
|
* hippo promote <id>
|
|
21
23
|
* hippo sync
|
|
24
|
+
* hippo wm <push|read|clear|flush>
|
|
22
25
|
*/
|
|
23
26
|
import * as path from 'path';
|
|
24
27
|
import * as fs from 'fs';
|
|
25
28
|
import { execSync } from 'child_process';
|
|
26
29
|
import { createMemory, calculateStrength, deriveHalfLife, resolveConfidence, applyOutcome, computeSchemaFit, Layer, } from './memory.js';
|
|
27
|
-
import { getHippoRoot, isInitialized, initStore, writeEntry, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, } from './store.js';
|
|
28
|
-
import { markRetrieved, estimateTokens, hybridSearch } from './search.js';
|
|
30
|
+
import { getHippoRoot, isInitialized, initStore, writeEntry, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, } from './store.js';
|
|
31
|
+
import { markRetrieved, estimateTokens, hybridSearch, explainMatch } from './search.js';
|
|
29
32
|
import { consolidate } from './consolidate.js';
|
|
30
33
|
import { isEmbeddingAvailable, embedAll, embedMemory, loadEmbeddingIndex, } from './embeddings.js';
|
|
31
34
|
import { captureError, extractLessons, deduplicateLesson, runWatched, fetchGitLog, isGitRepo, } from './autolearn.js';
|
|
32
35
|
import { getGlobalRoot, initGlobal, promoteToGlobal, shareMemory, listPeers, autoShare, transferScore, searchBothHybrid, syncGlobalToLocal, } from './shared.js';
|
|
33
36
|
import { importChatGPT, importClaude, importCursor, importGenericFile, importMarkdown, } from './importers.js';
|
|
34
37
|
import { cmdCapture } from './capture.js';
|
|
38
|
+
import { wmPush, wmRead, wmClear, wmFlush } from './working-memory.js';
|
|
35
39
|
// ---------------------------------------------------------------------------
|
|
36
40
|
// Helpers
|
|
37
41
|
// ---------------------------------------------------------------------------
|
|
42
|
+
function parseLimitFlag(value) {
|
|
43
|
+
if (!value)
|
|
44
|
+
return Infinity;
|
|
45
|
+
const parsed = parseInt(String(value), 10);
|
|
46
|
+
return Number.isFinite(parsed) && parsed >= 1 ? parsed : Infinity;
|
|
47
|
+
}
|
|
38
48
|
function requireInit(hippoRoot) {
|
|
39
49
|
if (!isInitialized(hippoRoot)) {
|
|
40
50
|
console.error('No .hippo directory found. Run `hippo init` first.');
|
|
@@ -57,8 +67,8 @@ function parseArgs(argv) {
|
|
|
57
67
|
i++;
|
|
58
68
|
}
|
|
59
69
|
else {
|
|
60
|
-
// Check if it's a repeatable flag (tag)
|
|
61
|
-
if (key === 'tag') {
|
|
70
|
+
// Check if it's a repeatable flag (tag, artifact)
|
|
71
|
+
if (key === 'tag' || key === 'artifact') {
|
|
62
72
|
if (Array.isArray(flags[key])) {
|
|
63
73
|
flags[key].push(next);
|
|
64
74
|
}
|
|
@@ -267,7 +277,9 @@ function cmdRemember(hippoRoot, text, flags) {
|
|
|
267
277
|
async function cmdRecall(hippoRoot, query, flags) {
|
|
268
278
|
requireInit(hippoRoot);
|
|
269
279
|
const budget = parseInt(String(flags['budget'] ?? '4000'), 10);
|
|
280
|
+
const limit = parseLimitFlag(flags['limit']);
|
|
270
281
|
const asJson = Boolean(flags['json']);
|
|
282
|
+
const showWhy = Boolean(flags['why']);
|
|
271
283
|
const globalRoot = getGlobalRoot();
|
|
272
284
|
const localEntries = loadSearchEntries(hippoRoot, query);
|
|
273
285
|
const globalEntries = isInitialized(globalRoot) ? loadSearchEntries(globalRoot, query) : [];
|
|
@@ -280,6 +292,9 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
280
292
|
else {
|
|
281
293
|
results = await hybridSearch(query, localEntries, { budget, hippoRoot });
|
|
282
294
|
}
|
|
295
|
+
if (limit < results.length) {
|
|
296
|
+
results = results.slice(0, limit);
|
|
297
|
+
}
|
|
283
298
|
if (results.length === 0) {
|
|
284
299
|
if (asJson) {
|
|
285
300
|
console.log(JSON.stringify({ query, results: [], total: 0 }));
|
|
@@ -301,14 +316,27 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
301
316
|
saveIndex(hippoRoot, localIndex);
|
|
302
317
|
updateStats(hippoRoot, { recalled: results.length });
|
|
303
318
|
if (asJson) {
|
|
304
|
-
const output = results.map((r) =>
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
319
|
+
const output = results.map((r) => {
|
|
320
|
+
const isGlobal = isInitialized(globalRoot) && !localIndex.entries[r.entry.id];
|
|
321
|
+
const base = {
|
|
322
|
+
id: r.entry.id,
|
|
323
|
+
score: r.score,
|
|
324
|
+
strength: r.entry.strength,
|
|
325
|
+
tokens: r.tokens,
|
|
326
|
+
tags: r.entry.tags,
|
|
327
|
+
content: r.entry.content,
|
|
328
|
+
};
|
|
329
|
+
if (showWhy) {
|
|
330
|
+
const explanation = explainMatch(query, r);
|
|
331
|
+
base.layer = r.entry.layer;
|
|
332
|
+
base.confidence = resolveConfidence(r.entry);
|
|
333
|
+
base.source = isGlobal ? 'global' : 'local';
|
|
334
|
+
base.reason = explanation.reason;
|
|
335
|
+
base.bm25 = r.bm25;
|
|
336
|
+
base.cosine = r.cosine;
|
|
337
|
+
}
|
|
338
|
+
return base;
|
|
339
|
+
});
|
|
312
340
|
console.log(JSON.stringify({ query, budget, results: output, total: output.length }));
|
|
313
341
|
return;
|
|
314
342
|
}
|
|
@@ -319,9 +347,16 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
319
347
|
const conf = resolveConfidence(e);
|
|
320
348
|
const confLabel = conf === 'stale' || conf === 'inferred' ? `[${conf}] \u26A0\uFE0F` : `[${conf}]`;
|
|
321
349
|
const strengthBar = '\u2588'.repeat(Math.round(e.strength * 10)) + '\u2591'.repeat(10 - Math.round(e.strength * 10));
|
|
322
|
-
const
|
|
350
|
+
const isGlobal = isInitialized(globalRoot) && !localIndex.entries[e.id];
|
|
351
|
+
const globalMark = isGlobal ? ' [global]' : '';
|
|
352
|
+
const sourceMark = isGlobal ? ' [global]' : ' [local]';
|
|
323
353
|
console.log(`--- ${e.id} [${e.layer}] ${confLabel}${globalMark} score=${fmt(r.score, 3)} strength=${fmt(e.strength)}`);
|
|
324
354
|
console.log(` [${strengthBar}] tags: ${e.tags.join(', ') || 'none'} | retrieved: ${e.retrieval_count}x`);
|
|
355
|
+
if (showWhy) {
|
|
356
|
+
const explanation = explainMatch(query, r);
|
|
357
|
+
console.log(` source:${sourceMark} | layer: [${e.layer}] | confidence: [${conf}]`);
|
|
358
|
+
console.log(` reason: ${explanation.reason}`);
|
|
359
|
+
}
|
|
325
360
|
console.log();
|
|
326
361
|
console.log(e.content);
|
|
327
362
|
console.log();
|
|
@@ -682,12 +717,226 @@ function cmdSession(hippoRoot, args, flags) {
|
|
|
682
717
|
printSessionEvents(events);
|
|
683
718
|
return;
|
|
684
719
|
}
|
|
685
|
-
|
|
720
|
+
if (subcommand === 'latest') {
|
|
721
|
+
const snapshot = loadActiveTaskSnapshot(hippoRoot);
|
|
722
|
+
const events = listSessionEvents(hippoRoot, {
|
|
723
|
+
session_id: sessionId || snapshot?.session_id || undefined,
|
|
724
|
+
limit,
|
|
725
|
+
});
|
|
726
|
+
if (flags['json']) {
|
|
727
|
+
console.log(JSON.stringify({ snapshot: snapshot ?? null, events }, null, 2));
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
if (snapshot) {
|
|
731
|
+
printActiveTaskSnapshot(snapshot);
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
console.log('No active task snapshot.');
|
|
735
|
+
console.log('');
|
|
736
|
+
}
|
|
737
|
+
printSessionEvents(events);
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
if (subcommand === 'resume') {
|
|
741
|
+
const handoff = loadLatestHandoff(hippoRoot, sessionId || undefined);
|
|
742
|
+
if (!handoff) {
|
|
743
|
+
console.log('No handoff to resume from.');
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
const lines = [
|
|
747
|
+
'## Session Handoff (resumed)',
|
|
748
|
+
'',
|
|
749
|
+
`- Session: ${handoff.sessionId}`,
|
|
750
|
+
`- Updated: ${handoff.updatedAt}`,
|
|
751
|
+
];
|
|
752
|
+
if (handoff.taskId)
|
|
753
|
+
lines.push(`- Task: ${handoff.taskId}`);
|
|
754
|
+
if (handoff.repoRoot)
|
|
755
|
+
lines.push(`- Repo: ${handoff.repoRoot}`);
|
|
756
|
+
lines.push('', '### Summary', handoff.summary);
|
|
757
|
+
if (handoff.nextAction) {
|
|
758
|
+
lines.push('', '### Next action', handoff.nextAction);
|
|
759
|
+
}
|
|
760
|
+
if (handoff.artifacts && handoff.artifacts.length > 0) {
|
|
761
|
+
lines.push('', '### Artifacts');
|
|
762
|
+
for (const artifact of handoff.artifacts) {
|
|
763
|
+
lines.push(`- ${artifact}`);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
lines.push('');
|
|
767
|
+
console.log(lines.join('\n'));
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
console.error('Usage: hippo session <log|show|latest|resume>');
|
|
771
|
+
process.exit(1);
|
|
772
|
+
}
|
|
773
|
+
function printHandoff(handoff) {
|
|
774
|
+
console.log('## Session Handoff\n');
|
|
775
|
+
console.log(`- Session: ${handoff.sessionId}`);
|
|
776
|
+
console.log(`- Updated: ${handoff.updatedAt}`);
|
|
777
|
+
if (handoff.taskId)
|
|
778
|
+
console.log(`- Task: ${handoff.taskId}`);
|
|
779
|
+
if (handoff.repoRoot)
|
|
780
|
+
console.log(`- Repo: ${handoff.repoRoot}`);
|
|
781
|
+
console.log('');
|
|
782
|
+
console.log('### Summary');
|
|
783
|
+
console.log(handoff.summary);
|
|
784
|
+
if (handoff.nextAction) {
|
|
785
|
+
console.log('');
|
|
786
|
+
console.log('### Next action');
|
|
787
|
+
console.log(handoff.nextAction);
|
|
788
|
+
}
|
|
789
|
+
if (handoff.artifacts && handoff.artifacts.length > 0) {
|
|
790
|
+
console.log('');
|
|
791
|
+
console.log('### Artifacts');
|
|
792
|
+
for (const artifact of handoff.artifacts) {
|
|
793
|
+
console.log(`- ${artifact}`);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
console.log('');
|
|
797
|
+
}
|
|
798
|
+
function cmdHandoff(hippoRoot, args, flags) {
|
|
799
|
+
requireInit(hippoRoot);
|
|
800
|
+
const subcommand = args[0] ?? 'latest';
|
|
801
|
+
if (subcommand === 'create') {
|
|
802
|
+
const summary = String(flags['summary'] ?? '').trim();
|
|
803
|
+
if (!summary) {
|
|
804
|
+
console.error('Usage: hippo handoff create --summary "..." [--next "..."] [--session <id>] [--task <id>] [--artifact <path>...]');
|
|
805
|
+
process.exit(1);
|
|
806
|
+
}
|
|
807
|
+
const sessionId = String(flags['session'] ?? flags['id'] ?? '').trim() || `fallback-${Date.now()}-${process.pid}`;
|
|
808
|
+
const nextAction = String(flags['next'] ?? '').trim() || undefined;
|
|
809
|
+
const taskId = String(flags['task'] ?? '').trim() || undefined;
|
|
810
|
+
const artifactFlag = flags['artifact'];
|
|
811
|
+
const artifacts = Array.isArray(artifactFlag)
|
|
812
|
+
? artifactFlag
|
|
813
|
+
: (typeof artifactFlag === 'string' ? [artifactFlag] : []);
|
|
814
|
+
const handoff = saveSessionHandoff(hippoRoot, {
|
|
815
|
+
version: 1,
|
|
816
|
+
sessionId,
|
|
817
|
+
repoRoot: process.cwd(),
|
|
818
|
+
taskId,
|
|
819
|
+
summary,
|
|
820
|
+
nextAction,
|
|
821
|
+
artifacts,
|
|
822
|
+
});
|
|
823
|
+
console.log(`Created session handoff for session ${handoff.sessionId}`);
|
|
824
|
+
console.log(` Summary: ${handoff.summary}`);
|
|
825
|
+
if (handoff.nextAction)
|
|
826
|
+
console.log(` Next: ${handoff.nextAction}`);
|
|
827
|
+
if (handoff.artifacts && handoff.artifacts.length > 0) {
|
|
828
|
+
console.log(` Artifacts: ${handoff.artifacts.join(', ')}`);
|
|
829
|
+
}
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
if (subcommand === 'latest') {
|
|
833
|
+
const sessionId = String(flags['session'] ?? flags['id'] ?? '').trim() || undefined;
|
|
834
|
+
const handoff = loadLatestHandoff(hippoRoot, sessionId);
|
|
835
|
+
if (!handoff) {
|
|
836
|
+
if (flags['json']) {
|
|
837
|
+
console.log(JSON.stringify({ handoff: null }));
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
console.log('No session handoff found.');
|
|
841
|
+
}
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
if (flags['json']) {
|
|
845
|
+
console.log(JSON.stringify({ handoff }, null, 2));
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
printHandoff(handoff);
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
if (subcommand === 'show') {
|
|
852
|
+
const idArg = args[1];
|
|
853
|
+
if (!idArg) {
|
|
854
|
+
console.error('Usage: hippo handoff show <id> [--json]');
|
|
855
|
+
process.exit(1);
|
|
856
|
+
}
|
|
857
|
+
const handoffId = parseInt(idArg, 10);
|
|
858
|
+
if (!Number.isFinite(handoffId) || handoffId <= 0) {
|
|
859
|
+
console.error(`Invalid handoff ID: ${idArg}`);
|
|
860
|
+
process.exit(1);
|
|
861
|
+
}
|
|
862
|
+
const handoff = loadHandoffById(hippoRoot, handoffId);
|
|
863
|
+
if (!handoff) {
|
|
864
|
+
if (flags['json']) {
|
|
865
|
+
console.log(JSON.stringify({ handoff: null }));
|
|
866
|
+
}
|
|
867
|
+
else {
|
|
868
|
+
console.log(`No handoff found with ID ${handoffId}.`);
|
|
869
|
+
}
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
if (flags['json']) {
|
|
873
|
+
console.log(JSON.stringify({ handoff }, null, 2));
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
printHandoff(handoff);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
console.error('Usage: hippo handoff <create|latest|show>');
|
|
880
|
+
process.exit(1);
|
|
881
|
+
}
|
|
882
|
+
function cmdCurrent(hippoRoot, args, flags) {
|
|
883
|
+
requireInit(hippoRoot);
|
|
884
|
+
const subcommand = args[0] ?? 'show';
|
|
885
|
+
if (subcommand === 'show') {
|
|
886
|
+
const asJson = Boolean(flags['json']);
|
|
887
|
+
const snapshot = loadActiveTaskSnapshot(hippoRoot);
|
|
888
|
+
const sessionId = snapshot?.session_id ?? undefined;
|
|
889
|
+
const events = listSessionEvents(hippoRoot, {
|
|
890
|
+
session_id: sessionId,
|
|
891
|
+
limit: 5,
|
|
892
|
+
});
|
|
893
|
+
if (asJson) {
|
|
894
|
+
console.log(JSON.stringify({
|
|
895
|
+
snapshot: snapshot ?? null,
|
|
896
|
+
events: events.map((ev) => ({
|
|
897
|
+
id: ev.id,
|
|
898
|
+
session_id: ev.session_id,
|
|
899
|
+
event_type: ev.event_type,
|
|
900
|
+
content: ev.content,
|
|
901
|
+
created_at: ev.created_at,
|
|
902
|
+
})),
|
|
903
|
+
}));
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
if (!snapshot && events.length === 0) {
|
|
907
|
+
console.log('No active task or recent session events.');
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
console.log('# Current State\n');
|
|
911
|
+
if (snapshot) {
|
|
912
|
+
console.log(`Task: ${snapshot.task}`);
|
|
913
|
+
console.log(`Status: ${snapshot.status} | Source: ${snapshot.source} | Updated: ${snapshot.updated_at}`);
|
|
914
|
+
if (snapshot.session_id) {
|
|
915
|
+
console.log(`Session: ${snapshot.session_id}`);
|
|
916
|
+
}
|
|
917
|
+
console.log(`Summary: ${snapshot.summary}`);
|
|
918
|
+
console.log(`Next: ${snapshot.next_step}`);
|
|
919
|
+
}
|
|
920
|
+
else {
|
|
921
|
+
console.log('No active task snapshot.');
|
|
922
|
+
}
|
|
923
|
+
if (events.length > 0) {
|
|
924
|
+
console.log('');
|
|
925
|
+
console.log('Recent events:');
|
|
926
|
+
for (const ev of events) {
|
|
927
|
+
const ts = ev.created_at.slice(0, 19).replace('T', ' ');
|
|
928
|
+
console.log(` [${ts}] (${ev.event_type}) ${ev.content}`);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
console.error('Usage: hippo current <show>');
|
|
686
934
|
process.exit(1);
|
|
687
935
|
}
|
|
688
936
|
async function cmdContext(hippoRoot, args, flags) {
|
|
689
937
|
requireInit(hippoRoot);
|
|
690
938
|
const budget = parseInt(String(flags['budget'] ?? '1500'), 10);
|
|
939
|
+
const limit = parseLimitFlag(flags['limit']);
|
|
691
940
|
// If budget is 0, skip entirely (zero token cost)
|
|
692
941
|
if (budget <= 0)
|
|
693
942
|
return;
|
|
@@ -765,6 +1014,10 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
765
1014
|
selectedItems = results;
|
|
766
1015
|
totalTokens = results.reduce((sum, r) => sum + r.tokens, 0);
|
|
767
1016
|
}
|
|
1017
|
+
if (limit < selectedItems.length) {
|
|
1018
|
+
selectedItems = selectedItems.slice(0, limit);
|
|
1019
|
+
totalTokens = selectedItems.reduce((sum, r) => sum + r.tokens, 0);
|
|
1020
|
+
}
|
|
768
1021
|
if (selectedItems.length === 0 && !activeSnapshot && recentSessionEvents.length === 0)
|
|
769
1022
|
return;
|
|
770
1023
|
// Mark retrieved and persist
|
|
@@ -1136,97 +1389,97 @@ const HOOKS = {
|
|
|
1136
1389
|
'claude-code': {
|
|
1137
1390
|
file: 'CLAUDE.md',
|
|
1138
1391
|
description: 'Claude Code',
|
|
1139
|
-
content: `
|
|
1140
|
-
## Project Memory (Hippo)
|
|
1141
|
-
|
|
1142
|
-
Before starting work, load relevant context:
|
|
1143
|
-
\`\`\`bash
|
|
1144
|
-
hippo context --auto --budget 1500
|
|
1145
|
-
\`\`\`
|
|
1146
|
-
|
|
1147
|
-
When you learn something important:
|
|
1148
|
-
\`\`\`bash
|
|
1149
|
-
hippo remember "<lesson>"
|
|
1150
|
-
\`\`\`
|
|
1151
|
-
|
|
1152
|
-
When you hit an error or discover a gotcha:
|
|
1153
|
-
\`\`\`bash
|
|
1154
|
-
hippo remember "<what went wrong and why>" --error
|
|
1155
|
-
\`\`\`
|
|
1156
|
-
|
|
1157
|
-
After significant discussions or decisions, capture context:
|
|
1158
|
-
\`\`\`bash
|
|
1159
|
-
hippo capture --stdin <<< 'summary of what was decided'
|
|
1160
|
-
\`\`\`
|
|
1161
|
-
|
|
1162
|
-
After completing work successfully:
|
|
1163
|
-
\`\`\`bash
|
|
1164
|
-
hippo outcome --good
|
|
1165
|
-
\`\`\`
|
|
1392
|
+
content: `
|
|
1393
|
+
## Project Memory (Hippo)
|
|
1394
|
+
|
|
1395
|
+
Before starting work, load relevant context:
|
|
1396
|
+
\`\`\`bash
|
|
1397
|
+
hippo context --auto --budget 1500
|
|
1398
|
+
\`\`\`
|
|
1399
|
+
|
|
1400
|
+
When you learn something important:
|
|
1401
|
+
\`\`\`bash
|
|
1402
|
+
hippo remember "<lesson>"
|
|
1403
|
+
\`\`\`
|
|
1404
|
+
|
|
1405
|
+
When you hit an error or discover a gotcha:
|
|
1406
|
+
\`\`\`bash
|
|
1407
|
+
hippo remember "<what went wrong and why>" --error
|
|
1408
|
+
\`\`\`
|
|
1409
|
+
|
|
1410
|
+
After significant discussions or decisions, capture context:
|
|
1411
|
+
\`\`\`bash
|
|
1412
|
+
hippo capture --stdin <<< 'summary of what was decided'
|
|
1413
|
+
\`\`\`
|
|
1414
|
+
|
|
1415
|
+
After completing work successfully:
|
|
1416
|
+
\`\`\`bash
|
|
1417
|
+
hippo outcome --good
|
|
1418
|
+
\`\`\`
|
|
1166
1419
|
`.trim(),
|
|
1167
1420
|
},
|
|
1168
1421
|
'codex': {
|
|
1169
1422
|
file: 'AGENTS.md',
|
|
1170
1423
|
description: 'OpenAI Codex',
|
|
1171
|
-
content: `
|
|
1172
|
-
## Project Memory (Hippo)
|
|
1173
|
-
|
|
1174
|
-
At the start of every task, run:
|
|
1175
|
-
\`\`\`bash
|
|
1176
|
-
hippo context --auto --budget 1500
|
|
1177
|
-
\`\`\`
|
|
1178
|
-
Read the output before writing any code.
|
|
1179
|
-
|
|
1180
|
-
On errors or unexpected behaviour:
|
|
1181
|
-
\`\`\`bash
|
|
1182
|
-
hippo remember "<description of what went wrong>" --error
|
|
1183
|
-
\`\`\`
|
|
1184
|
-
|
|
1185
|
-
On task completion:
|
|
1186
|
-
\`\`\`bash
|
|
1187
|
-
hippo outcome --good
|
|
1188
|
-
\`\`\`
|
|
1424
|
+
content: `
|
|
1425
|
+
## Project Memory (Hippo)
|
|
1426
|
+
|
|
1427
|
+
At the start of every task, run:
|
|
1428
|
+
\`\`\`bash
|
|
1429
|
+
hippo context --auto --budget 1500
|
|
1430
|
+
\`\`\`
|
|
1431
|
+
Read the output before writing any code.
|
|
1432
|
+
|
|
1433
|
+
On errors or unexpected behaviour:
|
|
1434
|
+
\`\`\`bash
|
|
1435
|
+
hippo remember "<description of what went wrong>" --error
|
|
1436
|
+
\`\`\`
|
|
1437
|
+
|
|
1438
|
+
On task completion:
|
|
1439
|
+
\`\`\`bash
|
|
1440
|
+
hippo outcome --good
|
|
1441
|
+
\`\`\`
|
|
1189
1442
|
`.trim(),
|
|
1190
1443
|
},
|
|
1191
1444
|
'cursor': {
|
|
1192
1445
|
file: '.cursorrules',
|
|
1193
1446
|
description: 'Cursor',
|
|
1194
|
-
content: `
|
|
1195
|
-
# Project Memory (Hippo)
|
|
1196
|
-
# Before each task, load context:
|
|
1197
|
-
# hippo context --auto --budget 1500
|
|
1198
|
-
# After errors:
|
|
1199
|
-
# hippo remember "<error description>" --error
|
|
1200
|
-
# After completing:
|
|
1201
|
-
# hippo outcome --good
|
|
1447
|
+
content: `
|
|
1448
|
+
# Project Memory (Hippo)
|
|
1449
|
+
# Before each task, load context:
|
|
1450
|
+
# hippo context --auto --budget 1500
|
|
1451
|
+
# After errors:
|
|
1452
|
+
# hippo remember "<error description>" --error
|
|
1453
|
+
# After completing:
|
|
1454
|
+
# hippo outcome --good
|
|
1202
1455
|
`.trim(),
|
|
1203
1456
|
},
|
|
1204
1457
|
'openclaw': {
|
|
1205
1458
|
file: 'AGENTS.md',
|
|
1206
1459
|
description: 'OpenClaw',
|
|
1207
|
-
content: `
|
|
1208
|
-
## Project Memory (Hippo)
|
|
1209
|
-
|
|
1210
|
-
At the start of every session, run:
|
|
1211
|
-
\`\`\`bash
|
|
1212
|
-
hippo context --auto --budget 1500
|
|
1213
|
-
\`\`\`
|
|
1214
|
-
Read the output before writing any code.
|
|
1215
|
-
|
|
1216
|
-
On errors or unexpected behaviour:
|
|
1217
|
-
\`\`\`bash
|
|
1218
|
-
hippo remember "<description of what went wrong>" --error
|
|
1219
|
-
\`\`\`
|
|
1220
|
-
|
|
1221
|
-
On task completion:
|
|
1222
|
-
\`\`\`bash
|
|
1223
|
-
hippo outcome --good
|
|
1224
|
-
\`\`\`
|
|
1225
|
-
|
|
1226
|
-
After significant coding sessions:
|
|
1227
|
-
\`\`\`bash
|
|
1228
|
-
hippo learn --git
|
|
1229
|
-
\`\`\`
|
|
1460
|
+
content: `
|
|
1461
|
+
## Project Memory (Hippo)
|
|
1462
|
+
|
|
1463
|
+
At the start of every session, run:
|
|
1464
|
+
\`\`\`bash
|
|
1465
|
+
hippo context --auto --budget 1500
|
|
1466
|
+
\`\`\`
|
|
1467
|
+
Read the output before writing any code.
|
|
1468
|
+
|
|
1469
|
+
On errors or unexpected behaviour:
|
|
1470
|
+
\`\`\`bash
|
|
1471
|
+
hippo remember "<description of what went wrong>" --error
|
|
1472
|
+
\`\`\`
|
|
1473
|
+
|
|
1474
|
+
On task completion:
|
|
1475
|
+
\`\`\`bash
|
|
1476
|
+
hippo outcome --good
|
|
1477
|
+
\`\`\`
|
|
1478
|
+
|
|
1479
|
+
After significant coding sessions:
|
|
1480
|
+
\`\`\`bash
|
|
1481
|
+
hippo learn --git
|
|
1482
|
+
\`\`\`
|
|
1230
1483
|
`.trim(),
|
|
1231
1484
|
},
|
|
1232
1485
|
};
|
|
@@ -1306,126 +1559,234 @@ function cmdHook(args, flags) {
|
|
|
1306
1559
|
function escapeRegex(s) {
|
|
1307
1560
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1308
1561
|
}
|
|
1562
|
+
// ---------------------------------------------------------------------------
|
|
1563
|
+
// Working Memory
|
|
1564
|
+
// ---------------------------------------------------------------------------
|
|
1565
|
+
function cmdWm(hippoRoot, args, flags) {
|
|
1566
|
+
requireInit(hippoRoot);
|
|
1567
|
+
const subcommand = args[0] ?? '';
|
|
1568
|
+
if (subcommand === 'push') {
|
|
1569
|
+
const scope = String(flags['scope'] ?? 'default').trim();
|
|
1570
|
+
const content = String(flags['content'] ?? '').trim();
|
|
1571
|
+
const importance = parseFloat(String(flags['importance'] ?? '0.5'));
|
|
1572
|
+
const sessionId = flags['session'] ? String(flags['session']).trim() : undefined;
|
|
1573
|
+
const taskId = flags['task'] ? String(flags['task']).trim() : undefined;
|
|
1574
|
+
if (!content) {
|
|
1575
|
+
console.error('Usage: hippo wm push --scope <scope> --content "..." [--importance 0.8] [--session <id>] [--task <id>]');
|
|
1576
|
+
process.exit(1);
|
|
1577
|
+
}
|
|
1578
|
+
const id = wmPush(hippoRoot, {
|
|
1579
|
+
scope,
|
|
1580
|
+
content,
|
|
1581
|
+
importance: Number.isFinite(importance) ? importance : 0.5,
|
|
1582
|
+
sessionId,
|
|
1583
|
+
taskId,
|
|
1584
|
+
});
|
|
1585
|
+
console.log(`Pushed working memory #${id} (scope=${scope}, importance=${Number.isFinite(importance) ? importance : 0.5})`);
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
if (subcommand === 'read') {
|
|
1589
|
+
const scope = flags['scope'] ? String(flags['scope']).trim() : undefined;
|
|
1590
|
+
const sessionId = flags['session'] ? String(flags['session']).trim() : undefined;
|
|
1591
|
+
const limit = parseInt(String(flags['limit'] ?? '20'), 10) || 20;
|
|
1592
|
+
const items = wmRead(hippoRoot, { scope, sessionId, limit });
|
|
1593
|
+
if (flags['json']) {
|
|
1594
|
+
console.log(JSON.stringify({ items }, null, 2));
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1597
|
+
if (items.length === 0) {
|
|
1598
|
+
console.log('No working memory entries.');
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
console.log(`Working memory (${items.length} entries):\n`);
|
|
1602
|
+
for (const item of items) {
|
|
1603
|
+
const sessionLabel = item.sessionId ? ` session=${item.sessionId}` : '';
|
|
1604
|
+
const taskLabel = item.taskId ? ` task=${item.taskId}` : '';
|
|
1605
|
+
console.log(` #${item.id} [${item.scope}] importance=${item.importance}${sessionLabel}${taskLabel}`);
|
|
1606
|
+
console.log(` ${item.content}`);
|
|
1607
|
+
console.log(` created=${item.createdAt}`);
|
|
1608
|
+
console.log('');
|
|
1609
|
+
}
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
if (subcommand === 'clear') {
|
|
1613
|
+
const scope = flags['scope'] ? String(flags['scope']).trim() : undefined;
|
|
1614
|
+
const sessionId = flags['session'] ? String(flags['session']).trim() : undefined;
|
|
1615
|
+
const count = wmClear(hippoRoot, { scope, sessionId });
|
|
1616
|
+
console.log(`Cleared ${count} working memory entries.`);
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
if (subcommand === 'flush') {
|
|
1620
|
+
const scope = flags['scope'] ? String(flags['scope']).trim() : undefined;
|
|
1621
|
+
const sessionId = flags['session'] ? String(flags['session']).trim() : undefined;
|
|
1622
|
+
const count = wmFlush(hippoRoot, { scope, sessionId });
|
|
1623
|
+
console.log(`Flushed ${count} working memory entries.`);
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
console.error('Usage: hippo wm <push|read|clear|flush>');
|
|
1627
|
+
process.exit(1);
|
|
1628
|
+
}
|
|
1309
1629
|
function printUsage() {
|
|
1310
|
-
console.log(`
|
|
1311
|
-
Hippo - biologically-inspired memory system for AI agents
|
|
1312
|
-
|
|
1313
|
-
Usage: hippo <command> [options]
|
|
1314
|
-
|
|
1315
|
-
Commands:
|
|
1316
|
-
init Create .hippo/ structure in current directory
|
|
1317
|
-
--global Init the global store at ~/.hippo/
|
|
1318
|
-
--no-hooks Skip auto-detecting and installing agent hooks
|
|
1319
|
-
--no-schedule Skip auto-creating daily learn+sleep cron job
|
|
1320
|
-
remember <text> Store a memory
|
|
1321
|
-
--tag <tag> Add a tag (repeatable)
|
|
1322
|
-
--error Tag as error (boosts retention)
|
|
1323
|
-
--pin Pin memory (never decays)
|
|
1324
|
-
--verified Set confidence: verified (default)
|
|
1325
|
-
--observed Set confidence: observed
|
|
1326
|
-
--inferred Set confidence: inferred
|
|
1327
|
-
--global Store in global ~/.hippo/ store
|
|
1328
|
-
recall <query> Search and retrieve memories (local + global)
|
|
1329
|
-
--budget <n> Token budget (default: 4000)
|
|
1330
|
-
--json Output as JSON
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
--
|
|
1334
|
-
--
|
|
1335
|
-
--
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
--
|
|
1342
|
-
--
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
--
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
--
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
--
|
|
1353
|
-
--
|
|
1354
|
-
--
|
|
1355
|
-
--
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
--
|
|
1364
|
-
--
|
|
1365
|
-
--
|
|
1366
|
-
--
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
--
|
|
1370
|
-
--
|
|
1371
|
-
--
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
--
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
--
|
|
1400
|
-
--
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
--
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1630
|
+
console.log(`
|
|
1631
|
+
Hippo - biologically-inspired memory system for AI agents
|
|
1632
|
+
|
|
1633
|
+
Usage: hippo <command> [options]
|
|
1634
|
+
|
|
1635
|
+
Commands:
|
|
1636
|
+
init Create .hippo/ structure in current directory
|
|
1637
|
+
--global Init the global store at ~/.hippo/
|
|
1638
|
+
--no-hooks Skip auto-detecting and installing agent hooks
|
|
1639
|
+
--no-schedule Skip auto-creating daily learn+sleep cron job
|
|
1640
|
+
remember <text> Store a memory
|
|
1641
|
+
--tag <tag> Add a tag (repeatable)
|
|
1642
|
+
--error Tag as error (boosts retention)
|
|
1643
|
+
--pin Pin memory (never decays)
|
|
1644
|
+
--verified Set confidence: verified (default)
|
|
1645
|
+
--observed Set confidence: observed
|
|
1646
|
+
--inferred Set confidence: inferred
|
|
1647
|
+
--global Store in global ~/.hippo/ store
|
|
1648
|
+
recall <query> Search and retrieve memories (local + global)
|
|
1649
|
+
--budget <n> Token budget (default: 4000)
|
|
1650
|
+
--json Output as JSON
|
|
1651
|
+
--why Show match reasons and source annotations
|
|
1652
|
+
context Smart context injection for AI agents
|
|
1653
|
+
--auto Auto-detect task from git state
|
|
1654
|
+
--budget <n> Token budget (default: 1500)
|
|
1655
|
+
--format <fmt> Output format: markdown (default) or json
|
|
1656
|
+
--framing <mode> Framing: observe (default), suggest, assert
|
|
1657
|
+
sleep Run consolidation pass
|
|
1658
|
+
--dry-run Preview without writing
|
|
1659
|
+
status Show memory health stats
|
|
1660
|
+
outcome Apply feedback to last recall
|
|
1661
|
+
--good Memories were helpful
|
|
1662
|
+
--bad Memories were irrelevant
|
|
1663
|
+
--id <id> Target a specific memory
|
|
1664
|
+
conflicts List detected open memory conflicts
|
|
1665
|
+
--status <status> Filter by status (default: open)
|
|
1666
|
+
--json Output as JSON
|
|
1667
|
+
resolve <conflict_id> Resolve a memory conflict
|
|
1668
|
+
--keep <memory_id> Memory to keep (required)
|
|
1669
|
+
--forget Delete the losing memory (default: halve half-life)
|
|
1670
|
+
snapshot <sub> Persist or inspect the current active task
|
|
1671
|
+
snapshot save Save active task state
|
|
1672
|
+
--task <task>
|
|
1673
|
+
--summary <summary>
|
|
1674
|
+
--next-step <step>
|
|
1675
|
+
--source <source> Optional source label
|
|
1676
|
+
--session <id> Link snapshot to a session trail
|
|
1677
|
+
snapshot show Show the active task snapshot
|
|
1678
|
+
--json Output as JSON
|
|
1679
|
+
snapshot clear Clear the active task snapshot
|
|
1680
|
+
--status <status> Mark final status (default: cleared)
|
|
1681
|
+
session <sub> Append or inspect short-term session history
|
|
1682
|
+
session log Append a structured session event
|
|
1683
|
+
--id <session-id>
|
|
1684
|
+
--content <text>
|
|
1685
|
+
--type <type> Event type (default: note)
|
|
1686
|
+
--task <task> Optional task label
|
|
1687
|
+
--source <source> Optional source label
|
|
1688
|
+
session show Show recent events for a session or task
|
|
1689
|
+
--id <session-id>
|
|
1690
|
+
--task <task>
|
|
1691
|
+
--limit <n> Event limit (default: 8)
|
|
1692
|
+
--json Output as JSON
|
|
1693
|
+
session latest Show latest task snapshot + events
|
|
1694
|
+
--id <session-id> Filter by session
|
|
1695
|
+
--json Output as JSON
|
|
1696
|
+
session resume Re-inject latest handoff as context output
|
|
1697
|
+
--id <session-id> Filter by session
|
|
1698
|
+
handoff <sub> Manage session handoffs for continuity
|
|
1699
|
+
handoff create Create a new session handoff
|
|
1700
|
+
--summary <text> Handoff summary (required)
|
|
1701
|
+
--next <text> Next action for successor
|
|
1702
|
+
--session <id> Session ID (auto-generated if omitted)
|
|
1703
|
+
--task <id> Associated task ID
|
|
1704
|
+
--artifact <path> Related file path (repeatable)
|
|
1705
|
+
handoff latest Show the most recent handoff
|
|
1706
|
+
--session <id> Filter by session
|
|
1707
|
+
--json Output as JSON
|
|
1708
|
+
handoff show <id> Show a specific handoff by ID
|
|
1709
|
+
current <sub> Show compact current state for agent injection
|
|
1710
|
+
current show Active task + recent session events (default)
|
|
1711
|
+
--json Output as JSON
|
|
1712
|
+
forget <id> Force remove a memory
|
|
1713
|
+
inspect <id> Show full memory detail
|
|
1714
|
+
embed Embed all memories for semantic search
|
|
1715
|
+
--status Show embedding coverage
|
|
1716
|
+
watch "<command>" Run command, auto-learn from failures
|
|
1717
|
+
learn Learn lessons from repository history
|
|
1718
|
+
--git Scan recent git commits for lessons
|
|
1719
|
+
--days <n> Scan this many days back (default: 7)
|
|
1720
|
+
--repos <paths> Comma-separated repo paths to scan
|
|
1721
|
+
promote <id> Copy a local memory to the global store
|
|
1722
|
+
share <id> Share a memory with attribution + transfer scoring
|
|
1723
|
+
--force Share even if transfer score is low
|
|
1724
|
+
--auto Auto-share all high-transfer-score memories
|
|
1725
|
+
--dry-run Preview what would be shared
|
|
1726
|
+
--min-score <n> Minimum transfer score (default: 0.6)
|
|
1727
|
+
peers List projects contributing to global store
|
|
1728
|
+
sync Pull global memories into local project
|
|
1729
|
+
import Import memories from other AI tools
|
|
1730
|
+
--chatgpt <path> Import from ChatGPT memory export (JSON or txt)
|
|
1731
|
+
--claude <path> Import from CLAUDE.md or Claude memory.json
|
|
1732
|
+
--cursor <path> Import from .cursorrules or .cursor/rules
|
|
1733
|
+
--file <path> Import from any markdown or text file
|
|
1734
|
+
--markdown <path> Import from structured MEMORY.md / AGENTS.md
|
|
1735
|
+
--dry-run Preview without writing
|
|
1736
|
+
--global Write to global store (~/.hippo/)
|
|
1737
|
+
--tag <tag> Add extra tag (repeatable)
|
|
1738
|
+
capture Extract memories from conversation text
|
|
1739
|
+
--stdin Read from piped input
|
|
1740
|
+
--file <path> Read from a file
|
|
1741
|
+
--last-session (placeholder) Read from agent session logs
|
|
1742
|
+
--dry-run Preview without writing
|
|
1743
|
+
--global Write to global store (~/.hippo/)
|
|
1744
|
+
hook <sub> [target] Manage framework integrations
|
|
1745
|
+
hook list Show available hooks
|
|
1746
|
+
hook install <target> Install hook (claude-code|codex|cursor|openclaw)
|
|
1747
|
+
hook uninstall <target> Remove hook
|
|
1748
|
+
wm <sub> Working memory — bounded buffer for current state
|
|
1749
|
+
wm push Push a working memory entry
|
|
1750
|
+
--scope <scope> Scope name (default: default)
|
|
1751
|
+
--content <text> Content to store (required)
|
|
1752
|
+
--importance <n> Priority 0-1 (default: 0.5)
|
|
1753
|
+
--session <id> Session ID
|
|
1754
|
+
--task <id> Task ID
|
|
1755
|
+
wm read Read working memory entries
|
|
1756
|
+
--scope <scope> Filter by scope
|
|
1757
|
+
--session <id> Filter by session
|
|
1758
|
+
--limit <n> Max entries (default: 20)
|
|
1759
|
+
--json Output as JSON
|
|
1760
|
+
wm clear Clear working memory entries
|
|
1761
|
+
--scope <scope> Filter by scope
|
|
1762
|
+
--session <id> Filter by session
|
|
1763
|
+
wm flush Flush working memory (session end)
|
|
1764
|
+
--scope <scope> Filter by scope
|
|
1765
|
+
--session <id> Filter by session
|
|
1766
|
+
dashboard Open web dashboard for memory health
|
|
1767
|
+
--port <n> Port to serve on (default: 3333)
|
|
1768
|
+
mcp Start MCP server (stdio transport)
|
|
1769
|
+
|
|
1770
|
+
Examples:
|
|
1771
|
+
hippo init
|
|
1772
|
+
hippo remember "FRED cache can silently drop series" --tag error
|
|
1773
|
+
hippo recall "data pipeline issues" --budget 2000
|
|
1774
|
+
hippo context --auto --budget 1500
|
|
1775
|
+
hippo conflicts
|
|
1776
|
+
hippo session log --id sess_123 --task "Ship feature" --type progress --content "Build is green, next step is docs"
|
|
1777
|
+
hippo session latest --json
|
|
1778
|
+
hippo session resume
|
|
1779
|
+
hippo snapshot save --task "Ship feature" --summary "Tests are green" --next-step "Open the PR" --session sess_123
|
|
1780
|
+
hippo handoff create --summary "PR is open, tests green" --next "Merge after review" --session sess_123 --artifact src/foo.ts
|
|
1781
|
+
hippo embed --status
|
|
1782
|
+
hippo watch "npm run build"
|
|
1783
|
+
hippo learn --git --days 30
|
|
1784
|
+
hippo promote mem_abc123
|
|
1785
|
+
hippo sync
|
|
1786
|
+
hippo hook install claude-code
|
|
1787
|
+
hippo sleep --dry-run
|
|
1788
|
+
hippo outcome --good
|
|
1789
|
+
hippo status
|
|
1429
1790
|
`);
|
|
1430
1791
|
}
|
|
1431
1792
|
// ---------------------------------------------------------------------------
|
|
@@ -1477,6 +1838,12 @@ async function main() {
|
|
|
1477
1838
|
case 'session':
|
|
1478
1839
|
cmdSession(hippoRoot, args, flags);
|
|
1479
1840
|
break;
|
|
1841
|
+
case 'handoff':
|
|
1842
|
+
cmdHandoff(hippoRoot, args, flags);
|
|
1843
|
+
break;
|
|
1844
|
+
case 'current':
|
|
1845
|
+
cmdCurrent(hippoRoot, args, flags);
|
|
1846
|
+
break;
|
|
1480
1847
|
case 'forget': {
|
|
1481
1848
|
const id = args[0];
|
|
1482
1849
|
if (!id) {
|
|
@@ -1625,6 +1992,9 @@ async function main() {
|
|
|
1625
1992
|
await new Promise(() => { }); // run until Ctrl+C
|
|
1626
1993
|
break;
|
|
1627
1994
|
}
|
|
1995
|
+
case 'wm':
|
|
1996
|
+
cmdWm(hippoRoot, args, flags);
|
|
1997
|
+
break;
|
|
1628
1998
|
case 'mcp':
|
|
1629
1999
|
// Start MCP server over stdio - dynamically import to keep main CLI lean
|
|
1630
2000
|
await import('./mcp/server.js');
|