hippo-memory 1.45.0 → 1.46.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 +57 -15
- package/dist/ablation.d.ts +10 -1
- package/dist/ablation.js +17 -1
- package/dist/api.d.ts +60 -1
- package/dist/api.js +189 -7
- package/dist/audit.d.ts +1 -1
- package/dist/capture-error.d.ts +20 -0
- package/dist/capture-error.js +82 -0
- package/dist/capture.d.ts +25 -8
- package/dist/capture.js +100 -5
- package/dist/cli.d.ts +6 -1
- package/dist/cli.js +381 -48
- package/dist/config.d.ts +20 -0
- package/dist/config.js +35 -0
- package/dist/consolidate.d.ts +6 -0
- package/dist/consolidate.js +98 -13
- package/dist/db.js +57 -1
- package/dist/doctor.d.ts +34 -0
- package/dist/doctor.js +174 -0
- package/dist/dormant.d.ts +91 -0
- package/dist/dormant.js +121 -0
- package/dist/eval-stats.d.ts +123 -0
- package/dist/eval-stats.js +187 -0
- package/dist/half-life-migration.d.ts +55 -0
- package/dist/half-life-migration.js +111 -0
- package/dist/hooks.d.ts +4 -0
- package/dist/hooks.js +47 -0
- package/dist/mcp/server.d.ts +6 -0
- package/dist/mcp/server.js +70 -13
- package/dist/memory.d.ts +16 -2
- package/dist/memory.js +27 -5
- package/dist/physics-config.js +5 -1
- package/dist/recall-scope.d.ts +24 -0
- package/dist/recall-scope.js +41 -0
- package/dist/reject-flow.d.ts +3 -3
- package/dist/reject-flow.js +10 -3
- package/dist/search.d.ts +4 -4
- package/dist/search.js +23 -18
- package/dist/server.js +11 -1
- package/dist/store.d.ts +12 -1
- package/dist/store.js +58 -12
- package/dist/token-ledger.d.ts +119 -0
- package/dist/token-ledger.js +181 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- 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 +2 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { JsonValue } from './working-memory.js';
|
|
2
|
+
/** Why a failure was not stored, or `stored`. */
|
|
3
|
+
export type CaptureErrorOutcome = 'stored' | 'duplicate' | 'skipped-interrupt' | 'skipped-routine' | 'skipped-invalid';
|
|
4
|
+
/** Normalised form used to spot repeats of the same failure. */
|
|
5
|
+
export declare function failureSignature(text: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* The memory text for a failure payload, or the reason it is not stored.
|
|
8
|
+
* Pure: no store access.
|
|
9
|
+
*/
|
|
10
|
+
export declare function lessonFromFailure(payload: JsonValue): {
|
|
11
|
+
text: string;
|
|
12
|
+
} | {
|
|
13
|
+
skip: Exclude<CaptureErrorOutcome, 'stored' | 'duplicate'>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Store a failure payload as an error memory unless it is routine or a
|
|
17
|
+
* repeat of an auto-captured error already in the store.
|
|
18
|
+
*/
|
|
19
|
+
export declare function captureToolFailure(hippoRoot: string, tenantId: string, payload: JsonValue): CaptureErrorOutcome;
|
|
20
|
+
//# sourceMappingURL=capture-error.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hippo capture-error`: turn a failed tool call into an error memory. Run by
|
|
3
|
+
* the Claude Code `PostToolUseFailure` hook (both `hippo hook install
|
|
4
|
+
* claude-code` and the plugin), which writes the failure as JSON on stdin.
|
|
5
|
+
*
|
|
6
|
+
* Most failed tool calls are not lessons. An interrupt, a permission the
|
|
7
|
+
* user declined, a search that found nothing or a `grep` that exits 1 is
|
|
8
|
+
* routine, and error memories decay slower than other memories, so storing
|
|
9
|
+
* them would crowd out real lessons. Those are dropped here, repeats of the
|
|
10
|
+
* same failure are stored once, and what is stored is marked `observed`
|
|
11
|
+
* (auto-captured, not verified): outcome feedback, not capture, is what
|
|
12
|
+
* should strengthen it.
|
|
13
|
+
*/
|
|
14
|
+
import { createMemory } from './memory.js';
|
|
15
|
+
import { writeEntry, loadAllEntries } from './store.js';
|
|
16
|
+
import { loadConfig } from './config.js';
|
|
17
|
+
const MAX_LEN = 200;
|
|
18
|
+
/** Failures that are routine, not lessons. */
|
|
19
|
+
const ROUTINE_PATTERNS = [
|
|
20
|
+
/user (?:doesn't|does not) want|denied by (?:the )?user|user (?:rejected|declined|denied)|permission (?:denied|to use)|was blocked by (?:a )?hook/i,
|
|
21
|
+
/\bno (?:matches|files|results) found\b/i,
|
|
22
|
+
];
|
|
23
|
+
/** Shell commands whose exit code 1 means "nothing found" or "differs", not an error. */
|
|
24
|
+
const QUIET_EXIT_1 = /^\s*(?:grep|rg|egrep|fgrep|find|test|\[|diff|cmp|git diff|git grep)\b/;
|
|
25
|
+
function isString(v) {
|
|
26
|
+
return v !== undefined && v !== null && v.constructor === String;
|
|
27
|
+
}
|
|
28
|
+
function isObject(v) {
|
|
29
|
+
return v !== undefined && v !== null && !Array.isArray(v) && v.constructor === Object;
|
|
30
|
+
}
|
|
31
|
+
/** Normalised form used to spot repeats of the same failure. */
|
|
32
|
+
export function failureSignature(text) {
|
|
33
|
+
return text.toLowerCase().replace(/[0-9a-f]{7,}/g, '#').replace(/\d+/g, '#').replace(/\s+/g, ' ').trim();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The memory text for a failure payload, or the reason it is not stored.
|
|
37
|
+
* Pure: no store access.
|
|
38
|
+
*/
|
|
39
|
+
export function lessonFromFailure(payload) {
|
|
40
|
+
if (!isObject(payload))
|
|
41
|
+
return { skip: 'skipped-invalid' };
|
|
42
|
+
// SAFETY: isObject narrowed payload to a plain JSON object; the fields read are all optional.
|
|
43
|
+
const p = payload;
|
|
44
|
+
if (p.is_interrupt === true)
|
|
45
|
+
return { skip: 'skipped-interrupt' };
|
|
46
|
+
if (!isString(p.error) || p.error.trim().length < 12)
|
|
47
|
+
return { skip: 'skipped-invalid' };
|
|
48
|
+
const tool = isString(p.tool_name) ? p.tool_name : 'tool';
|
|
49
|
+
const error = p.error.replace(/\s+/g, ' ').trim();
|
|
50
|
+
if (ROUTINE_PATTERNS.some((re) => re.test(error)))
|
|
51
|
+
return { skip: 'skipped-routine' };
|
|
52
|
+
if (tool === 'Grep' || tool === 'Glob')
|
|
53
|
+
return { skip: 'skipped-routine' };
|
|
54
|
+
if (tool === 'Bash' && isObject(p.tool_input) && isString(p.tool_input['command'])
|
|
55
|
+
&& QUIET_EXIT_1.test(p.tool_input['command']) && /exit code 1\b/i.test(error)) {
|
|
56
|
+
return { skip: 'skipped-routine' };
|
|
57
|
+
}
|
|
58
|
+
return { text: `${tool}: ${error}`.slice(0, MAX_LEN) };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Store a failure payload as an error memory unless it is routine or a
|
|
62
|
+
* repeat of an auto-captured error already in the store.
|
|
63
|
+
*/
|
|
64
|
+
export function captureToolFailure(hippoRoot, tenantId, payload) {
|
|
65
|
+
const lesson = lessonFromFailure(payload);
|
|
66
|
+
if ('skip' in lesson)
|
|
67
|
+
return lesson.skip;
|
|
68
|
+
const sig = failureSignature(lesson.text);
|
|
69
|
+
const repeat = loadAllEntries(hippoRoot, tenantId).some((e) => e.tags.includes('auto-captured') && failureSignature(e.content) === sig);
|
|
70
|
+
if (repeat)
|
|
71
|
+
return 'duplicate';
|
|
72
|
+
const entry = createMemory(lesson.text, {
|
|
73
|
+
tags: ['error', 'auto-captured'],
|
|
74
|
+
source: 'tool-failure',
|
|
75
|
+
confidence: 'observed',
|
|
76
|
+
tenantId,
|
|
77
|
+
baseHalfLifeDays: loadConfig(hippoRoot).defaultHalfLifeDays,
|
|
78
|
+
});
|
|
79
|
+
writeEntry(hippoRoot, entry);
|
|
80
|
+
return 'stored';
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=capture-error.js.map
|
package/dist/capture.d.ts
CHANGED
|
@@ -45,14 +45,6 @@ export interface CaptureOptions {
|
|
|
45
45
|
*/
|
|
46
46
|
tenantId?: string;
|
|
47
47
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Build a compact text summary from a Claude Code / OpenCode JSONL transcript.
|
|
50
|
-
* Keeps plain user messages and the final chunk of assistant text, drops
|
|
51
|
-
* thinking blocks, tool_use, and tool_result noise. Output is fed to the
|
|
52
|
-
* existing `extractFromText` pipeline.
|
|
53
|
-
*
|
|
54
|
-
* Exported for tests.
|
|
55
|
-
*/
|
|
56
48
|
export declare function summariseTranscript(jsonl: string): string;
|
|
57
49
|
/**
|
|
58
50
|
* Resolve a transcript path for `--last-session`.
|
|
@@ -111,6 +103,24 @@ export declare function readTranscriptTail(transcriptPath: string, capBytes?: nu
|
|
|
111
103
|
* guard, not per-file copies.
|
|
112
104
|
*/
|
|
113
105
|
export declare function sanitizeLogMessage(message: string): string;
|
|
106
|
+
/** What one pre-compact run saved, reported to the user after compaction. */
|
|
107
|
+
export interface PreCompactReport {
|
|
108
|
+
snapshotSaved: boolean;
|
|
109
|
+
captured: number;
|
|
110
|
+
/** Claude Code session the run belonged to, when the payload named one. */
|
|
111
|
+
sessionId: string | null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The line shown to the user after compaction, or null when nothing was
|
|
115
|
+
* saved. Without it the only sign was Claude Code's generic
|
|
116
|
+
* "PreCompact [...] completed successfully".
|
|
117
|
+
*/
|
|
118
|
+
export declare function preCompactMessage(report: Pick<PreCompactReport, 'snapshotSaved' | 'captured'>): string | null;
|
|
119
|
+
/**
|
|
120
|
+
* Where pre-compact leaves its report for `hippo post-compact`: next to the
|
|
121
|
+
* pre-compact log, so both hooks find it from the same `--log-file`.
|
|
122
|
+
*/
|
|
123
|
+
export declare function preCompactReportPath(logFile: string): string;
|
|
114
124
|
export interface PreCompactOptions {
|
|
115
125
|
stdinText?: string;
|
|
116
126
|
stdinTimedOut?: boolean;
|
|
@@ -124,4 +134,11 @@ export interface PreCompactOptions {
|
|
|
124
134
|
* could turn a caught-and-logged failure back into a non-zero exit.
|
|
125
135
|
*/
|
|
126
136
|
export declare function cmdPreCompact(hippoRoot: string, options: PreCompactOptions): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* The message for the PostCompact hook, from the report pre-compact left,
|
|
139
|
+
* or null when there is nothing to say. Consumes the report, so the message
|
|
140
|
+
* shows once. A report from another session, or an old one, is dropped.
|
|
141
|
+
* Never throws.
|
|
142
|
+
*/
|
|
143
|
+
export declare function postCompactMessage(stdinText: string | undefined, logFile?: string, now?: Date): string | null;
|
|
127
144
|
//# sourceMappingURL=capture.d.ts.map
|
package/dist/capture.js
CHANGED
|
@@ -21,6 +21,7 @@ import { defaultPreCompactLogPath } from './hooks.js';
|
|
|
21
21
|
import { redactSecrets } from './secret-detect.js';
|
|
22
22
|
import { RejectedValueError, checkRejectionGuard } from './rejection.js';
|
|
23
23
|
import { openHippoDb, closeHippoDb } from './db.js';
|
|
24
|
+
import { loadConfig } from './config.js';
|
|
24
25
|
// Sentence-level patterns
|
|
25
26
|
//
|
|
26
27
|
// T1 (DF2): each pattern now carries TWO capture groups — group 1 is the
|
|
@@ -489,6 +490,7 @@ function writeExtractedItems(hippoRoot, tenantId, extracted) {
|
|
|
489
490
|
let captured = 0;
|
|
490
491
|
let skipped = 0;
|
|
491
492
|
let rejected = 0;
|
|
493
|
+
const baseHalfLifeDays = loadConfig(hippoRoot).defaultHalfLifeDays;
|
|
492
494
|
for (const item of extracted) {
|
|
493
495
|
if (isDuplicate(item.content, existing)) {
|
|
494
496
|
skipped++;
|
|
@@ -500,6 +502,7 @@ function writeExtractedItems(hippoRoot, tenantId, extracted) {
|
|
|
500
502
|
source: 'capture',
|
|
501
503
|
confidence: 'observed',
|
|
502
504
|
tenantId,
|
|
505
|
+
baseHalfLifeDays,
|
|
503
506
|
});
|
|
504
507
|
// AT1 (plan §3 containment): a refusal is per-VALUE — one rejected
|
|
505
508
|
// extraction must not abort the rest of this transcript's captures.
|
|
@@ -551,6 +554,14 @@ function errorMessage(cause) {
|
|
|
551
554
|
*
|
|
552
555
|
* Exported for tests.
|
|
553
556
|
*/
|
|
557
|
+
/** Leading markers of the command lines Claude Code writes with type 'user'. */
|
|
558
|
+
const CLAUDE_CODE_COMMAND_PREFIXES = ['<local-command-', '<command-name>', '<command-message>', '<command-args>'];
|
|
559
|
+
function isNonHumanUserLine(entry, content) {
|
|
560
|
+
if (entry.isMeta === true || entry.isSidechain === true || entry.isCompactSummary === true)
|
|
561
|
+
return true;
|
|
562
|
+
const head = content.trimStart();
|
|
563
|
+
return CLAUDE_CODE_COMMAND_PREFIXES.some((p) => head.startsWith(p));
|
|
564
|
+
}
|
|
554
565
|
export function summariseTranscript(jsonl) {
|
|
555
566
|
const lines = jsonl.split('\n').filter((l) => l.trim());
|
|
556
567
|
const userMessages = [];
|
|
@@ -571,8 +582,9 @@ export function summariseTranscript(jsonl) {
|
|
|
571
582
|
continue;
|
|
572
583
|
const content = 'content' in message ? message.content : undefined;
|
|
573
584
|
if (entry.type === 'user') {
|
|
574
|
-
// Plain text user messages only (skip tool_result arrays)
|
|
575
|
-
|
|
585
|
+
// Plain text user messages only (skip tool_result arrays), and only
|
|
586
|
+
// ones the human wrote (see isNonHumanUserLine).
|
|
587
|
+
if (isStringValue(content) && content.trim() && !isNonHumanUserLine(entry, content)) {
|
|
576
588
|
userMessages.push(content.trim());
|
|
577
589
|
}
|
|
578
590
|
}
|
|
@@ -1030,7 +1042,7 @@ function lastPlainUserMessage(jsonl) {
|
|
|
1030
1042
|
if (!message)
|
|
1031
1043
|
continue;
|
|
1032
1044
|
const content = 'content' in message ? message.content : undefined;
|
|
1033
|
-
if (isStringValue(content) && content.trim())
|
|
1045
|
+
if (isStringValue(content) && content.trim() && !isNonHumanUserLine(entry, content))
|
|
1034
1046
|
return content.trim();
|
|
1035
1047
|
}
|
|
1036
1048
|
return '';
|
|
@@ -1109,12 +1121,34 @@ function isReadableFile(filePath) {
|
|
|
1109
1121
|
return false;
|
|
1110
1122
|
}
|
|
1111
1123
|
}
|
|
1124
|
+
/**
|
|
1125
|
+
* The line shown to the user after compaction, or null when nothing was
|
|
1126
|
+
* saved. Without it the only sign was Claude Code's generic
|
|
1127
|
+
* "PreCompact [...] completed successfully".
|
|
1128
|
+
*/
|
|
1129
|
+
export function preCompactMessage(report) {
|
|
1130
|
+
if (!report.snapshotSaved && report.captured === 0)
|
|
1131
|
+
return null;
|
|
1132
|
+
const parts = [];
|
|
1133
|
+
if (report.snapshotSaved)
|
|
1134
|
+
parts.push('your task snapshot');
|
|
1135
|
+
if (report.captured > 0)
|
|
1136
|
+
parts.push(`${report.captured} new memor${report.captured === 1 ? 'y' : 'ies'}`);
|
|
1137
|
+
return `Hippo saved ${parts.join(' and ')} before compacting.${report.snapshotSaved ? ' The snapshot is restored into the new context.' : ''}`;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Where pre-compact leaves its report for `hippo post-compact`: next to the
|
|
1141
|
+
* pre-compact log, so both hooks find it from the same `--log-file`.
|
|
1142
|
+
*/
|
|
1143
|
+
export function preCompactReportPath(logFile) {
|
|
1144
|
+
return path.join(path.dirname(logFile), 'pre-compact-last.json');
|
|
1145
|
+
}
|
|
1112
1146
|
/**
|
|
1113
1147
|
* Runs the PreCompact producer. Returns any `embedMemory` promises kicked
|
|
1114
1148
|
* off along the way (empty on every skip path) so `cmdPreCompact` can await
|
|
1115
1149
|
* them, bounded, before it exits (X6).
|
|
1116
1150
|
*/
|
|
1117
|
-
function runPreCompact(hippoRoot, stdinText, stdinTimedOut, logFile) {
|
|
1151
|
+
function runPreCompact(hippoRoot, stdinText, stdinTimedOut, logFile, report) {
|
|
1118
1152
|
// X3: the PreCompact hook fires in every Claude Code project, including
|
|
1119
1153
|
// ones that never ran `hippo init`, so gate before any store-opening call
|
|
1120
1154
|
// (saveActiveTaskSnapshot etc. call initStore, which would create one).
|
|
@@ -1156,6 +1190,7 @@ function runPreCompact(hippoRoot, stdinText, stdinTimedOut, logFile) {
|
|
|
1156
1190
|
}
|
|
1157
1191
|
if ('session_id' in payload && isStringValue(payload.session_id))
|
|
1158
1192
|
sessionId = payload.session_id;
|
|
1193
|
+
report.sessionId = sessionId;
|
|
1159
1194
|
payloadTranscriptPath = payload.transcript_path;
|
|
1160
1195
|
}
|
|
1161
1196
|
// X11: payload transcript_path must end .jsonl. No directory-containment
|
|
@@ -1291,6 +1326,7 @@ function runPreCompact(hippoRoot, stdinText, stdinTimedOut, logFile) {
|
|
|
1291
1326
|
session_id: sessionId,
|
|
1292
1327
|
});
|
|
1293
1328
|
appendPreCompactLog(logFile, 'snapshot saved');
|
|
1329
|
+
report.snapshotSaved = true;
|
|
1294
1330
|
}
|
|
1295
1331
|
catch (err) {
|
|
1296
1332
|
appendPreCompactLog(logFile, `snapshot save failed: ${errorMessage(err)}`);
|
|
@@ -1300,6 +1336,7 @@ function runPreCompact(hippoRoot, stdinText, stdinTimedOut, logFile) {
|
|
|
1300
1336
|
// the next SessionEnd capture (existing dedup absorbs the overlap).
|
|
1301
1337
|
try {
|
|
1302
1338
|
const { captured, skipped, rejected, embeds } = writeExtractedItems(hippoRoot, tenantId, extracted);
|
|
1339
|
+
report.captured = captured;
|
|
1303
1340
|
appendPreCompactLog(logFile, `capture: ${captured} items captured, ${skipped} skipped` +
|
|
1304
1341
|
(rejected > 0 ? `, ${rejected} rejected` : ''));
|
|
1305
1342
|
return embeds;
|
|
@@ -1324,8 +1361,9 @@ const EMBED_SETTLE_TIMEOUT_MS = 3000;
|
|
|
1324
1361
|
export async function cmdPreCompact(hippoRoot, options) {
|
|
1325
1362
|
const logFile = options.logFile ?? defaultPreCompactLogPath();
|
|
1326
1363
|
let embeds = [];
|
|
1364
|
+
const report = { snapshotSaved: false, captured: 0, sessionId: null };
|
|
1327
1365
|
try {
|
|
1328
|
-
embeds = runPreCompact(hippoRoot, options.stdinText, options.stdinTimedOut ?? false, logFile);
|
|
1366
|
+
embeds = runPreCompact(hippoRoot, options.stdinText, options.stdinTimedOut ?? false, logFile, report);
|
|
1329
1367
|
}
|
|
1330
1368
|
catch (err) {
|
|
1331
1369
|
appendPreCompactLog(logFile, `pre-compact failed: ${errorMessage(err)}`);
|
|
@@ -1341,6 +1379,63 @@ export async function cmdPreCompact(hippoRoot, options) {
|
|
|
1341
1379
|
clearTimeout(timer);
|
|
1342
1380
|
appendPreCompactLog(logFile, outcome === 'settled' ? 'embeddings settled' : 'embeddings timeout');
|
|
1343
1381
|
}
|
|
1382
|
+
// Nothing goes to stdout: Claude Code passes PreCompact stdout to the
|
|
1383
|
+
// summarising model as extra instructions. The PostCompact hook
|
|
1384
|
+
// (`hippo post-compact`) tells the user instead, from this report.
|
|
1385
|
+
if (report.snapshotSaved || report.captured > 0) {
|
|
1386
|
+
try {
|
|
1387
|
+
fs.writeFileSync(preCompactReportPath(logFile), JSON.stringify({ ...report, at: new Date().toISOString() }));
|
|
1388
|
+
}
|
|
1389
|
+
catch {
|
|
1390
|
+
// Losing the message must never fail the hook.
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1344
1393
|
process.exit(0);
|
|
1345
1394
|
}
|
|
1395
|
+
/** How old a pre-compact report may be and still describe this compaction. */
|
|
1396
|
+
const POST_COMPACT_REPORT_MAX_AGE_MS = 10 * 60_000;
|
|
1397
|
+
/**
|
|
1398
|
+
* The message for the PostCompact hook, from the report pre-compact left,
|
|
1399
|
+
* or null when there is nothing to say. Consumes the report, so the message
|
|
1400
|
+
* shows once. A report from another session, or an old one, is dropped.
|
|
1401
|
+
* Never throws.
|
|
1402
|
+
*/
|
|
1403
|
+
export function postCompactMessage(stdinText, logFile = defaultPreCompactLogPath(), now = new Date()) {
|
|
1404
|
+
const reportFile = preCompactReportPath(logFile);
|
|
1405
|
+
let raw;
|
|
1406
|
+
try {
|
|
1407
|
+
raw = fs.readFileSync(reportFile, 'utf8');
|
|
1408
|
+
fs.rmSync(reportFile, { force: true });
|
|
1409
|
+
}
|
|
1410
|
+
catch {
|
|
1411
|
+
return null;
|
|
1412
|
+
}
|
|
1413
|
+
try {
|
|
1414
|
+
const report = JSON.parse(raw);
|
|
1415
|
+
if (!isObjectLike(report))
|
|
1416
|
+
return null;
|
|
1417
|
+
const at = 'at' in report && isStringValue(report.at) ? Date.parse(report.at) : Number.NaN;
|
|
1418
|
+
if (Number.isNaN(at) || now.getTime() - at > POST_COMPACT_REPORT_MAX_AGE_MS)
|
|
1419
|
+
return null;
|
|
1420
|
+
let payloadSession = null;
|
|
1421
|
+
try {
|
|
1422
|
+
const payload = JSON.parse((stdinText ?? '').trim() || 'null');
|
|
1423
|
+
if (isObjectLike(payload) && 'session_id' in payload && isStringValue(payload.session_id))
|
|
1424
|
+
payloadSession = payload.session_id;
|
|
1425
|
+
}
|
|
1426
|
+
catch {
|
|
1427
|
+
// No usable payload: fall back to the age check alone.
|
|
1428
|
+
}
|
|
1429
|
+
const reportSession = 'sessionId' in report && isStringValue(report.sessionId) ? report.sessionId : null;
|
|
1430
|
+
if (payloadSession !== null && reportSession !== null && payloadSession !== reportSession)
|
|
1431
|
+
return null;
|
|
1432
|
+
return preCompactMessage({
|
|
1433
|
+
snapshotSaved: 'snapshotSaved' in report && report.snapshotSaved === true,
|
|
1434
|
+
captured: 'captured' in report && Number.isInteger(report.captured) ? Number(report.captured) : 0,
|
|
1435
|
+
});
|
|
1436
|
+
}
|
|
1437
|
+
catch {
|
|
1438
|
+
return null;
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1346
1441
|
//# sourceMappingURL=capture.js.map
|
package/dist/cli.d.ts
CHANGED
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
* hippo reject <id>|--value "<text>" --reason "<why>"
|
|
20
20
|
* hippo rejections
|
|
21
21
|
* hippo unreject <digest-prefix>
|
|
22
|
+
* hippo dormant [<query>] [--limit <n>] [--json] | restore <id> | forget <id>
|
|
23
|
+
* hippo tokens [--days <n>] [--json] [--global]
|
|
24
|
+
* hippo doctor [--json]
|
|
22
25
|
* hippo inspect <id>
|
|
23
26
|
* hippo embed [--status]
|
|
24
27
|
* hippo watch "<command>"
|
|
@@ -58,6 +61,8 @@ export declare function printContextMarkdown(items: Array<{
|
|
|
58
61
|
score: number;
|
|
59
62
|
tokens: number;
|
|
60
63
|
isGlobal: boolean;
|
|
61
|
-
}>, totalTokens: number, framing?: string
|
|
64
|
+
}>, totalTokens: number, framing?: string, opts?: {
|
|
65
|
+
showStrength?: boolean;
|
|
66
|
+
}): void;
|
|
62
67
|
export declare function runCli(argv?: string[]): Promise<void>;
|
|
63
68
|
//# sourceMappingURL=cli.d.ts.map
|