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/doctor.js
CHANGED
|
@@ -139,7 +139,8 @@ function projectsCheck(globalRoot) {
|
|
|
139
139
|
const r = planProjectRepair(db, globalRoot, resolveTenantId({}));
|
|
140
140
|
const found = [
|
|
141
141
|
r.copies.length > 0 ? `${r.copies.length} imported notes copied under the wrong project` : '',
|
|
142
|
-
r.folds.length > 0 ?
|
|
142
|
+
r.folds.length > 0 ? `old project names that now resolve to another project: ${r.folds.map((f) => `${f.from} -> ${f.into}`).join(', ')}` : '',
|
|
143
|
+
r.collisions.length > 0 ? `old project names shared by several projects, folded by hand only: ${r.collisions.map((c) => `${c.name} (${c.ids.join(', ')})`).join('; ')}` : '',
|
|
143
144
|
r.toProject.length + r.setAside.length > 0 ? `${r.toProject.length + r.setAside.length} merged memories tagged user-global` : '',
|
|
144
145
|
].filter((s) => s !== '');
|
|
145
146
|
return found.length === 0
|
|
@@ -154,124 +155,138 @@ function projectsCheck(globalRoot) {
|
|
|
154
155
|
closeHippoDb(db);
|
|
155
156
|
}
|
|
156
157
|
}
|
|
158
|
+
function nodeCheck(node) {
|
|
159
|
+
return versionAtLeast(node, MIN_NODE)
|
|
160
|
+
? { id: 'node', status: 'pass', detail: `Node.js ${node}` }
|
|
161
|
+
: { id: 'node', status: 'fail', detail: `Node.js ${node} is older than ${MIN_NODE}`, fix: `Install Node.js ${MIN_NODE} or newer` };
|
|
162
|
+
}
|
|
163
|
+
/** The store the checks run against (project first, then global), and the check that says which. */
|
|
164
|
+
function storeCheck(local, globalRoot, hasGlobal) {
|
|
165
|
+
if (local !== null && isInitialized(local)) {
|
|
166
|
+
return { store: local, check: { id: 'store', status: 'pass', detail: `project store at ${local}${hasGlobal ? ` (global store at ${globalRoot} too)` : ''}` } };
|
|
167
|
+
}
|
|
168
|
+
if (local !== null) {
|
|
169
|
+
// The walk stops at the first .hippo it finds, so a bare one (no hippo.db) blocks a parent or global store too.
|
|
170
|
+
return { store: null, check: { id: 'store', status: 'fail', detail: `${local} has no hippo.db, so hippo commands run here stop at it`, fix: `run hippo init in ${path.dirname(local)}, or remove that .hippo folder` } };
|
|
171
|
+
}
|
|
172
|
+
if (hasGlobal) {
|
|
173
|
+
return { store: globalRoot, check: { id: 'store', status: 'warn', detail: `no project store here; using the global store at ${globalRoot}`, fix: 'hippo init (in the project root)' } };
|
|
174
|
+
}
|
|
175
|
+
return { store: null, check: { id: 'store', status: 'fail', detail: 'no hippo store found (project or global)', fix: 'hippo init (in the project root), or hippo init --global' } };
|
|
176
|
+
}
|
|
177
|
+
function schemaCheck(have, want) {
|
|
178
|
+
return have === want
|
|
179
|
+
? { id: 'schema', status: 'pass', detail: `database schema v${have}` }
|
|
180
|
+
: have > want
|
|
181
|
+
? { id: 'schema', status: 'fail', detail: `database schema v${have} is newer than this hippo (v${want})`, fix: 'npm install -g hippo-memory@latest' }
|
|
182
|
+
: { id: 'schema', status: 'info', detail: `database schema v${have}; hippo migrates it to v${want} on the next write` };
|
|
183
|
+
}
|
|
184
|
+
function memoriesCheck(db) {
|
|
185
|
+
const memories = countTableRows(db, 'memories');
|
|
186
|
+
const dormant = countTableRows(db, 'dormant_memories');
|
|
187
|
+
const memoryCheck = { id: 'memories', status: 'info', detail: `${memories ?? '?'} memories${dormant !== null ? `, ${dormant} dormant` : ''}` };
|
|
188
|
+
if (memories === 0) {
|
|
189
|
+
memoryCheck.status = 'warn';
|
|
190
|
+
memoryCheck.fix = 'hippo learn --git (seed lessons from git history)';
|
|
191
|
+
}
|
|
192
|
+
return memoryCheck;
|
|
193
|
+
}
|
|
194
|
+
function tokensCheck(db, since) {
|
|
195
|
+
try {
|
|
196
|
+
// SAFETY: COUNT/SUM aggregate row.
|
|
197
|
+
const row = db.prepare(`SELECT COUNT(CASE WHEN event = 'inject' THEN 1 END) AS n,
|
|
198
|
+
COALESCE(SUM(CASE WHEN event = 'inject' THEN tokens END), 0) AS t,
|
|
199
|
+
COALESCE(SUM(CASE WHEN event = 'reread' THEN tokens END), 0) AS r
|
|
200
|
+
FROM token_ledger WHERE ts >= ?`).get(since);
|
|
201
|
+
return {
|
|
202
|
+
id: 'tokens',
|
|
203
|
+
status: 'info',
|
|
204
|
+
detail: `${Number(row?.n ?? 0)} memory blocks sent to agents in 7 days, about ${Number(row?.t ?? 0)} tokens sent and ${Number(row?.r ?? 0)} re-read by later model calls (hippo tokens for detail)`,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return { id: 'tokens', status: 'info', detail: 'no token ledger yet (created on the next write)' };
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/** Checks that read the store's database; a failed open becomes a failed schema check after whatever already passed. */
|
|
212
|
+
function databaseChecks(store, now) {
|
|
213
|
+
const checks = [];
|
|
214
|
+
let db = null;
|
|
215
|
+
try {
|
|
216
|
+
db = openHippoDbReadOnly(store);
|
|
217
|
+
const have = getSchemaVersion(db);
|
|
218
|
+
checks.push(schemaCheck(have, getCurrentSchemaVersion()));
|
|
219
|
+
checks.push(memoriesCheck(db));
|
|
220
|
+
const since = new Date(now.getTime() - 7 * 86_400_000).toISOString();
|
|
221
|
+
checks.push(tokensCheck(db, since));
|
|
222
|
+
checks.push(failuresCheck(db, since, have));
|
|
223
|
+
checks.push(sleepCheck(db, now));
|
|
224
|
+
checks.push(compactionsCheck(db, now));
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
checks.push({
|
|
228
|
+
id: 'schema',
|
|
229
|
+
status: 'fail',
|
|
230
|
+
detail: `cannot open the database: ${err instanceof Error ? err.message : String(err)}`,
|
|
231
|
+
fix: err instanceof IncompatibleBinaryError ? 'npm install -g hippo-memory@latest' : 'check file permissions on the .hippo folder',
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
if (db !== null)
|
|
236
|
+
closeHippoDb(db);
|
|
237
|
+
}
|
|
238
|
+
return checks;
|
|
239
|
+
}
|
|
240
|
+
// Each hook and what it does, so a partial install says what is missing.
|
|
241
|
+
const CLAUDE_CODE_HOOKS = [
|
|
242
|
+
['hippo context --pinned-only', 'per-prompt memory'],
|
|
243
|
+
['hippo session-end', 'session-end capture and sleep'],
|
|
244
|
+
['hippo pre-compact', 'compaction snapshot and memories request'],
|
|
245
|
+
['hippo compact-resume', 'resume after compaction'],
|
|
246
|
+
['hippo post-compact', 'saving the memories a compaction lists'],
|
|
247
|
+
['hippo capture-error', 'failed-tool capture'],
|
|
248
|
+
];
|
|
249
|
+
function claudeCodeCheck(home) {
|
|
250
|
+
const claudeDir = path.join(home, '.claude');
|
|
251
|
+
if (!fs.existsSync(claudeDir)) {
|
|
252
|
+
return { id: 'claude-code', status: 'info', detail: 'Claude Code not found; other agents can use hippo over MCP (hippo mcp)' };
|
|
253
|
+
}
|
|
254
|
+
const settings = readJson(path.join(claudeDir, 'settings.json'));
|
|
255
|
+
const text = settings === null ? '' : JSON.stringify(settings);
|
|
256
|
+
const viaPlugin = /hippo-memory@/.test(text);
|
|
257
|
+
const missing = CLAUDE_CODE_HOOKS.filter(([marker]) => !text.includes(marker)).map(([, what]) => what);
|
|
258
|
+
if (viaPlugin) {
|
|
259
|
+
return { id: 'claude-code', status: 'pass', detail: 'Claude Code: hippo plugin enabled (all hooks, including compaction and failed-tool capture)' };
|
|
260
|
+
}
|
|
261
|
+
if (missing.length === 0) {
|
|
262
|
+
return { id: 'claude-code', status: 'pass', detail: 'Claude Code: all hippo hooks installed, including compaction and failed-tool capture' };
|
|
263
|
+
}
|
|
264
|
+
if (missing.length === CLAUDE_CODE_HOOKS.length) {
|
|
265
|
+
return { id: 'claude-code', status: 'warn', detail: 'Claude Code found, but no hippo hooks are installed', fix: 'hippo hook install claude-code' };
|
|
266
|
+
}
|
|
267
|
+
return { id: 'claude-code', status: 'warn', detail: `Claude Code: hippo hooks missing for ${missing.join(', ')}`, fix: 'hippo hook install claude-code (adds only what is missing)' };
|
|
268
|
+
}
|
|
157
269
|
/** Run every check. Never throws for a broken install; broken parts become failed checks. */
|
|
158
270
|
export function runDoctor(opts) {
|
|
159
271
|
const cwd = opts.cwd ?? process.cwd();
|
|
160
272
|
const home = opts.home ?? os.homedir();
|
|
161
273
|
const now = opts.now ?? new Date();
|
|
162
274
|
const checks = [];
|
|
163
|
-
|
|
164
|
-
checks.push(versionAtLeast(node, MIN_NODE)
|
|
165
|
-
? { id: 'node', status: 'pass', detail: `Node.js ${node}` }
|
|
166
|
-
: { id: 'node', status: 'fail', detail: `Node.js ${node} is older than ${MIN_NODE}`, fix: `Install Node.js ${MIN_NODE} or newer` });
|
|
275
|
+
checks.push(nodeCheck(opts.nodeVersion ?? process.versions.node));
|
|
167
276
|
const local = findHippoStoreDir(cwd);
|
|
168
277
|
const globalRoot = getGlobalRoot();
|
|
169
278
|
const hasGlobal = isInitialized(globalRoot);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
checks.push(
|
|
174
|
-
}
|
|
175
|
-
else if (local !== null) {
|
|
176
|
-
// The walk stops at the first .hippo it finds, so a bare one (no hippo.db) blocks a parent or global store too.
|
|
177
|
-
checks.push({ id: 'store', status: 'fail', detail: `${local} has no hippo.db, so hippo commands run here stop at it`, fix: `run hippo init in ${path.dirname(local)}, or remove that .hippo folder` });
|
|
178
|
-
}
|
|
179
|
-
else if (hasGlobal) {
|
|
180
|
-
store = globalRoot;
|
|
181
|
-
checks.push({ id: 'store', status: 'warn', detail: `no project store here; using the global store at ${globalRoot}`, fix: 'hippo init (in the project root)' });
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
checks.push({ id: 'store', status: 'fail', detail: 'no hippo store found (project or global)', fix: 'hippo init (in the project root), or hippo init --global' });
|
|
185
|
-
}
|
|
186
|
-
if (store !== null) {
|
|
187
|
-
let db = null;
|
|
188
|
-
try {
|
|
189
|
-
db = openHippoDbReadOnly(store);
|
|
190
|
-
const have = getSchemaVersion(db);
|
|
191
|
-
const want = getCurrentSchemaVersion();
|
|
192
|
-
checks.push(have === want
|
|
193
|
-
? { id: 'schema', status: 'pass', detail: `database schema v${have}` }
|
|
194
|
-
: have > want
|
|
195
|
-
? { id: 'schema', status: 'fail', detail: `database schema v${have} is newer than this hippo (v${want})`, fix: 'npm install -g hippo-memory@latest' }
|
|
196
|
-
: { id: 'schema', status: 'info', detail: `database schema v${have}; hippo migrates it to v${want} on the next write` });
|
|
197
|
-
const memories = countTableRows(db, 'memories');
|
|
198
|
-
const dormant = countTableRows(db, 'dormant_memories');
|
|
199
|
-
const memoryCheck = { id: 'memories', status: 'info', detail: `${memories ?? '?'} memories${dormant !== null ? `, ${dormant} dormant` : ''}` };
|
|
200
|
-
if (memories === 0) {
|
|
201
|
-
memoryCheck.status = 'warn';
|
|
202
|
-
memoryCheck.fix = 'hippo learn --git (seed lessons from git history)';
|
|
203
|
-
}
|
|
204
|
-
checks.push(memoryCheck);
|
|
205
|
-
const since = new Date(now.getTime() - 7 * 86_400_000).toISOString();
|
|
206
|
-
try {
|
|
207
|
-
// SAFETY: COUNT/SUM aggregate row.
|
|
208
|
-
const row = db.prepare(`SELECT COUNT(CASE WHEN event = 'inject' THEN 1 END) AS n,
|
|
209
|
-
COALESCE(SUM(CASE WHEN event = 'inject' THEN tokens END), 0) AS t,
|
|
210
|
-
COALESCE(SUM(CASE WHEN event = 'reread' THEN tokens END), 0) AS r
|
|
211
|
-
FROM token_ledger WHERE ts >= ?`).get(since);
|
|
212
|
-
checks.push({
|
|
213
|
-
id: 'tokens',
|
|
214
|
-
status: 'info',
|
|
215
|
-
detail: `${Number(row?.n ?? 0)} memory blocks sent to agents in 7 days, about ${Number(row?.t ?? 0)} tokens sent and ${Number(row?.r ?? 0)} re-read by later model calls (hippo tokens for detail)`,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
catch {
|
|
219
|
-
checks.push({ id: 'tokens', status: 'info', detail: 'no token ledger yet (created on the next write)' });
|
|
220
|
-
}
|
|
221
|
-
checks.push(failuresCheck(db, since, have));
|
|
222
|
-
checks.push(sleepCheck(db, now));
|
|
223
|
-
checks.push(compactionsCheck(db, now));
|
|
224
|
-
}
|
|
225
|
-
catch (err) {
|
|
226
|
-
checks.push({
|
|
227
|
-
id: 'schema',
|
|
228
|
-
status: 'fail',
|
|
229
|
-
detail: `cannot open the database: ${err instanceof Error ? err.message : String(err)}`,
|
|
230
|
-
fix: err instanceof IncompatibleBinaryError ? 'npm install -g hippo-memory@latest' : 'check file permissions on the .hippo folder',
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
finally {
|
|
234
|
-
if (db !== null)
|
|
235
|
-
closeHippoDb(db);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
279
|
+
const { store, check } = storeCheck(local, globalRoot, hasGlobal);
|
|
280
|
+
checks.push(check);
|
|
281
|
+
if (store !== null)
|
|
282
|
+
checks.push(...databaseChecks(store, now));
|
|
238
283
|
const holdoutRateBp = store === null ? 0 : loadConfig(store).pilot.holdoutRateBp;
|
|
239
284
|
if (holdoutRateBp > 0) {
|
|
240
285
|
checks.push({ id: 'pilot', status: 'info', detail: `pilot holdout on: about ${holdoutRateBp / 100}% of sessions get no memories pushed by hippo (pilot.holdoutRateBp=${holdoutRateBp})` });
|
|
241
286
|
}
|
|
242
287
|
if (hasGlobal)
|
|
243
288
|
checks.push(projectsCheck(globalRoot));
|
|
244
|
-
|
|
245
|
-
if (fs.existsSync(claudeDir)) {
|
|
246
|
-
const settings = readJson(path.join(claudeDir, 'settings.json'));
|
|
247
|
-
const text = settings === null ? '' : JSON.stringify(settings);
|
|
248
|
-
const viaPlugin = /hippo-memory@/.test(text);
|
|
249
|
-
// Each hook and what it does, so a partial install says what is missing.
|
|
250
|
-
const hooks = [
|
|
251
|
-
['hippo context --pinned-only', 'per-prompt memory'],
|
|
252
|
-
['hippo session-end', 'session-end capture and sleep'],
|
|
253
|
-
['hippo pre-compact', 'compaction snapshot and memories request'],
|
|
254
|
-
['hippo compact-resume', 'resume after compaction'],
|
|
255
|
-
['hippo post-compact', 'saving the memories a compaction lists'],
|
|
256
|
-
['hippo capture-error', 'failed-tool capture'],
|
|
257
|
-
];
|
|
258
|
-
const missing = hooks.filter(([marker]) => !text.includes(marker)).map(([, what]) => what);
|
|
259
|
-
if (viaPlugin) {
|
|
260
|
-
checks.push({ id: 'claude-code', status: 'pass', detail: 'Claude Code: hippo plugin enabled (all hooks, including compaction and failed-tool capture)' });
|
|
261
|
-
}
|
|
262
|
-
else if (missing.length === 0) {
|
|
263
|
-
checks.push({ id: 'claude-code', status: 'pass', detail: 'Claude Code: all hippo hooks installed, including compaction and failed-tool capture' });
|
|
264
|
-
}
|
|
265
|
-
else if (missing.length === hooks.length) {
|
|
266
|
-
checks.push({ id: 'claude-code', status: 'warn', detail: 'Claude Code found, but no hippo hooks are installed', fix: 'hippo hook install claude-code' });
|
|
267
|
-
}
|
|
268
|
-
else {
|
|
269
|
-
checks.push({ id: 'claude-code', status: 'warn', detail: `Claude Code: hippo hooks missing for ${missing.join(', ')}`, fix: 'hippo hook install claude-code (adds only what is missing)' });
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
checks.push({ id: 'claude-code', status: 'info', detail: 'Claude Code not found; other agents can use hippo over MCP (hippo mcp)' });
|
|
274
|
-
}
|
|
289
|
+
checks.push(claudeCodeCheck(home));
|
|
275
290
|
if (isCodexPresent(home))
|
|
276
291
|
checks.push(codexCheck(home));
|
|
277
292
|
checks.push({ id: 'embeddings', status: 'info', detail: isEmbeddingAvailable() ? 'local embeddings available (hybrid search)' : 'embeddings not installed; recall uses BM25 (optional: hippo embed --help)' });
|
package/dist/dormant.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { rejectionDigest } from './rejection.js';
|
|
2
|
+
import { escapeLike } from './escape.js';
|
|
2
3
|
const DEFAULT_LIST_LIMIT = 20;
|
|
3
4
|
/**
|
|
4
5
|
* Insert (or refresh) the dormant snapshot for `move.entry`. Does not touch
|
|
@@ -17,10 +18,6 @@ export function insertDormantRow(db, move) {
|
|
|
17
18
|
dormant_at = excluded.dormant_at
|
|
18
19
|
`).run(move.entry.tenantId, move.entry.id, move.entry.content, JSON.stringify(move.entry), move.reason, move.strength, move.dormantAt);
|
|
19
20
|
}
|
|
20
|
-
/** Escape LIKE metacharacters so a search term matches literally (ESCAPE '\'). */
|
|
21
|
-
function escapeLike(term) {
|
|
22
|
-
return term.replace(/[\\%_]/g, (ch) => `\\${ch}`);
|
|
23
|
-
}
|
|
24
21
|
/**
|
|
25
22
|
* Parse a stored snapshot back into a MemoryEntry, or null when the row no
|
|
26
23
|
* longer matches the snapshot it carries (edited by hand, or truncated).
|
|
@@ -8,14 +8,10 @@
|
|
|
8
8
|
* read their key from a conventional env var. The provider is selected by
|
|
9
9
|
* `config.embeddings.provider` (default `'local'`).
|
|
10
10
|
*
|
|
11
|
-
* Design contract
|
|
12
|
-
* - Local provider `id` is the BARE model string
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* `${id}#t2`, docs/plans/2026-07-09-recall-determinism.md T1), the STORED
|
|
16
|
-
* identity carries a `#t<N>` suffix and pre-#t2 stores get exactly one
|
|
17
|
-
* forced reindex on their next embed-touching operation — deliberate,
|
|
18
|
-
* because their vectors were computed over path-contaminated text.)
|
|
11
|
+
* Design contract:
|
|
12
|
+
* - Local provider `id` is the BARE model string; the STORED identity adds a `#t<N>`
|
|
13
|
+
* embed-text-format suffix (`embeddingIndexIdentity`), so older stores reindex once:
|
|
14
|
+
* their vectors were computed over path-contaminated text.
|
|
19
15
|
* - API provider `id` is `${kind}:${model}`; switching to/from an API embedder
|
|
20
16
|
* (or a dimension change) flips the identity and triggers the existing
|
|
21
17
|
* reindex-on-change path.
|
|
@@ -8,14 +8,10 @@
|
|
|
8
8
|
* read their key from a conventional env var. The provider is selected by
|
|
9
9
|
* `config.embeddings.provider` (default `'local'`).
|
|
10
10
|
*
|
|
11
|
-
* Design contract
|
|
12
|
-
* - Local provider `id` is the BARE model string
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* `${id}#t2`, docs/plans/2026-07-09-recall-determinism.md T1), the STORED
|
|
16
|
-
* identity carries a `#t<N>` suffix and pre-#t2 stores get exactly one
|
|
17
|
-
* forced reindex on their next embed-touching operation — deliberate,
|
|
18
|
-
* because their vectors were computed over path-contaminated text.)
|
|
11
|
+
* Design contract:
|
|
12
|
+
* - Local provider `id` is the BARE model string; the STORED identity adds a `#t<N>`
|
|
13
|
+
* embed-text-format suffix (`embeddingIndexIdentity`), so older stores reindex once:
|
|
14
|
+
* their vectors were computed over path-contaminated text.
|
|
19
15
|
* - API provider `id` is `${kind}:${model}`; switching to/from an API embedder
|
|
20
16
|
* (or a dimension change) flips the identity and triggers the existing
|
|
21
17
|
* reindex-on-change path.
|
package/dist/embeddings.js
CHANGED
|
@@ -314,7 +314,7 @@ export async function embedMemory(hippoRoot, entry, model) {
|
|
|
314
314
|
try {
|
|
315
315
|
const identity = provider.id;
|
|
316
316
|
if (embeddingModelRequiresReindex(hippoRoot, identity)) {
|
|
317
|
-
//
|
|
317
|
+
// Host-wide rebuild. The embedding index is keyed by entry.id
|
|
318
318
|
// (which is tenant-scoped) but the index itself is one per hippoRoot.
|
|
319
319
|
// Cross-tenant content equivalence is visible at the vector level.
|
|
320
320
|
// Per-tenant indices would be a larger architecture change.
|
|
@@ -357,6 +357,57 @@ export async function embedMemory(hippoRoot, entry, model) {
|
|
|
357
357
|
log.warn(`skipped embedding ${entry.id} (${err instanceof Error ? err.message : String(err)}); run 'hippo embed' to backfill`);
|
|
358
358
|
});
|
|
359
359
|
}
|
|
360
|
+
/** Throws when an unavailable provider is a misconfiguration rather than an intentional no-op. */
|
|
361
|
+
function throwIfProviderKeyMissing(hippoRoot, provider) {
|
|
362
|
+
// A configured (non-disabled) API provider with a missing key is a
|
|
363
|
+
// misconfiguration, not a no-op: surface it so programmatic callers of the
|
|
364
|
+
// exported embedAll() learn nothing was written. Local-not-installed and an
|
|
365
|
+
// explicit enabled=false stay silent no-ops (best-effort / intentional).
|
|
366
|
+
const cfg = loadConfig(hippoRoot).embeddings;
|
|
367
|
+
if (provider.kind !== 'local' &&
|
|
368
|
+
cfg.enabled !== false &&
|
|
369
|
+
provider.keyEnv &&
|
|
370
|
+
!envByName(provider.keyEnv)?.trim()) {
|
|
371
|
+
throw new Error(`Embedding provider '${provider.kind}' is configured but ${provider.keyEnv} is not set.`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// Embed entries without a cached vector in save-checkpointed chunks.
|
|
375
|
+
// provider.embed batches internally (one HTTP request per batchSize for API
|
|
376
|
+
// providers; sequential for local). A `[]` row means that single item could
|
|
377
|
+
// not be embedded and is left for a later run (resumable). On a hard provider
|
|
378
|
+
// failure mid-backfill we persist the chunks already embedded this run rather
|
|
379
|
+
// than discarding paid progress, then stop and resume on the next run.
|
|
380
|
+
async function backfillPending(hippoRoot, provider, pending, model) {
|
|
381
|
+
let count = 0;
|
|
382
|
+
// Initialized to `undefined` (not a known-evidence literal like `null`) so
|
|
383
|
+
// it stays a plain `unknown` binding for the arbitrary caught value below;
|
|
384
|
+
// falsy either way, so `if (backfillError)` behaves identically.
|
|
385
|
+
let backfillError = undefined;
|
|
386
|
+
const SAVE_CHUNK = 64;
|
|
387
|
+
for (let i = 0; i < pending.length; i += SAVE_CHUNK) {
|
|
388
|
+
const chunk = pending.slice(i, i + SAVE_CHUNK);
|
|
389
|
+
let vectors;
|
|
390
|
+
try {
|
|
391
|
+
vectors = await provider.embed(chunk.map((e) => embeddingInputText(e)), 'passage');
|
|
392
|
+
}
|
|
393
|
+
catch (err) {
|
|
394
|
+
// Preserve the chunks already saved this run, then surface the failure
|
|
395
|
+
// below so the explicit `hippo embed` path never reports a false success.
|
|
396
|
+
backfillError = err;
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
const rows = [];
|
|
400
|
+
for (let j = 0; j < chunk.length; j++) {
|
|
401
|
+
const vec = vectors[j];
|
|
402
|
+
if (vec && vec.length > 0)
|
|
403
|
+
rows.push([chunk[j].id, vec]);
|
|
404
|
+
else
|
|
405
|
+
noteSkippedEmbedding(chunk[j].id);
|
|
406
|
+
}
|
|
407
|
+
count += withVectorDb(hippoRoot, (db) => upsertVectors(db, rows, model));
|
|
408
|
+
}
|
|
409
|
+
return { count, backfillError };
|
|
410
|
+
}
|
|
360
411
|
/**
|
|
361
412
|
* Embed all entries in hippoRoot that don't already have cached vectors.
|
|
362
413
|
* Prunes orphaned embeddings for memories that no longer exist.
|
|
@@ -364,22 +415,12 @@ export async function embedMemory(hippoRoot, entry, model) {
|
|
|
364
415
|
*/
|
|
365
416
|
export async function embedAll(hippoRoot, model, provider = resolveEmbeddingProvider(hippoRoot, { model })) {
|
|
366
417
|
if (!provider.isAvailable()) {
|
|
367
|
-
|
|
368
|
-
// misconfiguration, not a no-op: surface it so programmatic callers of the
|
|
369
|
-
// exported embedAll() learn nothing was written. Local-not-installed and an
|
|
370
|
-
// explicit enabled=false stay silent no-ops (best-effort / intentional).
|
|
371
|
-
const cfg = loadConfig(hippoRoot).embeddings;
|
|
372
|
-
if (provider.kind !== 'local' &&
|
|
373
|
-
cfg.enabled !== false &&
|
|
374
|
-
provider.keyEnv &&
|
|
375
|
-
!envByName(provider.keyEnv)?.trim()) {
|
|
376
|
-
throw new Error(`Embedding provider '${provider.kind}' is configured but ${provider.keyEnv} is not set.`);
|
|
377
|
-
}
|
|
418
|
+
throwIfProviderKeyMissing(hippoRoot, provider);
|
|
378
419
|
return 0;
|
|
379
420
|
}
|
|
380
421
|
return withEmbedLock(hippoRoot, async () => {
|
|
381
422
|
const identity = provider.id;
|
|
382
|
-
//
|
|
423
|
+
// Host-wide by design. embedAll backfills vectors for all tenants'
|
|
383
424
|
// entries into the per-host embedding index. Per-tenant filtering would
|
|
384
425
|
// produce partial indices and break recall.
|
|
385
426
|
const entries = loadAllEntries(hippoRoot);
|
|
@@ -395,41 +436,8 @@ export async function embedAll(hippoRoot, model, provider = resolveEmbeddingProv
|
|
|
395
436
|
deleteOrphanVectors(db);
|
|
396
437
|
return storedVectorIds(db);
|
|
397
438
|
});
|
|
398
|
-
// Embed entries without a cached vector in save-checkpointed chunks.
|
|
399
|
-
// provider.embed batches internally (one HTTP request per batchSize for API
|
|
400
|
-
// providers; sequential for local). A `[]` row means that single item could
|
|
401
|
-
// not be embedded and is left for a later run (resumable). On a hard provider
|
|
402
|
-
// failure mid-backfill we persist the chunks already embedded this run rather
|
|
403
|
-
// than discarding paid progress, then stop and resume on the next run.
|
|
404
439
|
const pending = entries.filter((e) => !embedded.has(e.id));
|
|
405
|
-
|
|
406
|
-
// Initialized to `undefined` (not a known-evidence literal like `null`) so
|
|
407
|
-
// it stays a plain `unknown` binding for the arbitrary caught value below;
|
|
408
|
-
// falsy either way, so `if (backfillError)` behaves identically.
|
|
409
|
-
let backfillError = undefined;
|
|
410
|
-
const SAVE_CHUNK = 64;
|
|
411
|
-
for (let i = 0; i < pending.length; i += SAVE_CHUNK) {
|
|
412
|
-
const chunk = pending.slice(i, i + SAVE_CHUNK);
|
|
413
|
-
let vectors;
|
|
414
|
-
try {
|
|
415
|
-
vectors = await provider.embed(chunk.map((e) => embeddingInputText(e)), 'passage');
|
|
416
|
-
}
|
|
417
|
-
catch (err) {
|
|
418
|
-
// Preserve the chunks already saved this run, then surface the failure
|
|
419
|
-
// below so the explicit `hippo embed` path never reports a false success.
|
|
420
|
-
backfillError = err;
|
|
421
|
-
break;
|
|
422
|
-
}
|
|
423
|
-
const rows = [];
|
|
424
|
-
for (let j = 0; j < chunk.length; j++) {
|
|
425
|
-
const vec = vectors[j];
|
|
426
|
-
if (vec && vec.length > 0)
|
|
427
|
-
rows.push([chunk[j].id, vec]);
|
|
428
|
-
else
|
|
429
|
-
noteSkippedEmbedding(chunk[j].id);
|
|
430
|
-
}
|
|
431
|
-
count += withVectorDb(hippoRoot, (db) => upsertVectors(db, rows, model));
|
|
432
|
-
}
|
|
440
|
+
const { count, backfillError } = await backfillPending(hippoRoot, provider, pending, model);
|
|
433
441
|
saveStoredEmbeddingModel(hippoRoot, identity);
|
|
434
442
|
// Partial progress is now persisted; surface a hard backfill failure so the
|
|
435
443
|
// explicit embed path reports it (best-effort callers go via embedMemory).
|
package/dist/env.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export declare function envTenant(): string;
|
|
|
35
35
|
export declare function envSkipAutoIntegrations(): boolean;
|
|
36
36
|
export declare function envSkipPostinstall(): boolean;
|
|
37
37
|
export declare function envMcpStdio(): boolean;
|
|
38
|
-
/**
|
|
38
|
+
/** `1` or `true`, so `0` and `false` turn it off; `true` stays on for anyone who set it that way. */
|
|
39
39
|
export declare function envRequireServer(): boolean;
|
|
40
40
|
export declare function envRequireSessionScopedFreshTail(): boolean;
|
|
41
41
|
export declare function envStdinWaitMs(): number | undefined;
|
package/dist/env.js
CHANGED
|
@@ -15,9 +15,9 @@ function positiveInt(name) {
|
|
|
15
15
|
const parsed = Number.parseInt(raw(name) ?? '', 10);
|
|
16
16
|
return parsed > 0 ? parsed : undefined;
|
|
17
17
|
}
|
|
18
|
-
/**
|
|
19
|
-
function
|
|
20
|
-
return
|
|
18
|
+
/** Trimmed, with an empty or whitespace-only value read as unset. */
|
|
19
|
+
function trimmed(name) {
|
|
20
|
+
return raw(name)?.trim() || undefined;
|
|
21
21
|
}
|
|
22
22
|
/** The whole environment, for code that takes it as an injectable map (agent-memory machines, owner checks, support bundles). */
|
|
23
23
|
export function processEnv() {
|
|
@@ -61,10 +61,10 @@ export function envHippoHome() { return raw('HIPPO_HOME')?.trim(); }
|
|
|
61
61
|
export function envXdgDataHome() { return raw('XDG_DATA_HOME')?.trim(); }
|
|
62
62
|
export function envHomeDir() { return raw('HOME') || raw('USERPROFILE'); }
|
|
63
63
|
export function envPath() { return raw('PATH'); }
|
|
64
|
-
export function envModelCache() { return
|
|
64
|
+
export function envModelCache() { return trimmed('HIPPO_MODEL_CACHE'); }
|
|
65
65
|
// Session, scope and tenant.
|
|
66
|
-
export function envHippoSessionId() { return
|
|
67
|
-
export function envClaudeCodeSessionId() { return
|
|
66
|
+
export function envHippoSessionId() { return trimmed('HIPPO_SESSION_ID'); }
|
|
67
|
+
export function envClaudeCodeSessionId() { return trimmed('CLAUDE_CODE_SESSION_ID'); }
|
|
68
68
|
export function envScope() { return raw('HIPPO_SCOPE'); }
|
|
69
69
|
export function envGstackSkill() { return raw('GSTACK_SKILL'); }
|
|
70
70
|
export function envOpenclawSkill() { return raw('OPENCLAW_SKILL'); }
|
|
@@ -76,8 +76,8 @@ export function envTenant() {
|
|
|
76
76
|
export function envSkipAutoIntegrations() { return isOne('HIPPO_SKIP_AUTO_INTEGRATIONS'); }
|
|
77
77
|
export function envSkipPostinstall() { return isOne('HIPPO_SKIP_POSTINSTALL'); }
|
|
78
78
|
export function envMcpStdio() { return isOne('HIPPO_MCP_STDIO'); }
|
|
79
|
-
/**
|
|
80
|
-
export function envRequireServer() { return
|
|
79
|
+
/** `1` or `true`, so `0` and `false` turn it off; `true` stays on for anyone who set it that way. */
|
|
80
|
+
export function envRequireServer() { return isOneOrTrue('HIPPO_REQUIRE_SERVER'); }
|
|
81
81
|
export function envRequireSessionScopedFreshTail() { return isOne('HIPPO_REQUIRE_SESSION_SCOPED_FRESH_TAIL'); }
|
|
82
82
|
export function envStdinWaitMs() { return positiveInt('HIPPO_STDIN_WAIT_MS'); }
|
|
83
83
|
export function envLogLevel() { return raw('HIPPO_LOG')?.trim().toLowerCase() ?? ''; }
|
|
@@ -89,18 +89,18 @@ export function envApiKey() { return raw('HIPPO_API_KEY'); }
|
|
|
89
89
|
export function envClientIpHeader() { return raw('HIPPO_CLIENT_IP_HEADER')?.trim().toLowerCase(); }
|
|
90
90
|
export function envTrustedProxies() { return raw('HIPPO_TRUSTED_PROXIES'); }
|
|
91
91
|
export function envMcpSseMaxStreams() { return positiveInt('MCP_SSE_MAX_STREAMS'); }
|
|
92
|
-
export function envMcpSseHeartbeatMs() { return
|
|
93
|
-
export function envMcpSseMaxAgeSec() { return
|
|
92
|
+
export function envMcpSseHeartbeatMs() { return positiveInt('MCP_SSE_HEARTBEAT_MS'); }
|
|
93
|
+
export function envMcpSseMaxAgeSec() { return positiveInt('MCP_SSE_MAX_AGE_SEC'); }
|
|
94
94
|
// LLM and reranker credentials and knobs.
|
|
95
95
|
export function envAnthropicApiKey() { return raw('ANTHROPIC_API_KEY'); }
|
|
96
96
|
export function envLlmTimeoutMs() { return positiveInt('HIPPO_LLM_TIMEOUT_MS'); }
|
|
97
|
-
export function envTypesafeApiKey() { return
|
|
97
|
+
export function envTypesafeApiKey() { return trimmed('TYPESAFE_API_KEY'); }
|
|
98
98
|
export function envJevTimeoutMs() { return positiveInt('HIPPO_JEV_TIMEOUT_MS'); }
|
|
99
99
|
export function envJevModel() { return raw('HIPPO_JEV_MODEL'); }
|
|
100
100
|
export function envLlmRerankerUrl() { return raw('HIPPO_LLM_RERANKER_URL'); }
|
|
101
101
|
export function envLlmRerankerKey() { return raw('HIPPO_LLM_RERANKER_KEY'); }
|
|
102
102
|
export function envLlmRerankerModel() { return raw('HIPPO_LLM_RERANKER_MODEL'); }
|
|
103
|
-
export function envLlmRerankerTimeoutMs() { return
|
|
103
|
+
export function envLlmRerankerTimeoutMs() { return positiveInt('HIPPO_LLM_RERANKER_TIMEOUT_MS'); }
|
|
104
104
|
export function envClefEndpoint() { return raw('HIPPO_CLEF_ENDPOINT')?.trim(); }
|
|
105
105
|
export function envClefEndpointToken() { return raw('HIPPO_CLEF_ENDPOINT_TOKEN')?.trim() || undefined; }
|
|
106
106
|
export function envClefTimeoutMs() { return raw('HIPPO_CLEF_TIMEOUT_MS'); }
|
package/dist/escape.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Escape LIKE metacharacters for a query that declares `ESCAPE '\'`. */
|
|
2
|
+
export declare function escapeLike(term: string): string;
|
|
3
|
+
/** Escape a string for use as a literal inside a RegExp source. */
|
|
4
|
+
export declare function escapeRegex(s: string): string;
|
|
5
|
+
//# sourceMappingURL=escape.d.ts.map
|
package/dist/escape.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Leaf module: literal-match escapes, kept in one place so every LIKE and RegExp caller escapes the same set.
|
|
2
|
+
/** Escape LIKE metacharacters for a query that declares `ESCAPE '\'`. */
|
|
3
|
+
export function escapeLike(term) {
|
|
4
|
+
return term.replace(/[%_\\]/g, '\\$&');
|
|
5
|
+
}
|
|
6
|
+
/** Escape a string for use as a literal inside a RegExp source. */
|
|
7
|
+
export function escapeRegex(s) {
|
|
8
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=escape.js.map
|
package/dist/eval-stats.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Statistics and cost accounting for the token-efficiency evals
|
|
3
|
-
* Part IX, TE3-TE5).
|
|
2
|
+
* Statistics and cost accounting for the token-efficiency evals.
|
|
4
3
|
*
|
|
5
4
|
* - Cost: price provider usage over four buckets (uncached input, cache
|
|
6
5
|
* write, cache read, output). Raw token counts overstate savings when most
|
package/dist/eval-stats.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Statistics and cost accounting for the token-efficiency evals
|
|
3
|
-
* Part IX, TE3-TE5).
|
|
2
|
+
* Statistics and cost accounting for the token-efficiency evals.
|
|
4
3
|
*
|
|
5
4
|
* - Cost: price provider usage over four buckets (uncached input, cache
|
|
6
5
|
* write, cache read, output). Raw token counts overstate savings when most
|