hippo-memory 1.62.0 → 1.63.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 +9 -0
- package/dist/agent-memories/apply.d.ts +2 -0
- package/dist/agent-memories/apply.js +23 -1
- package/dist/agent-memories/claude-code.d.ts +2 -1
- package/dist/agent-memories/claude-code.js +4 -4
- package/dist/agent-memories/report.d.ts +1 -0
- package/dist/agent-memories/report.js +2 -2
- package/dist/agent-memories/sync.js +37 -23
- package/dist/ambient-store.d.ts +4 -4
- package/dist/ambient-store.js +4 -3
- package/dist/api/assemble.d.ts +7 -10
- package/dist/api/assemble.js +7 -12
- package/dist/api/audit.d.ts +2 -2
- package/dist/api/audit.js +2 -2
- package/dist/api/auth.d.ts +6 -6
- package/dist/api/auth.js +5 -7
- package/dist/api/context-select.d.ts +4 -3
- package/dist/api/context-select.js +9 -11
- package/dist/api/context-types.d.ts +12 -17
- package/dist/api/context.d.ts +3 -2
- package/dist/api/context.js +20 -20
- package/dist/api/dormant.js +1 -1
- package/dist/api/drill-down.d.ts +4 -4
- package/dist/api/drill-down.js +22 -10
- package/dist/api/outcome.d.ts +8 -13
- package/dist/api/outcome.js +13 -17
- package/dist/api/promote.d.ts +5 -8
- package/dist/api/quarantine.js +3 -2
- package/dist/api/recall-types.d.ts +43 -55
- package/dist/api/recall.d.ts +3 -3
- package/dist/api/recall.js +7 -18
- package/dist/api/remember.d.ts +2 -2
- package/dist/api/sleep.d.ts +7 -35
- package/dist/api/sleep.js +3 -2
- package/dist/api/tokens.d.ts +2 -2
- package/dist/api/tokens.js +2 -2
- package/dist/api/types.d.ts +6 -10
- package/dist/api/types.js +2 -4
- package/dist/audit-prune.d.ts +4 -6
- package/dist/audit-prune.js +3 -5
- package/dist/audit.js +11 -33
- package/dist/auth.d.ts +8 -9
- package/dist/auth.js +5 -7
- package/dist/autolearn.d.ts +1 -1
- package/dist/autolearn.js +1 -1
- package/dist/availability.js +3 -5
- package/dist/capture/command.d.ts +5 -4
- package/dist/capture/command.js +8 -22
- package/dist/capture/compact.d.ts +1 -1
- package/dist/capture/compact.js +9 -13
- package/dist/capture/extract.js +37 -115
- package/dist/capture-error.d.ts +1 -1
- package/dist/capture-error.js +1 -1
- package/dist/churn-git.d.ts +1 -1
- package/dist/churn-git.js +1 -1
- package/dist/cli/audit.js +3 -4
- package/dist/cli/auth.js +3 -6
- package/dist/cli/curate.d.ts +1 -1
- package/dist/cli/curate.js +8 -24
- package/dist/cli/dag.js +5 -9
- package/dist/cli/decisions.js +10 -21
- package/dist/cli/explain.js +2 -1
- package/dist/cli/goals.js +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/cli/playbooks.js +4 -9
- package/dist/cli/projects.js +3 -1
- package/dist/cli/recall.js +2 -1
- package/dist/cli/remember.js +6 -18
- package/dist/cli/session-hooks.js +21 -40
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +2 -6
- package/dist/cli/shared.js +3 -3
- package/dist/cli/slack.js +1 -1
- package/dist/cli/sleep.js +27 -1
- package/dist/cli/status.d.ts +4 -4
- package/dist/cli/status.js +7 -12
- package/dist/cli/transfer.js +8 -13
- package/dist/cli/usage.js +9 -6
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +4 -9
- package/dist/compaction-record.d.ts +2 -0
- package/dist/compaction-record.js +89 -68
- package/dist/compare.d.ts +11 -16
- package/dist/compare.js +11 -16
- package/dist/config.d.ts +19 -18
- package/dist/config.js +90 -67
- package/dist/connectors/github/backfill.d.ts +2 -2
- package/dist/connectors/github/backfill.js +8 -15
- package/dist/connectors/github/cli-impl.js +3 -8
- package/dist/connectors/github/deletion.d.ts +5 -12
- package/dist/connectors/github/deletion.js +5 -12
- package/dist/connectors/github/dlq.d.ts +6 -9
- package/dist/connectors/github/dlq.js +2 -3
- package/dist/connectors/github/ingest.d.ts +5 -7
- package/dist/connectors/github/ingest.js +8 -12
- package/dist/connectors/github/octokit-client.d.ts +3 -5
- package/dist/connectors/github/octokit-client.js +5 -6
- package/dist/connectors/github/signature.d.ts +9 -39
- package/dist/connectors/github/signature.js +9 -39
- package/dist/connectors/github/tenant-routing.d.ts +1 -1
- package/dist/connectors/github/tenant-routing.js +1 -1
- package/dist/connectors/github/transform.js +2 -2
- package/dist/connectors/github/types.d.ts +2 -10
- package/dist/connectors/github/types.js +1 -3
- package/dist/connectors/slack/deletion.d.ts +3 -8
- package/dist/connectors/slack/deletion.js +3 -8
- package/dist/connectors/slack/dlq.d.ts +1 -1
- package/dist/connectors/slack/ingest.d.ts +1 -1
- package/dist/connectors/slack/ingest.js +7 -16
- package/dist/connectors/slack/signature.d.ts +1 -1
- package/dist/connectors/slack/tenant-routing.d.ts +3 -5
- package/dist/connectors/slack/tenant-routing.js +3 -5
- package/dist/connectors/slack/transform.d.ts +5 -6
- package/dist/connectors/slack/transform.js +5 -6
- package/dist/connectors/slack/types.d.ts +2 -6
- package/dist/connectors/slack/types.js +1 -3
- package/dist/connectors/slack/web-client.js +10 -3
- package/dist/connectors/slack/workspaces.d.ts +3 -5
- package/dist/connectors/slack/workspaces.js +3 -5
- package/dist/consolidate/conflicts.js +3 -14
- package/dist/consolidate/decay.js +9 -29
- package/dist/consolidate/llm-passes.js +4 -5
- package/dist/consolidate/merge.js +8 -23
- package/dist/consolidate/run.d.ts +1 -8
- package/dist/consolidate/run.js +3 -25
- package/dist/consolidate/sleep.js +5 -17
- package/dist/consolidate/traces.js +9 -21
- package/dist/customer-notes.d.ts +5 -7
- package/dist/customer-notes.js +6 -9
- package/dist/dag.d.ts +10 -21
- package/dist/dag.js +23 -73
- package/dist/db/continuity.js +2 -2
- package/dist/db/migrations/v14.js +1 -1
- package/dist/db/migrations/v15.js +1 -2
- package/dist/db/migrations/v16.js +3 -4
- package/dist/db/migrations/v17.js +2 -3
- package/dist/db/migrations/v19.js +1 -1
- package/dist/db/migrations/v20.js +1 -1
- package/dist/db/migrations/v21.js +2 -6
- package/dist/db/migrations/v22.js +2 -4
- package/dist/db/migrations/v23.js +1 -1
- package/dist/db/migrations/v24.js +4 -6
- package/dist/db/migrations/v25.js +2 -3
- package/dist/db/migrations/v26.js +3 -3
- package/dist/db/migrations/v27.js +2 -10
- package/dist/db/migrations/v28.js +5 -8
- package/dist/db/migrations/v29.js +3 -4
- package/dist/db/migrations/v30.js +2 -2
- package/dist/db/migrations/v31.js +1 -1
- package/dist/db/migrations/v32.js +1 -1
- package/dist/db/migrations/v33.js +3 -3
- package/dist/db/migrations/v34.js +1 -1
- package/dist/db/migrations/v35.js +3 -4
- package/dist/db/migrations/v36.js +3 -4
- package/dist/db/migrations/v37.js +5 -5
- package/dist/db/migrations/v38.js +7 -8
- package/dist/db/migrations/v39.js +1 -1
- package/dist/db/migrations/v40.js +4 -16
- package/dist/db/migrations/v41.js +3 -4
- package/dist/db/migrations/v42.js +3 -4
- package/dist/db/migrations/v45.js +1 -1
- package/dist/db/migrations/v46.js +1 -1
- package/dist/db/migrations/v47.js +1 -1
- package/dist/db/migrations/v48.js +1 -1
- package/dist/decisions.d.ts +2 -2
- package/dist/decisions.js +6 -6
- package/dist/dedupe.js +86 -61
- package/dist/delivery-recorder.js +154 -135
- package/dist/doctor.js +119 -104
- package/dist/dormant.js +1 -4
- package/dist/embedding-provider.d.ts +4 -8
- package/dist/embedding-provider.js +4 -8
- package/dist/embeddings.js +55 -47
- package/dist/env.d.ts +1 -1
- package/dist/env.js +12 -12
- package/dist/escape.d.ts +5 -0
- package/dist/escape.js +10 -0
- package/dist/eval-stats.d.ts +1 -2
- package/dist/eval-stats.js +1 -2
- package/dist/eval-suite.js +27 -21
- package/dist/extract.js +4 -9
- package/dist/failure-log.d.ts +3 -3
- package/dist/failure-log.js +1 -1
- package/dist/forward-claim-detector.d.ts +2 -4
- package/dist/forward-claim-detector.js +6 -11
- package/dist/goals.d.ts +3 -3
- package/dist/goals.js +5 -6
- package/dist/graph/read.d.ts +2 -2
- package/dist/graph/read.js +5 -6
- package/dist/graph/types.d.ts +8 -8
- package/dist/graph/write.d.ts +7 -14
- package/dist/graph/write.js +16 -23
- package/dist/graph-extract.d.ts +7 -8
- package/dist/graph-extract.js +62 -72
- package/dist/graph-recall.d.ts +2 -2
- package/dist/graph-recall.js +55 -49
- package/dist/graph-stream.d.ts +5 -6
- package/dist/graph-stream.js +66 -57
- package/dist/graph-view.d.ts +2 -2
- package/dist/graph-view.js +7 -7
- package/dist/half-life-migration.d.ts +1 -2
- package/dist/half-life-migration.js +2 -3
- package/dist/hooks/codex-session.js +1 -1
- package/dist/hooks/codex-wrapper.d.ts +1 -1
- package/dist/hooks/codex-wrapper.js +3 -2
- package/dist/hooks/json-hooks.d.ts +2 -2
- package/dist/hooks/json-hooks.js +5 -4
- package/dist/hooks/opencode.d.ts +1 -1
- package/dist/hooks/opencode.js +5 -4
- package/dist/hooks/shared.d.ts +3 -7
- package/dist/hooks/shared.js +1 -8
- package/dist/http-util.d.ts +2 -3
- package/dist/http-util.js +3 -0
- package/dist/importers/core.d.ts +2 -9
- package/dist/importers/core.js +15 -30
- package/dist/importers/sources.js +2 -1
- package/dist/importers/vault.js +2 -20
- package/dist/incidents.d.ts +1 -1
- package/dist/incidents.js +1 -1
- package/dist/instruction-detect.d.ts +1 -1
- package/dist/instruction-detect.js +1 -1
- package/dist/invalidation.d.ts +3 -0
- package/dist/invalidation.js +160 -114
- package/dist/json.d.ts +5 -0
- package/dist/json.js +4 -0
- package/dist/judgment.js +1 -2
- package/dist/local-embedding.js +1 -1
- package/dist/mcp/admin-tools.js +7 -17
- package/dist/mcp/format.js +1 -1
- package/dist/mcp/framing.js +3 -6
- package/dist/mcp/protocol.d.ts +2 -5
- package/dist/mcp/protocol.js +1 -3
- package/dist/mcp/recall-tools.js +12 -15
- package/dist/mcp/request.js +4 -3
- package/dist/mcp/session-state.js +2 -3
- package/dist/mcp/stdio.js +2 -1
- package/dist/mcp/tools.js +9 -6
- package/dist/memory-value-weights.d.ts +5 -8
- package/dist/memory-value-weights.js +5 -8
- package/dist/memory-value.d.ts +13 -13
- package/dist/memory-value.js +26 -37
- package/dist/memory.d.ts +20 -22
- package/dist/memory.js +24 -48
- package/dist/multihop.d.ts +1 -1
- package/dist/multihop.js +3 -2
- package/dist/owner-validation.d.ts +4 -5
- package/dist/owner-validation.js +4 -5
- package/dist/physics.d.ts +4 -4
- package/dist/physics.js +7 -9
- package/dist/policies.d.ts +9 -10
- package/dist/policies.js +12 -14
- package/dist/postinstall.js +3 -6
- package/dist/predictions/planning-fallacy.d.ts +9 -14
- package/dist/predictions/planning-fallacy.js +10 -16
- package/dist/predictions/store.d.ts +15 -23
- package/dist/predictions/store.js +36 -33
- package/dist/processes.d.ts +2 -7
- package/dist/processes.js +3 -3
- package/dist/project-briefs.d.ts +2 -3
- package/dist/project-briefs.js +9 -13
- package/dist/project-identity.d.ts +22 -9
- package/dist/project-identity.js +47 -12
- package/dist/project-merge.d.ts +17 -2
- package/dist/project-merge.js +109 -27
- package/dist/project-remote.d.ts +12 -0
- package/dist/project-remote.js +138 -0
- package/dist/prompt-recall.js +1 -2
- package/dist/rate-limit.d.ts +1 -1
- package/dist/rate-limit.js +1 -1
- package/dist/raw-archive.d.ts +9 -0
- package/dist/raw-archive.js +70 -53
- package/dist/recall-history.d.ts +19 -20
- package/dist/recall-history.js +24 -42
- package/dist/recall-pipeline.js +4 -28
- package/dist/recall-scope.d.ts +7 -8
- package/dist/recall-scope.js +7 -8
- package/dist/recall-trace.d.ts +5 -9
- package/dist/recall-trace.js +6 -10
- package/dist/refine-llm.d.ts +1 -1
- package/dist/refine-llm.js +2 -2
- package/dist/reject-flow.d.ts +3 -4
- package/dist/reject-flow.js +122 -117
- package/dist/rejection.d.ts +5 -6
- package/dist/rejection.js +7 -15
- package/dist/rerankers/clef.d.ts +1 -1
- package/dist/rerankers/jev.d.ts +1 -2
- package/dist/rerankers/jev.js +4 -5
- package/dist/rerankers/llm.d.ts +1 -2
- package/dist/rerankers/llm.js +1 -2
- package/dist/rerankers/types.d.ts +1 -2
- package/dist/rrf.d.ts +2 -2
- package/dist/rrf.js +2 -2
- package/dist/search/bm25-search.d.ts +1 -1
- package/dist/search/bm25-search.js +2 -1
- package/dist/search/boosts.js +2 -1
- package/dist/search/hybrid.d.ts +1 -1
- package/dist/search/hybrid.js +2 -1
- package/dist/search/physics-search.d.ts +1 -1
- package/dist/search/physics-search.js +2 -1
- package/dist/search/types.d.ts +2 -0
- package/dist/search/types.js +3 -1
- package/dist/secret-detect.d.ts +4 -5
- package/dist/secret-detect.js +6 -10
- package/dist/server/auth.js +5 -5
- package/dist/server/client-ip.js +1 -1
- package/dist/server/cursor.js +2 -1
- package/dist/server/mcp-http.js +4 -4
- package/dist/server/request.d.ts +3 -6
- package/dist/server/request.js +6 -7
- package/dist/server/routes/admin.js +5 -4
- package/dist/server/routes/customer-notes.js +6 -5
- package/dist/server/routes/decisions.js +4 -3
- package/dist/server/routes/incidents.js +7 -5
- package/dist/server/routes/memories.js +7 -7
- package/dist/server/routes/policies.js +3 -2
- package/dist/server/routes/predictions.js +12 -15
- package/dist/server/routes/processes.js +3 -2
- package/dist/server/routes/project-briefs.js +8 -7
- package/dist/server/routes/recall.js +95 -93
- package/dist/server/routes/skills.js +6 -5
- package/dist/server/types.d.ts +1 -1
- package/dist/server/validation.d.ts +1 -2
- package/dist/server/validation.js +7 -14
- package/dist/server-detect.js +72 -58
- package/dist/server.d.ts +2 -2
- package/dist/server.js +131 -117
- package/dist/shared.d.ts +17 -17
- package/dist/shared.js +93 -97
- package/dist/skills.d.ts +3 -3
- package/dist/skills.js +8 -8
- package/dist/store/audit-event.d.ts +2 -2
- package/dist/store/audit-event.js +1 -1
- package/dist/store/candidates.d.ts +2 -2
- package/dist/store/candidates.js +4 -3
- package/dist/store/conflicts.js +30 -22
- package/dist/store/delete-and-batch.d.ts +11 -14
- package/dist/store/delete-and-batch.js +40 -91
- package/dist/store/entry-reads.d.ts +17 -25
- package/dist/store/entry-reads.js +59 -40
- package/dist/store/entry-row.d.ts +6 -24
- package/dist/store/entry-row.js +6 -24
- package/dist/store/entry-writes.d.ts +6 -7
- package/dist/store/entry-writes.js +13 -11
- package/dist/store/handoffs.d.ts +1 -1
- package/dist/store/handoffs.js +7 -10
- package/dist/store/index-and-stats.d.ts +2 -6
- package/dist/store/index-and-stats.js +4 -10
- package/dist/store/mirrors.d.ts +6 -19
- package/dist/store/mirrors.js +14 -39
- package/dist/store/open.js +9 -31
- package/dist/store/rows.d.ts +5 -11
- package/dist/store/rows.js +6 -11
- package/dist/store/search-rows.d.ts +17 -34
- package/dist/store/search-rows.js +31 -59
- package/dist/store/sessions.d.ts +4 -5
- package/dist/store/sessions.js +5 -6
- package/dist/store/summaries.d.ts +13 -17
- package/dist/store/summaries.js +26 -70
- package/dist/support-bundle.js +4 -8
- package/dist/tenant.d.ts +1 -5
- package/dist/token-ledger.d.ts +1 -1
- package/dist/token-ledger.js +3 -5
- package/dist/trace.js +1 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/working-memory.d.ts +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 +1 -1
package/dist/cli.js
CHANGED
|
@@ -185,7 +185,7 @@ export function shouldAutoRepairCodexWrapper(currentCommand, flags) {
|
|
|
185
185
|
// hook install codex` (a Codex update can restore the real binary over our
|
|
186
186
|
// shim). Never first-installs — silently swapping the codex binary on routine
|
|
187
187
|
// commands is a consent violation and reads as binary hijacking to
|
|
188
|
-
// supply-chain scanners
|
|
188
|
+
// supply-chain scanners.
|
|
189
189
|
function maybeRepairCodexWrapper(currentCommand, flags) {
|
|
190
190
|
if (!shouldAutoRepairCodexWrapper(currentCommand, flags))
|
|
191
191
|
return;
|
|
@@ -407,7 +407,7 @@ export const COMMANDS = {
|
|
|
407
407
|
usage: VERB_USAGE.context,
|
|
408
408
|
},
|
|
409
409
|
hook: {
|
|
410
|
-
run: async ({ args
|
|
410
|
+
run: async ({ args }) => { (await import('./cli/setup.js')).cmdHook(args); },
|
|
411
411
|
usage: VERB_USAGE.hook,
|
|
412
412
|
},
|
|
413
413
|
setup: {
|
|
@@ -579,13 +579,8 @@ async function main(command, args, flags, hippoRoot) {
|
|
|
579
579
|
return;
|
|
580
580
|
}
|
|
581
581
|
maybeRepairCodexWrapper(command, flags);
|
|
582
|
-
/**
|
|
583
|
-
*
|
|
584
|
-
* the literal scope string 'true' (recall filter/unlock input, wm session scope,
|
|
585
|
-
* the remember scope-tag dual-write) or silently dropped the user's scoping
|
|
586
|
-
* intent (the remember envelope WRITE). Reject it once here, mirroring the
|
|
587
|
-
* --hops value-less guard, so every current and future command - including the
|
|
588
|
-
* thin-client dispatch relays - sees --scope only as a non-empty string. */
|
|
582
|
+
/** A value-less --scope parses as boolean true, which consumers coerced to the scope 'true' or dropped;
|
|
583
|
+
* reject it once here so every command, thin-client relays included, sees only a non-empty string. */
|
|
589
584
|
if ('scope' in flags && (typeof flags['scope'] !== 'string' || !flags['scope'].trim())) {
|
|
590
585
|
printError('--scope requires a non-empty value (e.g. --scope slack:private:C1).');
|
|
591
586
|
process.exit(1);
|
|
@@ -56,6 +56,8 @@ export interface ItemContext {
|
|
|
56
56
|
recordId: string | null;
|
|
57
57
|
sessionId: string;
|
|
58
58
|
originProject: string;
|
|
59
|
+
/** Where the session ran, so rows held under the project's older folder name count too. */
|
|
60
|
+
cwd: string | null;
|
|
59
61
|
items: string[];
|
|
60
62
|
}
|
|
61
63
|
/** Items that become rows, then the record `done`, in one transaction so two sessions cannot both insert one text. Mirrors after commit. */
|
|
@@ -7,7 +7,7 @@ import { loadConfig } from './config.js';
|
|
|
7
7
|
import { closeHippoDb, isSqliteBusy, openHippoDb } from './db.js';
|
|
8
8
|
import { gatedWrite } from './gated-write.js';
|
|
9
9
|
import { COMPACTION_MEMORY_TAG, COMPACTION_SOURCE_PREFIX, Layer, createMemory, generateId } from './memory.js';
|
|
10
|
-
import {
|
|
10
|
+
import { isGlobalStoreRoot, originInSql, projectId, projectNames, resolveProjectIdentity } from './project-identity.js';
|
|
11
11
|
import { maskEmails, redactSecretsStrict } from './secret-detect.js';
|
|
12
12
|
import { strengthenRetrievedOn, writeEntryMirrors } from './store/entry-writes.js';
|
|
13
13
|
import { isRecallBoostAblated } from './ablation.js';
|
|
@@ -30,11 +30,19 @@ const CLAIMED_SUFFIX = '.claimed';
|
|
|
30
30
|
/** The marker redactSecretsStrict writes; an item holding it was a secret before it was stored. */
|
|
31
31
|
const REDACTED = '[REDACTED]';
|
|
32
32
|
/** Where the session ran: rows written through the global store keep the project the session was in. */
|
|
33
|
-
function
|
|
33
|
+
function compactionProject(hippoRoot, cwd) {
|
|
34
34
|
if (!isGlobalStoreRoot(hippoRoot))
|
|
35
|
-
return
|
|
35
|
+
return resolveProjectIdentity(path.dirname(hippoRoot));
|
|
36
36
|
// No cwd means user-global, as stampOriginProject gives the global store; undefined would fall back to the hook's own cwd.
|
|
37
|
-
return cwd === null ? '' :
|
|
37
|
+
return cwd === null ? '' : resolveProjectIdentity(cwd);
|
|
38
|
+
}
|
|
39
|
+
function compactionOrigin(hippoRoot, cwd) {
|
|
40
|
+
return projectId(compactionProject(hippoRoot, cwd));
|
|
41
|
+
}
|
|
42
|
+
/** The names a record's held rows may carry: its origin, plus the folder name rows saved before project ids used. */
|
|
43
|
+
function heldOrigins(hippoRoot, cwd, originProject) {
|
|
44
|
+
const names = projectNames(compactionProject(hippoRoot, cwd));
|
|
45
|
+
return names.includes(originProject) ? names : [originProject];
|
|
38
46
|
}
|
|
39
47
|
function scrub(text) {
|
|
40
48
|
return maskEmails(redactSecretsStrict(text));
|
|
@@ -158,12 +166,76 @@ function restates(item, held) {
|
|
|
158
166
|
return next === item.length;
|
|
159
167
|
}
|
|
160
168
|
/** Live rows of one tenant and origin that default recall shows: a compaction often restates what an earlier one, or the user, already saved. */
|
|
161
|
-
function heldRows(db, tenantId,
|
|
169
|
+
function heldRows(db, tenantId, origins) {
|
|
162
170
|
// SAFETY: the SELECT names the id, source_session_id and content columns.
|
|
163
|
-
const rows = db.prepare(`SELECT id, source_session_id, content FROM memories WHERE tenant_id = ? AND
|
|
164
|
-
AND (scope IS NULL OR (scope != 'unknown:legacy' AND scope NOT LIKE '%:private:%'))`).all(tenantId,
|
|
171
|
+
const rows = db.prepare(`SELECT id, source_session_id, content FROM memories WHERE tenant_id = ? AND ${originInSql(origins)} AND superseded_by IS NULL AND kind != 'raw'
|
|
172
|
+
AND (scope IS NULL OR (scope != 'unknown:legacy' AND scope NOT LIKE '%:private:%'))`).all(tenantId, ...origins);
|
|
165
173
|
return rows.map((r) => ({ id: r.id, sessionId: r.source_session_id, words: words(r.content) }));
|
|
166
174
|
}
|
|
175
|
+
function compactionEntry(text, ctx, baseHalfLifeDays) {
|
|
176
|
+
return {
|
|
177
|
+
...createMemory(text, {
|
|
178
|
+
layer: Layer.Episodic,
|
|
179
|
+
tags: [COMPACTION_MEMORY_TAG],
|
|
180
|
+
source: `${COMPACTION_SOURCE_PREFIX}${ctx.sessionId}`,
|
|
181
|
+
confidence: 'observed',
|
|
182
|
+
kind: 'distilled',
|
|
183
|
+
source_session_id: ctx.sessionId,
|
|
184
|
+
tenantId: ctx.tenantId,
|
|
185
|
+
baseHalfLifeDays,
|
|
186
|
+
}),
|
|
187
|
+
origin_project: ctx.originProject,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** Runs inside saveItems' transaction: restatements of held rows are counted, the rest go through the write gate. */
|
|
191
|
+
function writeItemRows(db, hippoRoot, ctx, rows, baseHalfLifeDays) {
|
|
192
|
+
const out = { written: [], repeats: 0, refused: 0, restated: [] };
|
|
193
|
+
const held = heldRows(db, ctx.tenantId, heldOrigins(hippoRoot, ctx.cwd, ctx.originProject));
|
|
194
|
+
const restated = new Set();
|
|
195
|
+
for (const text of rows) {
|
|
196
|
+
const itemWords = words(text);
|
|
197
|
+
const match = held.find((h) => restates(itemWords, h.words));
|
|
198
|
+
if (match) {
|
|
199
|
+
out.repeats++;
|
|
200
|
+
if (match.id !== null && match.sessionId !== ctx.sessionId)
|
|
201
|
+
restated.add(match.id);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
// createMemory throws below 3 chars, which would sink the whole transaction.
|
|
205
|
+
if (text.trim().length < 3) {
|
|
206
|
+
out.refused++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const entry = compactionEntry(text, ctx, baseHalfLifeDays);
|
|
210
|
+
if (gatedWrite(db, hippoRoot, entry, { actor: 'post-compact' }) === 'written') {
|
|
211
|
+
out.written.push(entry);
|
|
212
|
+
held.push({ id: null, sessionId: ctx.sessionId, words: itemWords });
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
out.refused++;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
out.restated = [...restated];
|
|
219
|
+
return out;
|
|
220
|
+
}
|
|
221
|
+
/** After commit: report skips, mirror the new rows, bump the counter. */
|
|
222
|
+
function finishItemWrites(hippoRoot, writes, log) {
|
|
223
|
+
if (writes.repeats > 0)
|
|
224
|
+
log(`skipped ${writes.repeats} item(s) the store already holds`);
|
|
225
|
+
if (writes.refused > 0)
|
|
226
|
+
log(`skipped ${writes.refused} item(s) the write gate refused`);
|
|
227
|
+
for (const entry of writes.written)
|
|
228
|
+
writeEntryMirrors(hippoRoot, entry);
|
|
229
|
+
if (writes.written.length > 0) {
|
|
230
|
+
try {
|
|
231
|
+
updateStats(hippoRoot, { remembered: writes.written.length });
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
// The rows are committed; a counter that could not be bumped must not turn that into a failed step.
|
|
235
|
+
log(`remembered counter not updated: ${errorMessage(err)}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
167
239
|
/** Items that become rows, then the record `done`, in one transaction so two sessions cannot both insert one text. Mirrors after commit. */
|
|
168
240
|
export function saveItems(db, hippoRoot, ctx, log) {
|
|
169
241
|
const usable = ctx.items.filter((item) => !item.includes(REDACTED));
|
|
@@ -175,9 +247,7 @@ export function saveItems(db, hippoRoot, ctx, log) {
|
|
|
175
247
|
if (capped > 0)
|
|
176
248
|
log(`capped: ${capped} more kept in the record only`);
|
|
177
249
|
const baseHalfLifeDays = loadConfig(hippoRoot).defaultHalfLifeDays;
|
|
178
|
-
|
|
179
|
-
let repeats = 0;
|
|
180
|
-
let refused = 0;
|
|
250
|
+
let writes;
|
|
181
251
|
db.exec('BEGIN IMMEDIATE');
|
|
182
252
|
try {
|
|
183
253
|
if (ctx.recordId !== null) {
|
|
@@ -190,47 +260,11 @@ export function saveItems(db, hippoRoot, ctx, log) {
|
|
|
190
260
|
return current?.items_written ?? 0;
|
|
191
261
|
}
|
|
192
262
|
}
|
|
193
|
-
|
|
194
|
-
const restated = new Set();
|
|
195
|
-
for (const text of rows) {
|
|
196
|
-
const itemWords = words(text);
|
|
197
|
-
const match = held.find((h) => restates(itemWords, h.words));
|
|
198
|
-
if (match) {
|
|
199
|
-
repeats++;
|
|
200
|
-
if (match.id !== null && match.sessionId !== ctx.sessionId)
|
|
201
|
-
restated.add(match.id);
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
// createMemory throws below 3 chars, which would sink the whole transaction.
|
|
205
|
-
if (text.trim().length < 3) {
|
|
206
|
-
refused++;
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
const entry = {
|
|
210
|
-
...createMemory(text, {
|
|
211
|
-
layer: Layer.Episodic,
|
|
212
|
-
tags: [COMPACTION_MEMORY_TAG],
|
|
213
|
-
source: `${COMPACTION_SOURCE_PREFIX}${ctx.sessionId}`,
|
|
214
|
-
confidence: 'observed',
|
|
215
|
-
kind: 'distilled',
|
|
216
|
-
source_session_id: ctx.sessionId,
|
|
217
|
-
tenantId: ctx.tenantId,
|
|
218
|
-
baseHalfLifeDays,
|
|
219
|
-
}),
|
|
220
|
-
origin_project: ctx.originProject,
|
|
221
|
-
};
|
|
222
|
-
if (gatedWrite(db, hippoRoot, entry, { actor: 'post-compact' }) === 'written') {
|
|
223
|
-
written.push(entry);
|
|
224
|
-
held.push({ id: null, sessionId: ctx.sessionId, words: itemWords });
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
refused++;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
263
|
+
writes = writeItemRows(db, hippoRoot, ctx, rows, baseHalfLifeDays);
|
|
230
264
|
// Said again by another session is the same signal as being recalled; the same session carrying it forward is not.
|
|
231
|
-
strengthenRetrievedOn(db,
|
|
265
|
+
strengthenRetrievedOn(db, writes.restated, { tenantId: ctx.tenantId, recallBoostAblated: isRecallBoostAblated() });
|
|
232
266
|
if (ctx.recordId !== null) {
|
|
233
|
-
db.prepare(`UPDATE compactions SET items_written = ?, status = 'done' WHERE tenant_id = ? AND id = ?`).run(written.length, ctx.tenantId, ctx.recordId);
|
|
267
|
+
db.prepare(`UPDATE compactions SET items_written = ?, status = 'done' WHERE tenant_id = ? AND id = ?`).run(writes.written.length, ctx.tenantId, ctx.recordId);
|
|
234
268
|
}
|
|
235
269
|
db.exec('COMMIT');
|
|
236
270
|
}
|
|
@@ -241,22 +275,8 @@ export function saveItems(db, hippoRoot, ctx, log) {
|
|
|
241
275
|
catch { /* already rolled back; keep the original error */ }
|
|
242
276
|
throw err;
|
|
243
277
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (refused > 0)
|
|
247
|
-
log(`skipped ${refused} item(s) the write gate refused`);
|
|
248
|
-
for (const entry of written)
|
|
249
|
-
writeEntryMirrors(hippoRoot, entry);
|
|
250
|
-
if (written.length > 0) {
|
|
251
|
-
try {
|
|
252
|
-
updateStats(hippoRoot, { remembered: written.length });
|
|
253
|
-
}
|
|
254
|
-
catch (err) {
|
|
255
|
-
// The rows are committed; a counter that could not be bumped must not turn that into a failed step.
|
|
256
|
-
log(`remembered counter not updated: ${errorMessage(err)}`);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return written.length;
|
|
278
|
+
finishItemWrites(hippoRoot, writes, log);
|
|
279
|
+
return writes.written.length;
|
|
260
280
|
}
|
|
261
281
|
/** null when the text is not a PostCompact payload naming a session. */
|
|
262
282
|
export function parsePostCompactPayload(stdinText) {
|
|
@@ -320,6 +340,7 @@ export function saveCompaction(hippoRoot, payload, log) {
|
|
|
320
340
|
recordId: record?.id ?? null,
|
|
321
341
|
sessionId: payload.sessionId,
|
|
322
342
|
originProject: record?.originProject ?? compactionOrigin(hippoRoot, payload.cwd),
|
|
343
|
+
cwd: payload.cwd,
|
|
323
344
|
items: text.items,
|
|
324
345
|
}, log);
|
|
325
346
|
}
|
|
@@ -494,7 +515,7 @@ function importSpool(db, hippoRoot, tenantId, log, deadline) {
|
|
|
494
515
|
// The record holds the items now, so the file is done even if the write below fails.
|
|
495
516
|
fs.rmSync(claimed, { force: true });
|
|
496
517
|
removed = true;
|
|
497
|
-
saveItems(db, hippoRoot, { tenantId: spooled.tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, items: record.items }, log);
|
|
518
|
+
saveItems(db, hippoRoot, { tenantId: spooled.tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, cwd: record.cwd, items: record.items }, log);
|
|
498
519
|
finished++;
|
|
499
520
|
}
|
|
500
521
|
catch (err) {
|
|
@@ -515,7 +536,7 @@ export function replayCompactions(db, hippoRoot, log, deadline = Number.POSITIVE
|
|
|
515
536
|
if (Date.now() > deadline)
|
|
516
537
|
break;
|
|
517
538
|
try {
|
|
518
|
-
saveItems(db, hippoRoot, { tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, items: record.items }, log);
|
|
539
|
+
saveItems(db, hippoRoot, { tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, cwd: record.cwd, items: record.items }, log);
|
|
519
540
|
finished++;
|
|
520
541
|
}
|
|
521
542
|
catch (err) {
|
|
@@ -549,7 +570,7 @@ export function replayCompactions(db, hippoRoot, log, deadline = Number.POSITIVE
|
|
|
549
570
|
log(`${record.id} was filled by another process`);
|
|
550
571
|
continue;
|
|
551
572
|
}
|
|
552
|
-
saveItems(db, hippoRoot, { tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, items: text.items }, log);
|
|
573
|
+
saveItems(db, hippoRoot, { tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, cwd: record.cwd, items: text.items }, log);
|
|
553
574
|
finished++;
|
|
554
575
|
}
|
|
555
576
|
catch (err) {
|
package/dist/compare.d.ts
CHANGED
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
* multihop.ts, rerankers/*). Every comparator here takes a structural param
|
|
7
7
|
* type instead of an imported one, on purpose — a type-only import back to
|
|
8
8
|
* search.ts would still create the search.ts <-> physics.ts ESM import
|
|
9
|
-
* cycle this module exists to avoid
|
|
10
|
-
* docs/plans/2026-07-09-recall-determinism.md T2).
|
|
9
|
+
* cycle this module exists to avoid.
|
|
11
10
|
*
|
|
12
11
|
* Mirrors the deliberate-determinism comment style already established in
|
|
13
12
|
* graph-stream.ts:88, :165-168, :233-236 — a sort with a documented,
|
|
@@ -32,11 +31,9 @@ export interface EntryIdentity {
|
|
|
32
31
|
* independently-created stores (different directory name, different insert
|
|
33
32
|
* order of everything else on disk) sorts identically. The metadata keys make
|
|
34
33
|
* byte-identical twins order by what they carry instead of by `id`
|
|
35
|
-
* (`crypto.randomUUID()`), which is per-instance random
|
|
36
|
-
* dedupe survivor
|
|
37
|
-
*
|
|
38
|
-
* episodic copy because `mem_` sorts before `sem_`. `id` stays the terminal
|
|
39
|
-
* key so the order is total within one store.
|
|
34
|
+
* (`crypto.randomUUID()`), which is per-instance random and would make the
|
|
35
|
+
* dedupe survivor arbitrary. `id` stays the terminal key so the order is
|
|
36
|
+
* total within one store.
|
|
40
37
|
*
|
|
41
38
|
* Layer rank puts semantic first: semantic rows are consolidation output, so
|
|
42
39
|
* keeping that copy preserves the promotion instead of demoting the memory.
|
|
@@ -47,8 +44,8 @@ export interface EntryIdentity {
|
|
|
47
44
|
* Plain `<`/`>`, NOT `localeCompare`: `localeCompare` is locale- and
|
|
48
45
|
* ICU-version-dependent (a determinism leak in its own right) and needlessly
|
|
49
46
|
* slow for a tiebreak that only needs a total order. The metadata keys are
|
|
50
|
-
* only computed on a content tie, which is rare
|
|
51
|
-
*
|
|
47
|
+
* only computed on a content tie, which is rare, so the per-compare Set/sort
|
|
48
|
+
* cost never lands on the hot path.
|
|
52
49
|
*/
|
|
53
50
|
export declare function compareEntryIdentity(a: EntryIdentity, b: EntryIdentity): number;
|
|
54
51
|
/** Minimal shape for score-primary sort sites (SearchResult and friends
|
|
@@ -72,13 +69,11 @@ export declare function compareScoredResults(a: ScoredEntryLike, b: ScoredEntryL
|
|
|
72
69
|
*
|
|
73
70
|
* `ScoredPhysicsResult` (physics.ts) carries `{ memoryId, baseScore,
|
|
74
71
|
* clusterAmplification, finalScore }` -- NO `entry`/`content` in scope at
|
|
75
|
-
* that layer, so `compareEntryIdentity` cannot apply directly
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* MUTATES scores before the downstream content-aware merge sort runs -- so
|
|
81
|
-
* the tie key must be content-stable at THIS layer, not just downstream).
|
|
72
|
+
* that layer, so `compareEntryIdentity` cannot apply directly. With only the
|
|
73
|
+
* default memoryId key this is PER-INSTANCE-ONLY determinism; callers that need
|
|
74
|
+
* CROSS-INGEST stability supply `tieKeyOf` mapping the result to its memory
|
|
75
|
+
* CONTENT, because the baseScore tie order selects the cluster_top_k
|
|
76
|
+
* amplification set, which MUTATES scores before the content-aware merge sort.
|
|
82
77
|
*
|
|
83
78
|
* A factory (not a fixed-field comparator) because physics.ts re-sorts the
|
|
84
79
|
* same result array by two different score fields in sequence (`baseScore`
|
package/dist/compare.js
CHANGED
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
* multihop.ts, rerankers/*). Every comparator here takes a structural param
|
|
7
7
|
* type instead of an imported one, on purpose — a type-only import back to
|
|
8
8
|
* search.ts would still create the search.ts <-> physics.ts ESM import
|
|
9
|
-
* cycle this module exists to avoid
|
|
10
|
-
* docs/plans/2026-07-09-recall-determinism.md T2).
|
|
9
|
+
* cycle this module exists to avoid.
|
|
11
10
|
*
|
|
12
11
|
* Mirrors the deliberate-determinism comment style already established in
|
|
13
12
|
* graph-stream.ts:88, :165-168, :233-236 — a sort with a documented,
|
|
@@ -21,11 +20,9 @@
|
|
|
21
20
|
* independently-created stores (different directory name, different insert
|
|
22
21
|
* order of everything else on disk) sorts identically. The metadata keys make
|
|
23
22
|
* byte-identical twins order by what they carry instead of by `id`
|
|
24
|
-
* (`crypto.randomUUID()`), which is per-instance random
|
|
25
|
-
* dedupe survivor
|
|
26
|
-
*
|
|
27
|
-
* episodic copy because `mem_` sorts before `sem_`. `id` stays the terminal
|
|
28
|
-
* key so the order is total within one store.
|
|
23
|
+
* (`crypto.randomUUID()`), which is per-instance random and would make the
|
|
24
|
+
* dedupe survivor arbitrary. `id` stays the terminal key so the order is
|
|
25
|
+
* total within one store.
|
|
29
26
|
*
|
|
30
27
|
* Layer rank puts semantic first: semantic rows are consolidation output, so
|
|
31
28
|
* keeping that copy preserves the promotion instead of demoting the memory.
|
|
@@ -36,8 +33,8 @@
|
|
|
36
33
|
* Plain `<`/`>`, NOT `localeCompare`: `localeCompare` is locale- and
|
|
37
34
|
* ICU-version-dependent (a determinism leak in its own right) and needlessly
|
|
38
35
|
* slow for a tiebreak that only needs a total order. The metadata keys are
|
|
39
|
-
* only computed on a content tie, which is rare
|
|
40
|
-
*
|
|
36
|
+
* only computed on a content tie, which is rare, so the per-compare Set/sort
|
|
37
|
+
* cost never lands on the hot path.
|
|
41
38
|
*/
|
|
42
39
|
export function compareEntryIdentity(a, b) {
|
|
43
40
|
return (compareStrings(a.content, b.content) ||
|
|
@@ -90,13 +87,11 @@ export function compareScoredResults(a, b) {
|
|
|
90
87
|
*
|
|
91
88
|
* `ScoredPhysicsResult` (physics.ts) carries `{ memoryId, baseScore,
|
|
92
89
|
* clusterAmplification, finalScore }` -- NO `entry`/`content` in scope at
|
|
93
|
-
* that layer, so `compareEntryIdentity` cannot apply directly
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* MUTATES scores before the downstream content-aware merge sort runs -- so
|
|
99
|
-
* the tie key must be content-stable at THIS layer, not just downstream).
|
|
90
|
+
* that layer, so `compareEntryIdentity` cannot apply directly. With only the
|
|
91
|
+
* default memoryId key this is PER-INSTANCE-ONLY determinism; callers that need
|
|
92
|
+
* CROSS-INGEST stability supply `tieKeyOf` mapping the result to its memory
|
|
93
|
+
* CONTENT, because the baseScore tie order selects the cluster_top_k
|
|
94
|
+
* amplification set, which MUTATES scores before the content-aware merge sort.
|
|
100
95
|
*
|
|
101
96
|
* A factory (not a fixed-field comparator) because physics.ts re-sorts the
|
|
102
97
|
* same result array by two different score fields in sequence (`baseScore`
|
package/dist/config.d.ts
CHANGED
|
@@ -64,34 +64,33 @@ export interface HippoConfig {
|
|
|
64
64
|
enabled: boolean;
|
|
65
65
|
budget: number;
|
|
66
66
|
/** Skip a block identical to the one already injected this session
|
|
67
|
-
*
|
|
67
|
+
* Default true. Needs a session id from the hook payload. */
|
|
68
68
|
skipUnchanged: boolean;
|
|
69
69
|
/** Resend an unchanged block after this many consecutive skips, so long
|
|
70
70
|
* sessions still see pinned rules near the latest turn. Default 10; 0
|
|
71
71
|
* never resends an unchanged block. */
|
|
72
72
|
refreshTurns: number;
|
|
73
|
-
/**
|
|
74
|
-
*
|
|
75
|
-
* tokens fell 847 to 533 (docs/evals/2026-09-26-z1-prompt-recall-result.md). */
|
|
73
|
+
/** Gate the hook's backfill on the prompt's own content instead of the five
|
|
74
|
+
* newest memories. Default true: the same overlap for fewer tokens. */
|
|
76
75
|
promptRecall: boolean;
|
|
77
|
-
/**
|
|
76
|
+
/** Overlap metric for the prompt-recall gate. Default 'jaccard' (tuned). */
|
|
78
77
|
promptRecallMetric: PromptRecallMetric;
|
|
79
|
-
/**
|
|
78
|
+
/** Minimum overlap score to admit a candidate. Default 0.04 (tuned). */
|
|
80
79
|
promptRecallThreshold: number;
|
|
81
|
-
/**
|
|
80
|
+
/** Minimum shared tokens to admit a candidate. Default 2. */
|
|
82
81
|
promptRecallMinShared: number;
|
|
83
|
-
/**
|
|
82
|
+
/** Max prompt-recall entries injected per prompt. Default 5 (tuned). */
|
|
84
83
|
promptRecallMaxItems: number;
|
|
85
|
-
/**
|
|
84
|
+
/** FTS candidate pool size per store before gating. Default 100. */
|
|
86
85
|
promptRecallCandidates: number;
|
|
87
86
|
};
|
|
88
|
-
/** Memory scope isolation
|
|
87
|
+
/** Memory scope isolation: when true (default), ambient context
|
|
89
88
|
* (`hippo context`, the UserPromptSubmit hook, /v1/context, MCP
|
|
90
89
|
* hippo_context) excludes memories owned by OTHER projects; explicit
|
|
91
90
|
* recall is unaffected. Set false to disable the ORIGIN PARTITION only -
|
|
92
91
|
* the secret veto is unconditional for ambient surfaces and no config or
|
|
93
92
|
* flag re-includes secret-flagged rows (explicit recall still returns
|
|
94
|
-
* them).
|
|
93
|
+
* them). */
|
|
95
94
|
contextProjectIsolation: boolean;
|
|
96
95
|
extraction: {
|
|
97
96
|
enabled: boolean | 'auto';
|
|
@@ -110,11 +109,8 @@ export interface HippoConfig {
|
|
|
110
109
|
ambient: {
|
|
111
110
|
enabled: boolean;
|
|
112
111
|
};
|
|
113
|
-
/**
|
|
114
|
-
* (
|
|
115
|
-
* E2 weights (src/memory-value-weights.ts) only run when explicitly
|
|
116
|
-
* enabled; no other knobs in v1 (the rescue budget is a code constant
|
|
117
|
-
* tied to E2 evidence, not user-tunable). */
|
|
112
|
+
/** Opt-in learned memory-value rescue veto on the sleep decay pass. Default OFF: the frozen weights
|
|
113
|
+
* (src/memory-value-weights.ts) only run when enabled; the rescue budget is a code constant, not user-tunable. */
|
|
118
114
|
memoryValue: {
|
|
119
115
|
enabled: boolean;
|
|
120
116
|
};
|
|
@@ -131,8 +127,8 @@ export interface HippoConfig {
|
|
|
131
127
|
* Default 180. 0 keeps dormant memories forever. */
|
|
132
128
|
retentionDays: number;
|
|
133
129
|
};
|
|
134
|
-
/**
|
|
135
|
-
* changed since storage. Default OFF
|
|
130
|
+
/** Tags a memory `churn-stale` when its named file/symbol/script
|
|
131
|
+
* changed since storage. Default OFF until a measurement justifies the flip. */
|
|
136
132
|
churnStaleness: {
|
|
137
133
|
enabled: boolean;
|
|
138
134
|
};
|
|
@@ -150,6 +146,11 @@ export interface HippoConfig {
|
|
|
150
146
|
pilot: {
|
|
151
147
|
holdoutRateBp: number;
|
|
152
148
|
};
|
|
149
|
+
/** How a folder's project is named. `remote: false` drops the origin-remote rule, leaving
|
|
150
|
+
* `.hippo-project.json` then the folder name. Read from the global store's config only, so every store agrees. */
|
|
151
|
+
projectIdentity: {
|
|
152
|
+
remote: boolean;
|
|
153
|
+
};
|
|
153
154
|
}
|
|
154
155
|
export declare function loadConfig(hippoRoot: string): HippoConfig;
|
|
155
156
|
//# sourceMappingURL=config.d.ts.map
|