hippo-memory 1.56.0 → 1.57.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 (67) hide show
  1. package/dist/api.d.ts +16 -9
  2. package/dist/api.js +57 -24
  3. package/dist/card-detail.d.ts +1 -1
  4. package/dist/card-detail.js +1 -1
  5. package/dist/cli/shared.d.ts +137 -0
  6. package/dist/cli/shared.js +830 -0
  7. package/dist/cli/sleep.d.ts +10 -0
  8. package/dist/cli/sleep.js +171 -0
  9. package/dist/cli.d.ts +0 -7
  10. package/dist/cli.js +223 -1789
  11. package/dist/connectors/github/webhook.d.ts +19 -0
  12. package/dist/connectors/github/webhook.js +313 -0
  13. package/dist/connectors/slack/webhook.d.ts +22 -0
  14. package/dist/connectors/slack/webhook.js +203 -0
  15. package/dist/consolidate.js +3 -2
  16. package/dist/context-auto.d.ts +3 -0
  17. package/dist/context-auto.js +34 -0
  18. package/dist/customer-notes.js +2 -1
  19. package/dist/dashboard.js +2 -1
  20. package/dist/decisions.js +2 -1
  21. package/dist/eval-stats.d.ts +58 -0
  22. package/dist/eval-stats.js +111 -0
  23. package/dist/goals.d.ts +49 -25
  24. package/dist/goals.js +39 -22
  25. package/dist/graph-extract.js +1 -1
  26. package/dist/graph-recall.d.ts +1 -1
  27. package/dist/graph-recall.js +1 -1
  28. package/dist/graph.js +1 -1
  29. package/dist/hooks.d.ts +1 -3
  30. package/dist/hooks.js +2 -4
  31. package/dist/http-util.d.ts +31 -0
  32. package/dist/http-util.js +46 -0
  33. package/dist/incidents.js +2 -1
  34. package/dist/index.d.ts +5 -2
  35. package/dist/index.js +5 -2
  36. package/dist/mcp/server.js +173 -285
  37. package/dist/memory.d.ts +19 -0
  38. package/dist/memory.js +38 -0
  39. package/dist/policies.js +2 -1
  40. package/dist/predictions.js +2 -1
  41. package/dist/processes.js +2 -1
  42. package/dist/project-briefs.js +3 -1
  43. package/dist/prompt-recall.js +1 -1
  44. package/dist/recall-history.d.ts +5 -0
  45. package/dist/recall-history.js +9 -0
  46. package/dist/recall-pipeline.d.ts +101 -0
  47. package/dist/recall-pipeline.js +313 -0
  48. package/dist/recall-scope.d.ts +22 -0
  49. package/dist/recall-scope.js +27 -1
  50. package/dist/search.d.ts +0 -20
  51. package/dist/search.js +2 -49
  52. package/dist/server.js +1901 -2384
  53. package/dist/skills.js +2 -1
  54. package/dist/store-cards.d.ts +53 -0
  55. package/dist/store-cards.js +512 -0
  56. package/dist/store.d.ts +2 -89
  57. package/dist/store.js +6 -562
  58. package/dist/tenant.d.ts +22 -0
  59. package/dist/tenant.js +26 -0
  60. package/dist/tokenize.d.ts +2 -0
  61. package/dist/tokenize.js +8 -0
  62. package/dist/version.d.ts +1 -1
  63. package/dist/version.js +1 -1
  64. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  65. package/extensions/openclaw-plugin/package.json +1 -1
  66. package/openclaw.plugin.json +1 -1
  67. package/package.json +1 -1
package/dist/api.d.ts CHANGED
@@ -19,7 +19,7 @@ import { auditMemories, type AuditEvent, type AuditOp } from './audit.js';
19
19
  import { autoShare } from './shared.js';
20
20
  import type { DeliveryObserver } from './delivery-recorder.js';
21
21
  import { type ApiKeyListItem } from './auth.js';
22
- import { type RerankStep } from './search.js';
22
+ import { type RerankStep, type SearchResult } from './search.js';
23
23
  import { consolidate } from './consolidate.js';
24
24
  import { loadConfig } from './config.js';
25
25
  import { deduplicateStore } from './dedupe.js';
@@ -92,9 +92,8 @@ export type { TokenSummary, TokenSurface, TokenSurfaceSummary } from './token-le
92
92
  export type { FailureSummary } from './failure-log.js';
93
93
  export { classifyOriginProject } from './project-identity.js';
94
94
  /**
95
- * v39 S4: the secret half of the ambient policy on its own, for surfaces
96
- * with their own scope semantics (MCP hippo_context's explicit-scope
97
- * exact-match). A flagged row is only admitted inside its owning project;
95
+ * v39 S4: the secret half of the ambient policy on its own, for callers
96
+ * that apply their own scope rule. A flagged row is only admitted inside its owning project;
98
97
  * flagged rows with no project origin never ambient-inject.
99
98
  */
100
99
  export declare function ambientSecretAdmit(e: MemoryEntry, currentProjectName: string): boolean;
@@ -270,16 +269,22 @@ export interface RecallOpts {
270
269
  * Mirrors `suppressAvailabilityHint`'s pattern: callers that run their OWN
271
270
  * tracing over a DIFFERENT result set must suppress api.recall's copy so
272
271
  * the training corpus doesn't get a trace mislabeled as 'api' pipeline
273
- * when the caller's actual user-visible results came from elsewhere. The
274
- * MCP handler sets this — its primary ranked band comes from a separate
275
- * physics/hybrid scorer, not this api.recall call's BM25 band (real MCP
276
- * tracing is the reserved 'mcp' pipeline, a follow-up). HTTP / direct SDK
277
- * callers leave this unset and get the trace.
272
+ * when the caller's actual user-visible results came from elsewhere. Under
273
+ * `showRanked` it also drops the 'mcp' trace of the shown list. HTTP /
274
+ * direct SDK callers leave this unset and get the trace.
278
275
  */
279
276
  suppressRecallTrace?: boolean;
280
277
  /** Set only by the MCP recall tool, which ranks with its own scorer and drops copies from its own final list: this call
281
278
  * then keeps a memory that a merged row in the same result holds word for word. Other callers leave it unset. */
282
279
  keepHeldCopies?: boolean;
280
+ /** MCP recall only: `retrieve` ranks the whole scoped store and strengthens and traces (pipeline 'mcp') just the ids this returns; `results` stays the window band. */
281
+ showRanked?: (ranking: StoreRanking, result: RecallResult) => readonly string[];
282
+ }
283
+ /** `ranked`: every scored row, best first, goal boost applied, entries as loaded; `pool`: the store after the scope filter. */
284
+ export interface StoreRanking {
285
+ ranked: SearchResult[];
286
+ pool: MemoryEntry[];
287
+ droppedByScope: number;
283
288
  }
284
289
  export interface ContinuityBlock {
285
290
  activeSnapshot: TaskSnapshot | null;
@@ -946,6 +951,8 @@ export interface ContextOpts {
946
951
  limit?: number;
947
952
  pinnedOnly?: boolean;
948
953
  scope?: string;
954
+ /** Envelope scope to match exactly, as in `recall`: admits that scope even when private, after the actor's scope check. */
955
+ exactScope?: string;
949
956
  /** With `pinnedOnly`, also inject the N most recent writes that pass the
950
957
  * quality floor (`isContentWorthStoring`, DF3). Filtering happens BEFORE
951
958
  * the take-N, so a caller asking for 5 gets 5 qualifying entries rather
package/dist/api.js CHANGED
@@ -16,7 +16,7 @@ import { detectInstruction } from './instruction-detect.js';
16
16
  import { quarantineScopeFor, recordQuarantine, getQuarantineRow, listQuarantineRows, approveQuarantineRow, rejectQuarantineRow, } from './quarantine.js';
17
17
  import { summarizeFailures } from './failure-log.js';
18
18
  import { formatHandoffEvidenceLine } from './handoff.js';
19
- import { createMemory, createSuccessor, applyOutcome, calculateStrength, CHURN_STALE_TAG, COMPACTION_MEMORY_TAG, } from './memory.js';
19
+ import { createMemory, createSuccessor, applyOutcome, calculateStrength, markRetrieved, CHURN_STALE_TAG, COMPACTION_MEMORY_TAG, } from './memory.js';
20
20
  import { appendAuditEvent, auditQueryFields, queryAuditEvents, auditMemories, isContentWorthStoring, } from './audit.js';
21
21
  import { promoteToGlobal, getGlobalRoot, autoShare, searchBothHybrid } from './shared.js';
22
22
  import { writeRecallTrace, writeRecallTraceAtRoot, recordTraceOutcome } from './recall-trace.js';
@@ -24,7 +24,7 @@ import { evalNow } from './ablation.js';
24
24
  import { archiveRawMemory } from './raw-archive.js';
25
25
  import { createApiKey, listApiKeys, revokeApiKey, grantScope, ungrantScope, } from './auth.js';
26
26
  import { applyGoalStackBoost } from './goals.js';
27
- import { markRetrieved, estimateTokens, hybridSearch, physicsSearch, churnStaleFactor } from './search.js';
27
+ import { estimateTokens, hybridSearch, physicsSearch, churnStaleFactor } from './search.js';
28
28
  import { compareEntryIdentity, compareScoredResults } from './compare.js';
29
29
  import { dropHeldCopies, duplicateKey, storedTextKeys } from './same-text.js';
30
30
  import { scopeMatch } from './scope.js';
@@ -39,7 +39,7 @@ import { computeAmbientState } from './ambient.js';
39
39
  import { loadPendingExtractionTenants, markPendingProcessedUpTo } from './graph.js';
40
40
  import { extractGraph } from './graph-extract.js';
41
41
  import { computePlanningFallacyOutput, } from './predictions.js';
42
- import { detectAnchoring, hashQueryText, } from './recall-history.js';
42
+ import { detectAnchoring, hashQueryText, biasHintEnabled, } from './recall-history.js';
43
43
  import { detectAvailabilityBias } from './availability.js';
44
44
  /**
45
45
  * Helper for building process-local (admin-by-default) Actor values. v1.12.0
@@ -107,23 +107,22 @@ export { classifyOriginProject } from './project-identity.js';
107
107
  * injects inside its owning project; flagged rows with no project origin
108
108
  * (''/null) never ambient-inject at all. Explicit recall is unaffected -
109
109
  * recalling a secret is a deliberate act.
110
- * - S2 envelope parity: private scopes + quarantine buckets never inject.
110
+ * - S2 envelope parity: private/quarantine scopes never inject unless `exactScope` names one.
111
111
  * - S3 origin partition: other-project rows are excluded unless
112
112
  * `includeCrossProject`.
113
113
  */
114
- function ambientAdmitEntry(e, currentProjectName, includeCrossProject) {
114
+ function ambientAdmitEntry(e, currentProjectName, includeCrossProject, exactScope) {
115
115
  if (!ambientSecretAdmit(e, currentProjectName))
116
116
  return false;
117
- if (!passesScopeFilterForRecall(e.scope ?? null, undefined))
117
+ if (!passesScopeFilterForRecall(e.scope ?? null, exactScope))
118
118
  return false;
119
119
  if (includeCrossProject)
120
120
  return true;
121
121
  return classifyOriginProject(e.origin_project, currentProjectName) !== 'cross-project';
122
122
  }
123
123
  /**
124
- * v39 S4: the secret half of the ambient policy on its own, for surfaces
125
- * with their own scope semantics (MCP hippo_context's explicit-scope
126
- * exact-match). A flagged row is only admitted inside its owning project;
124
+ * v39 S4: the secret half of the ambient policy on its own, for callers
125
+ * that apply their own scope rule. A flagged row is only admitted inside its owning project;
127
126
  * flagged rows with no project origin never ambient-inject.
128
127
  */
129
128
  export function ambientSecretAdmit(e, currentProjectName) {
@@ -244,6 +243,8 @@ export function recall(ctx, opts) {
244
243
  export async function retrieve(ctx, opts) {
245
244
  assertScopeRequestAllowed(ctx.actor, opts.scope);
246
245
  const windowSize = recallWindowSize(opts);
246
+ if (opts.showRanked)
247
+ return retrieveFromStore(ctx, opts, windowSize, opts.showRanked);
247
248
  let candidates = loadRecallSearchEntries(ctx.hippoRoot, opts.query, windowSize, ctx.tenantId, opts.scope, 'exact', false);
248
249
  if (opts.mode === 'hybrid' || opts.mode === 'physics') {
249
250
  const searchOpts = { budget: Infinity, hippoRoot: ctx.hippoRoot, scope: opts.scope ?? null };
@@ -257,6 +258,40 @@ export async function retrieve(ctx, opts) {
257
258
  strengthenRetrieved(ctx.hippoRoot, result.results.map((r) => r.id), ctx.tenantId);
258
259
  return result;
259
260
  }
261
+ /** `retrieve` under `showRanked`: physics when `mode` says so, hybrid otherwise, over every admitted row. */
262
+ async function retrieveFromStore(ctx, opts, windowSize, show) {
263
+ const store = loadAllEntries(ctx.hippoRoot, ctx.tenantId);
264
+ const pool = store.filter((e) => passesScopeFilterForRecall(e.scope ?? null, opts.scope));
265
+ // No scope option: the scope boost follows HIPPO_SCOPE and the skill env, as MCP recall always ranked.
266
+ const searchOpts = { budget: Infinity, hippoRoot: ctx.hippoRoot };
267
+ let ranked = opts.mode === 'physics'
268
+ ? await physicsSearch(opts.query, pool, { ...searchOpts, physicsConfig: loadConfig(ctx.hippoRoot).physics })
269
+ : await hybridSearch(opts.query, pool, searchOpts);
270
+ if (opts.sessionId && !opts.goalTag) {
271
+ const db = openHippoDb(ctx.hippoRoot);
272
+ try {
273
+ ranked = applyGoalStackBoost(db, ranked, { sessionId: opts.sessionId, tenantId: ctx.tenantId, limit: ranked.length });
274
+ }
275
+ finally {
276
+ closeHippoDb(db);
277
+ }
278
+ }
279
+ const window = ranked.slice(0, windowSize).map((r) => r.entry);
280
+ const result = recallFrom(ctx, { ...opts, suppressRecallTrace: true }, windowSize, window);
281
+ const shown = show({ ranked, pool, droppedByScope: store.length - pool.length }, result);
282
+ strengthenRetrieved(ctx.hippoRoot, shown, ctx.tenantId);
283
+ if (!opts.suppressRecallTrace) {
284
+ const scores = new Map(ranked.map((r) => [r.entry.id, r.score]));
285
+ writeRecallTraceAtRoot(ctx.hippoRoot, {
286
+ tenantId: ctx.tenantId,
287
+ sessionId: opts.sessionId ?? null,
288
+ pipeline: 'mcp',
289
+ query: opts.query,
290
+ results: shown.map((id) => ({ memoryId: id, score: scores.get(id) ?? 0 })),
291
+ });
292
+ }
293
+ return result;
294
+ }
260
295
  /** Contract preflight: throws before any store-touching work. */
261
296
  function recallWindowSize(opts) {
262
297
  // F5 (v1.6.5) preflight — codex P1: original guard fired AFTER
@@ -564,9 +599,9 @@ function recallFrom(ctx, opts, windowSize, all) {
564
599
  // handle. v1.11.5 contract lock holds — api.recall does NOT write
565
600
  // last_trace_id (tests/api-recall-no-side-effects.test.ts); a trace INSERT
566
601
  // is the same observability class as the audit row it sits beside, not
567
- // retrieval state. F2 fix: suppressed when the caller (currently only the
568
- // MCP handler) traces its own, different result set — see
569
- // opts.suppressRecallTrace JSDoc. Fail-soft internally; never throws.
602
+ // retrieval state. F2 fix: suppressed when the caller traces its own,
603
+ // different result set (retrieve under showRanked traces the shown list as
604
+ // 'mcp'). Fail-soft internally; never throws.
570
605
  if (!opts.suppressRecallTrace) {
571
606
  writeRecallTrace(db, {
572
607
  tenantId: ctx.tenantId,
@@ -656,7 +691,7 @@ function recallFrom(ctx, opts, windowSize, all) {
656
691
  // detect call returns null and api.recall's anchoringHint stays absent.
657
692
  let anchoringHint = null;
658
693
  let suppressedByInterferenceCount = 0;
659
- if (process.env.HIPPO_ANCHORING !== 'off' && opts.recallHistory) {
694
+ if (biasHintEnabled('anchoring') && opts.recallHistory) {
660
695
  const queryHash = hashQueryText(opts.query);
661
696
  const topMemoryId = rankedOut[0]?.id ?? null;
662
697
  anchoringHint = detectAnchoring(opts.recallHistory, queryHash, topMemoryId);
@@ -709,7 +744,7 @@ function recallFrom(ctx, opts, windowSize, all) {
709
744
  // opts.recallHistory gate above so we never double-emit the audit op. Audit
710
745
  // emission is pipeline-local, mirroring the J1 block above.
711
746
  let availabilityHint = null;
712
- if (process.env.HIPPO_AVAILABILITY !== 'off' && !opts.suppressAvailabilityHint) {
747
+ if (biasHintEnabled('availability') && !opts.suppressAvailabilityHint) {
713
748
  availabilityHint = detectAvailabilityBias({
714
749
  topK: baseSlice.map((e) => ({ id: e.id, created: e.created })),
715
750
  pool: entries.map((e) => ({ id: e.id, created: e.created })),
@@ -1551,6 +1586,8 @@ export async function getContext(ctx, opts = {}) {
1551
1586
  const limit = opts.limit ?? Number.POSITIVE_INFINITY;
1552
1587
  const includeRecent = opts.includeRecent ?? 0;
1553
1588
  const activeScope = opts.scope ?? '';
1589
+ assertScopeRequestAllowed(ctx.actor, opts.exactScope);
1590
+ const exactScope = opts.exactScope || undefined;
1554
1591
  if (budget <= 0) {
1555
1592
  return { entries: [], tokens: 0 };
1556
1593
  }
@@ -1562,10 +1599,7 @@ export async function getContext(ctx, opts = {}) {
1562
1599
  const primaryIsGlobal = isGlobalStoreRoot(ctx.hippoRoot);
1563
1600
  const hasLocalTaskState = hasLocal && !primaryIsGlobal;
1564
1601
  // v39 memory scope isolation (docs/plans/2026-07-01-memory-scope-isolation.md).
1565
- // S2: envelope-filter parity with api.recall for AMBIENT context - private
1566
- // scopes and quarantine buckets never inject. `requested` is deliberately
1567
- // undefined: opts.scope is the scope-TAG boost input here, not an
1568
- // envelope-scope request (api.recall's exact-match semantics don't apply).
1602
+ // S2: envelope-filter parity with api.recall; opts.scope is only the tag boost, opts.exactScope the envelope request.
1569
1603
  // S3: origin partition - other-project memories are excluded unless the
1570
1604
  // caller explicitly asks for them (crossProject) or isolation is disabled.
1571
1605
  const config = loadConfig(ctx.hippoRoot);
@@ -1612,9 +1646,8 @@ export async function getContext(ctx, opts = {}) {
1612
1646
  sessionId: opts.currentSessionId,
1613
1647
  })
1614
1648
  : null;
1615
- // W1: pre-existing leak; same `requested: undefined` ambientAdmitEntry
1616
- // already uses when it scope-filters memory rows above.
1617
- const activeSnapshot = rawActiveSnapshot && passesScopeFilterForRecall(rowScope(rawActiveSnapshot), undefined)
1649
+ // W1: the same envelope rule ambientAdmitEntry applies to memory rows.
1650
+ const activeSnapshot = rawActiveSnapshot && passesScopeFilterForRecall(rowScope(rawActiveSnapshot), exactScope)
1618
1651
  ? rawActiveSnapshot
1619
1652
  : null;
1620
1653
  // Key on the RAW snapshot: a scope-hidden active session must not fall through to another session's ambient handoff.
@@ -1628,7 +1661,7 @@ export async function getContext(ctx, opts = {}) {
1628
1661
  // codex P2: admit scope in SQL so a newer denied row can't hide an older eligible one before LIMIT 1.
1629
1662
  scopeFilter: 'default-deny',
1630
1663
  });
1631
- const sessionHandoff = rawSessionHandoff && passesScopeFilterForRecall(rowScope(rawSessionHandoff), undefined)
1664
+ const sessionHandoff = rawSessionHandoff && passesScopeFilterForRecall(rowScope(rawSessionHandoff), exactScope)
1632
1665
  ? rawSessionHandoff
1633
1666
  : null;
1634
1667
  // Raw session id here too: each event is admitted on its own scope, same as recall and the CLI.
@@ -1636,7 +1669,7 @@ export async function getContext(ctx, opts = {}) {
1636
1669
  ? listSessionEvents(ctx.hippoRoot, ctx.tenantId, {
1637
1670
  session_id: rawActiveSnapshot.session_id,
1638
1671
  limit: 5,
1639
- }).filter((e) => passesScopeFilterForRecall(rowScope(e), undefined))
1672
+ }).filter((e) => passesScopeFilterForRecall(rowScope(e), exactScope))
1640
1673
  : [];
1641
1674
  const shownSnapshot = activeSnapshot && (!cost || pays(cost.snapshot(activeSnapshot))) ? activeSnapshot : null;
1642
1675
  const shownHandoff = sessionHandoff && (!cost || pays(cost.handoff(sessionHandoff))) ? sessionHandoff : null;
@@ -1650,7 +1683,7 @@ export async function getContext(ctx, opts = {}) {
1650
1683
  digestHiddenForHandoff = true;
1651
1684
  return false;
1652
1685
  }
1653
- return ambientAdmitEntry(e, currentProjectName, includeCrossProject);
1686
+ return ambientAdmitEntry(e, currentProjectName, includeCrossProject, exactScope);
1654
1687
  };
1655
1688
  const ownSessionId = opts.currentSessionId || '';
1656
1689
  // Inside admit, not after the load, so the loader's window widens past a session's own items.
@@ -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