hippo-memory 1.56.0 → 1.58.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 (129) hide show
  1. package/README.md +11 -0
  2. package/dist/agent-memories/claude-code.js +1 -1
  3. package/dist/agent-memories/gemini.js +1 -1
  4. package/dist/api-errors.d.ts +27 -0
  5. package/dist/api-errors.js +37 -0
  6. package/dist/api.d.ts +21 -14
  7. package/dist/api.js +97 -71
  8. package/dist/audit.d.ts +4 -0
  9. package/dist/audit.js +11 -0
  10. package/dist/autolearn.d.ts +1 -1
  11. package/dist/autolearn.js +7 -5
  12. package/dist/capture-contract.d.ts +47 -0
  13. package/dist/capture-contract.js +49 -0
  14. package/dist/capture-error.js +2 -1
  15. package/dist/capture.d.ts +0 -13
  16. package/dist/capture.js +5 -66
  17. package/dist/card-detail.d.ts +1 -1
  18. package/dist/card-detail.js +1 -1
  19. package/dist/cli/shared.d.ts +137 -0
  20. package/dist/cli/shared.js +834 -0
  21. package/dist/cli/sleep.d.ts +10 -0
  22. package/dist/cli/sleep.js +171 -0
  23. package/dist/cli.d.ts +0 -7
  24. package/dist/cli.js +322 -1827
  25. package/dist/client.js +9 -0
  26. package/dist/codex-patch.js +1 -1
  27. package/dist/compaction-record.d.ts +1 -1
  28. package/dist/compaction-record.js +3 -2
  29. package/dist/config.d.ts +5 -0
  30. package/dist/config.js +17 -0
  31. package/dist/connectors/github/dlq.js +5 -2
  32. package/dist/connectors/github/octokit-client.js +4 -2
  33. package/dist/connectors/github/webhook.d.ts +19 -0
  34. package/dist/connectors/github/webhook.js +313 -0
  35. package/dist/connectors/slack/dlq.js +6 -2
  36. package/dist/connectors/slack/web-client.js +7 -5
  37. package/dist/connectors/slack/webhook.d.ts +22 -0
  38. package/dist/connectors/slack/webhook.js +203 -0
  39. package/dist/consolidate.d.ts +10 -0
  40. package/dist/consolidate.js +38 -35
  41. package/dist/context-auto.d.ts +3 -0
  42. package/dist/context-auto.js +34 -0
  43. package/dist/customer-notes.js +16 -14
  44. package/dist/dag.js +3 -2
  45. package/dist/dashboard.js +3 -2
  46. package/dist/db.d.ts +12 -0
  47. package/dist/db.js +62 -1
  48. package/dist/decisions.js +11 -9
  49. package/dist/doctor.js +5 -0
  50. package/dist/embedding-provider.js +3 -3
  51. package/dist/embeddings.d.ts +4 -4
  52. package/dist/embeddings.js +72 -16
  53. package/dist/eval-stats.d.ts +58 -0
  54. package/dist/eval-stats.js +111 -0
  55. package/dist/extract.js +3 -2
  56. package/dist/goals.d.ts +49 -25
  57. package/dist/goals.js +39 -22
  58. package/dist/graph-extract.js +1 -1
  59. package/dist/graph-recall.d.ts +1 -1
  60. package/dist/graph-recall.js +1 -1
  61. package/dist/graph.js +1 -1
  62. package/dist/hooks.d.ts +1 -3
  63. package/dist/hooks.js +2 -4
  64. package/dist/http-retry.d.ts +21 -0
  65. package/dist/http-retry.js +50 -0
  66. package/dist/http-util.d.ts +39 -0
  67. package/dist/http-util.js +56 -0
  68. package/dist/importers.d.ts +2 -0
  69. package/dist/importers.js +16 -5
  70. package/dist/incidents.js +13 -11
  71. package/dist/index.d.ts +5 -2
  72. package/dist/index.js +5 -2
  73. package/dist/judgment.js +10 -17
  74. package/dist/log.d.ts +25 -0
  75. package/dist/log.js +48 -0
  76. package/dist/mcp/server.js +224 -308
  77. package/dist/mcp/tool-args.d.ts +21 -0
  78. package/dist/mcp/tool-args.js +80 -0
  79. package/dist/memory.d.ts +19 -0
  80. package/dist/memory.js +41 -2
  81. package/dist/overlap-index.d.ts +7 -0
  82. package/dist/overlap-index.js +38 -0
  83. package/dist/pilot-arm.d.ts +9 -0
  84. package/dist/pilot-arm.js +47 -0
  85. package/dist/policies.js +14 -12
  86. package/dist/predictions.js +11 -9
  87. package/dist/processes.js +16 -14
  88. package/dist/project-briefs.js +19 -16
  89. package/dist/project-identity.d.ts +1 -1
  90. package/dist/project-identity.js +25 -1
  91. package/dist/prompt-recall.js +1 -1
  92. package/dist/raw-archive.js +7 -6
  93. package/dist/recall-history.d.ts +5 -0
  94. package/dist/recall-history.js +9 -0
  95. package/dist/recall-pipeline.d.ts +101 -0
  96. package/dist/recall-pipeline.js +313 -0
  97. package/dist/recall-scope.d.ts +24 -1
  98. package/dist/recall-scope.js +29 -2
  99. package/dist/refine-llm.js +3 -2
  100. package/dist/reject-flow.js +6 -9
  101. package/dist/rejection.d.ts +2 -1
  102. package/dist/rejection.js +2 -1
  103. package/dist/search.d.ts +0 -20
  104. package/dist/search.js +16 -51
  105. package/dist/secret-detect.d.ts +13 -1
  106. package/dist/secret-detect.js +33 -1
  107. package/dist/server.d.ts +3 -1
  108. package/dist/server.js +1854 -2566
  109. package/dist/session-digest.js +2 -1
  110. package/dist/shared.js +7 -6
  111. package/dist/skills.js +17 -15
  112. package/dist/store-cards.d.ts +53 -0
  113. package/dist/store-cards.js +512 -0
  114. package/dist/store.d.ts +2 -89
  115. package/dist/store.js +10 -566
  116. package/dist/tenant.d.ts +22 -0
  117. package/dist/tenant.js +26 -0
  118. package/dist/token-ledger.d.ts +4 -2
  119. package/dist/token-ledger.js +2 -2
  120. package/dist/tokenize.d.ts +2 -0
  121. package/dist/tokenize.js +8 -0
  122. package/dist/version.d.ts +1 -1
  123. package/dist/version.js +1 -1
  124. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  125. package/extensions/openclaw-plugin/package.json +1 -1
  126. package/openclaw.plugin.json +1 -1
  127. package/package.json +1 -1
  128. package/dist/connectors/slack/ratelimit.d.ts +0 -9
  129. package/dist/connectors/slack/ratelimit.js +0 -18
@@ -7,6 +7,7 @@ import { loadConfig } from './config.js';
7
7
  import { closeHippoDb, openHippoDb } from './db.js';
8
8
  import { recordFailure } from './failure-log.js';
9
9
  import { blockHash } from './token-ledger.js';
10
+ import { redactSecretsStrict } from './secret-detect.js';
10
11
  const MAX_LEN = 200;
11
12
  /** The user, a permission prompt or a hook said no: routine, not a lesson. */
12
13
  const DECLINED = /user (?:doesn't|does not) want|denied by (?:the )?user|user (?:rejected|declined|denied)|permission to use|was blocked by (?:a )?hook/i;
@@ -44,7 +45,7 @@ export function lessonFromFailure(payload) {
44
45
  if (!isString(p.error) || p.error.trim().length < 12)
45
46
  return { skip: 'skipped-invalid', text: null, detail: null };
46
47
  const tool = isString(p.tool_name) ? p.tool_name : 'tool';
47
- const error = p.error.replace(/\s+/g, ' ').trim();
48
+ const error = redactSecretsStrict(p.error.replace(/\s+/g, ' ').trim());
48
49
  const text = `${tool}: ${error}`.slice(0, MAX_LEN);
49
50
  const command = isObject(p.tool_input) && isString(p.tool_input['command']) ? p.tool_input['command'].replace(LEADING_CD, '') : '';
50
51
  const head = command.trim().split(/\s+/).slice(0, 2).join(' ');
package/dist/capture.d.ts CHANGED
@@ -49,19 +49,6 @@ export interface CaptureOptions {
49
49
  tenantId?: string;
50
50
  originProject?: string;
51
51
  }
52
- /**
53
- * Runtime shape guards used throughout this file wherever a value arrives
54
- * unparsed (JSONL transcript records, stdout/stderr write() chunks). Generic
55
- * over the input so the parameter is never annotated `unknown` directly — TS
56
- * infers it from the call site — while the check itself avoids `typeof` by
57
- * testing identity against the coercion (`String(x) === x`) /
58
- * prototype-chain (`instanceof Object`) instead. Behaviourally equivalent to
59
- * `typeof x === 'string'` / a truthy `typeof x === 'object'` check for
60
- * anything `JSON.parse` can produce (the only divergence is boxed
61
- * primitives, which JSON.parse never yields).
62
- */
63
- export declare function isStringValue<T>(value: T): value is T & string;
64
- export declare function isObjectLike<T>(value: T): value is T & object;
65
52
  /** Message for a caught value of unknown shape. `cause` names the sanctioned unknown-input case (error-cause enrichment). */
66
53
  export declare function errorMessage(cause: unknown): string;
67
54
  /** Transcript-line flags isNonHumanUserLine reads (any may be absent); `promptSource: 'system'` marks Claude Code's own notices. */
package/dist/capture.js CHANGED
@@ -25,6 +25,7 @@ import { RejectedValueError, checkRejectionGuard } from './rejection.js';
25
25
  import { openHippoDb, closeHippoDb } from './db.js';
26
26
  import { loadConfig } from './config.js';
27
27
  import { classifyOriginProject } from './project-identity.js';
28
+ import { isObjectLike, isStringValue, readClaudeCodePreCompact } from './capture-contract.js';
28
29
  // Sentence-level patterns
29
30
  //
30
31
  // T1 (DF2): each pattern now carries TWO capture groups — group 1 is the
@@ -471,23 +472,6 @@ export function extractFromText(text) {
471
472
  }
472
473
  return items;
473
474
  }
474
- /**
475
- * Runtime shape guards used throughout this file wherever a value arrives
476
- * unparsed (JSONL transcript records, stdout/stderr write() chunks). Generic
477
- * over the input so the parameter is never annotated `unknown` directly — TS
478
- * infers it from the call site — while the check itself avoids `typeof` by
479
- * testing identity against the coercion (`String(x) === x`) /
480
- * prototype-chain (`instanceof Object`) instead. Behaviourally equivalent to
481
- * `typeof x === 'string'` / a truthy `typeof x === 'object'` check for
482
- * anything `JSON.parse` can produce (the only divergence is boxed
483
- * primitives, which JSON.parse never yields).
484
- */
485
- export function isStringValue(value) {
486
- return String(value) === value;
487
- }
488
- export function isObjectLike(value) {
489
- return value !== null && value instanceof Object;
490
- }
491
475
  /** Message for a caught value of unknown shape. `cause` names the sanctioned unknown-input case (error-cause enrichment). */
492
476
  export function errorMessage(cause) {
493
477
  return cause instanceof Error ? cause.message : String(cause);
@@ -1161,57 +1145,12 @@ function runPreCompact(hippoRoot, stdinText, stdinTimedOut, logFile) {
1161
1145
  appendPreCompactLog(logFile, 'skip: store not initialized');
1162
1146
  return;
1163
1147
  }
1164
- // Same hazard X4 guards below, different trigger: a read that timed out
1165
- // must not reach auto-discovery either, or it snapshots another session.
1166
- if (stdinTimedOut && (!stdinText || stdinText.trim() === '')) {
1167
- appendPreCompactLog(logFile, 'skip: no PreCompact payload arrived before the stdin wait window closed');
1168
- return;
1169
- }
1170
- // A true manual invocation has no stdin at all (TTY, or a non-TTY pipe
1171
- // that yielded an empty read) — that's the ONLY case newest-transcript
1172
- // auto-discovery is allowed to run. Any other non-empty stdin must
1173
- // JSON-parse to an object carrying a string transcript_path, or it is
1174
- // treated as malformed input and skipped (X4) rather than silently
1175
- // falling back to discovery, which could snapshot an unrelated session's
1176
- // transcript under this payload's session_id.
1177
- const manualInvocation = !stdinText || stdinText.trim() === '';
1178
- let sessionId = null;
1179
- let payloadTranscriptPath = null;
1180
- let payloadCwd = null;
1181
- let payloadTrigger = null;
1182
- if (!manualInvocation) {
1183
- let payload;
1184
- try {
1185
- payload = JSON.parse(stdinText.trim());
1186
- }
1187
- catch {
1188
- // payload stays undefined; the isObjectLike check below rejects it
1189
- // the same way it would reject an explicit null.
1190
- }
1191
- if (!isObjectLike(payload) || !('transcript_path' in payload) || !isStringValue(payload.transcript_path)) {
1192
- // Covers non-JSON stdin, a JSON value that isn't an object, and
1193
- // `"transcript_path": null` (or the key missing entirely) — all fail
1194
- // the string check. Log and skip; never fall through to auto-discovery.
1195
- appendPreCompactLog(logFile, 'skip: malformed or incomplete PreCompact payload (missing string transcript_path)');
1196
- return;
1197
- }
1198
- if ('session_id' in payload && isStringValue(payload.session_id))
1199
- sessionId = payload.session_id;
1200
- payloadTranscriptPath = payload.transcript_path;
1201
- payloadCwd = 'cwd' in payload && isStringValue(payload.cwd) ? payload.cwd : null;
1202
- payloadTrigger = 'trigger' in payload && isStringValue(payload.trigger) ? payload.trigger : null;
1203
- }
1204
- // X11: payload transcript_path must end .jsonl. No directory-containment
1205
- // check is applied on top of this — CLAUDE_CONFIG_DIR can relocate the
1206
- // transcript root entirely, so a path-prefix allowlist would just reject
1207
- // legitimate relocated installs. The trust boundary here is process
1208
- // identity, not path shape: a local process able to feed this hook
1209
- // arbitrary stdin already runs as the same user who owns every transcript
1210
- // this check could gate on, so containment buys no real isolation.
1211
- if (payloadTranscriptPath !== null && !/\.jsonl$/i.test(payloadTranscriptPath)) {
1212
- appendPreCompactLog(logFile, `skip: payload transcript_path is not a .jsonl file: ${payloadTranscriptPath}`);
1148
+ const receipt = readClaudeCodePreCompact(stdinText, stdinTimedOut);
1149
+ if (receipt.status !== 'received') {
1150
+ appendPreCompactLog(logFile, `skip: ${receipt.reason}`);
1213
1151
  return;
1214
1152
  }
1153
+ const { sessionId, transcriptPath: payloadTranscriptPath, cwd: payloadCwd, trigger: payloadTrigger } = receipt.input;
1215
1154
  // The record is the "something saved before every compaction", so it lands even when no snapshot is derivable below.
1216
1155
  let recordId = null;
1217
1156
  if (sessionId !== null && sessionId !== '') {
@@ -1,6 +1,6 @@
1
1
  import type { Card, CardComment, CardRun } from './card.js';
2
2
  import type { SessionHandoff } from './handoff.js';
3
- import { loadCardDeps } from './store.js';
3
+ import { loadCardDeps } from './store-cards.js';
4
4
  /** A card plus everything `hippo card show` prints about it. */
5
5
  export interface CardDetail {
6
6
  card: Card;
@@ -1,4 +1,4 @@
1
- import { loadCard, loadCardComments, loadCardDeps, loadCardRuns, loadLatestHandoffForCard } from './store.js';
1
+ import { loadCard, loadCardComments, loadCardDeps, loadCardRuns, loadLatestHandoffForCard } from './store-cards.js';
2
2
  /** Loads the detail behind `hippo card show` and `GET /api/cards/:id` (null when the tenant has no such card); five separate reads, so a write landing between them can show a mixed view, as `card show` always could. */
3
3
  export function loadCardDetail(hippoRoot, tenantId, id) {
4
4
  const card = loadCard(hippoRoot, tenantId, id);
@@ -0,0 +1,137 @@
1
+ import { TaskSnapshot, SessionEvent } from '../store.js';
2
+ import type { HandoffEvidence, SessionHandoff } from '../handoff.js';
3
+ import { type SearchResult } from '../search.js';
4
+ import { type HippoConfig } from '../config.js';
5
+ import { openHippoDb } from '../db.js';
6
+ import { type ImportReport } from '../agent-memories/report.js';
7
+ import { type ChurnStaleResult } from '../invalidation.js';
8
+ import { type AuditOp } from '../audit.js';
9
+ import { type ServerInfo } from '../server-detect.js';
10
+ import type { RecallSearchOpts } from '../recall-pipeline.js';
11
+ export declare function parseLimitFlag(value: string | boolean | string[] | undefined): number;
12
+ export declare function parseCountFlag(value: string | boolean | string[] | undefined): number;
13
+ export declare function parseBudgetFlag(value: string | boolean | string[] | undefined, fallback: number): number;
14
+ /**
15
+ * Emit an audit event against `hippoRoot`'s db. Opens its own short-lived
16
+ * connection so callers don't have to thread a db handle. Swallows all errors
17
+ * — audit must never crash a CLI command.
18
+ */
19
+ export declare function emitCliAudit(hippoRoot: string, op: AuditOp, targetId?: string, metadata?: Record<string, unknown>): void;
20
+ export declare function requireInit(hippoRoot: string): void;
21
+ /** Runs detectChurnStale against every store this repo's memories can live in. */
22
+ export declare function runChurnStaleForRepo(hippoRoot: string, dryRun: boolean): {
23
+ root: string;
24
+ result: ChurnStaleResult;
25
+ }[];
26
+ /**
27
+ * Run an HTTP-routed command if a `hippo serve` instance is detected for
28
+ * `hippoRoot`. Returns:
29
+ * - true if the HTTP path ran (success OR a structured server error that
30
+ * was already surfaced to stdout/stderr by `httpFn`),
31
+ * - false if no server was detected, or if the detected pidfile turned out
32
+ * to be stale (connection refused). On stale, the pidfile is removed
33
+ * if it still names that dead server (a newer one may have replaced
34
+ * it) and the caller should fall back to the direct path.
35
+ *
36
+ * Stale pidfiles must self-heal, not crash.
37
+ * When HIPPO_REQUIRE_SERVER is set, both fallback paths throw instead of
38
+ * returning false, so a missing server fails loudly rather than silently
39
+ * degrading to direct mode.
40
+ */
41
+ export declare function runViaServerIfAvailable(hippoRoot: string, httpFn: (info: ServerInfo, apiKey: string | undefined) => Promise<void>): Promise<boolean>;
42
+ export declare function fmt(n: number, digits?: number): string;
43
+ export declare function recallEntryText(r: SearchResult, query: string, showWhy: boolean, isGlobal: boolean): string;
44
+ export declare function recallHeading(entries: number, tokens: number, query: string): string;
45
+ /** One line when an agent memory import moved anything; its warnings go to stderr. */
46
+ export declare function printAgentImport(report: ImportReport, indent?: string): void;
47
+ /** The first hippo block in `text` and the agent whose current or shipped text it is; `owner` is undefined for an edited block. */
48
+ export declare function hippoBlock(text: string): {
49
+ start: number;
50
+ end: number;
51
+ eol: string;
52
+ inner: string;
53
+ owner?: string;
54
+ } | null;
55
+ /** Adds hippo's two Codex hooks and says what changed; each install ends on the trust reminder, since Codex skips an untrusted hook. */
56
+ export declare function installCodexMemoryHooks(indent: string): void;
57
+ /**
58
+ * Set up a machine-level daily runner that sweeps all registered Hippo
59
+ * workspaces.
60
+ * Linux/macOS: writes to user crontab.
61
+ * Windows: creates a scheduled task.
62
+ * Skips if already installed.
63
+ */
64
+ export declare function setupDailySchedule(globalRoot: string): void;
65
+ export type CliFlags = Record<string, string | boolean | string[]>;
66
+ export type EngineFlags = Pick<RecallSearchOpts, 'usePhysics' | 'physicsConfig' | 'mmr' | 'mmrLambda' | 'localBump'>;
67
+ export declare function parseAsOfFlag(flags: CliFlags): string | undefined;
68
+ /** --physics forces physics, --classic forces BM25+cosine, else physics unless the config turns it off. */
69
+ export declare function engineFlags(flags: CliFlags, config: HippoConfig): EngineFlags;
70
+ /**
71
+ * Detached worker that counts re-reads, runs sleep, then capture. Invoked via the internal
72
+ * `__session-end-worker` subcommand (not user-facing). Failures in one stage
73
+ * do not block the other.
74
+ */
75
+ export declare function collectHandoffEvidence(cwd: string, testStatus: HandoffEvidence['testStatus']): HandoffEvidence;
76
+ /** A folder without its own store never sleeps at session end, so its project's agent notes go to the global store here. */
77
+ export declare function logSessionEndImport(logFile: string | null, transcriptPath: string | undefined): void;
78
+ /**
79
+ * Best-effort log line for the snapshot-close step in
80
+ * `cmdSessionEndWorker`. `cmdSleep`/`cmdCapture` each tee console output to
81
+ * `logFile` only for their own duration (the tee is restored before this
82
+ * runs), so a plain `console.log` here would be silently discarded under
83
+ * the detached worker's `stdio: 'ignore'` — write straight to the file
84
+ * instead, matching capture.ts's `appendPreCompactLog` convention.
85
+ */
86
+ export declare function appendSessionEndCloseLog(logFile: string | null, message: string, opts?: {
87
+ startFresh?: boolean;
88
+ }): void;
89
+ export declare function printActiveTaskSnapshot(snapshot: TaskSnapshot): void;
90
+ export declare function printSessionEvents(events: SessionEvent[]): void;
91
+ export declare function printHandoff(handoff: SessionHandoff): void;
92
+ export declare function cardStringFlag(flags: Record<string, string | boolean | string[]>, key: string): string | undefined;
93
+ export declare function hostSessionId(): string | undefined;
94
+ /**
95
+ * Compaction drops the pinned blocks the per-prompt hook injected
96
+ * earlier, so record a `reset` for the payload's session and the next prompt
97
+ * injects again even if nothing changed. `requiredSource` limits it to hook
98
+ * payloads with that `source` (SessionStart fires for other reasons too).
99
+ * Best-effort and silent: a malformed payload records nothing.
100
+ */
101
+ export declare function resetHookInjection(hippoRoot: string, stdinText: string | undefined, requiredSource: string | null): void;
102
+ /**
103
+ * Run `fn` with console.log captured; returns the captured lines joined by
104
+ * newlines (what the same calls would have printed, minus the final newline).
105
+ */
106
+ export declare function captureConsole(fn: () => void): string;
107
+ /**
108
+ * The store a Claude Code hook writes to: the project store when there is
109
+ * one, else an existing global store, else the project path (which the hook
110
+ * then skips, since hooks fire in every directory and must not create one).
111
+ * Pre-compact and compact-resume must agree, or a snapshot saved to one store
112
+ * is looked for in the other.
113
+ */
114
+ export declare function hookStoreRoot(hippoRoot: string): string;
115
+ /**
116
+ * Run `fn` against the token ledger's store: the local store when it is
117
+ * initialized, else the global one (the per-prompt hook runs in directories
118
+ * without a local store). Best-effort: returns undefined and never throws,
119
+ * because a ledger failure must not break context or recall.
120
+ */
121
+ export declare function withLedgerDb<T>(hippoRoot: string, fn: (db: ReturnType<typeof openHippoDb>) => T): T | undefined;
122
+ export declare function learnFromRepo(hippoRoot: string, repoPath: string, days: number, label?: string): {
123
+ added: number;
124
+ skipped: number;
125
+ lowInfo: number;
126
+ };
127
+ export declare const HOOK_MARKERS: {
128
+ start: string;
129
+ end: string;
130
+ };
131
+ export declare const HOOKS: Record<string, {
132
+ file: string;
133
+ content: string;
134
+ description: string;
135
+ }>;
136
+ export declare function resolveAuthRoot(hippoRoot: string, flags: Record<string, string | boolean | string[]>): string;
137
+ //# sourceMappingURL=shared.d.ts.map