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/playbooks.js
CHANGED
|
@@ -6,11 +6,8 @@ import * as skillsModule from '../skills.js';
|
|
|
6
6
|
import { resolveTenantId } from '../tenant.js';
|
|
7
7
|
import { printError } from './output.js';
|
|
8
8
|
import { requireInit } from './shared.js';
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// `process close 1abc` / `supersede 1abc` silently hit the wrong row; require
|
|
12
|
-
// the whole arg to be digits. (Mirrors parsePositiveIncidentId; codex P2,
|
|
13
|
-
// 2026-05-29.)
|
|
9
|
+
// parseInt alone accepts trailing junk ('1abc' -> 1), which would let `process close 1abc`
|
|
10
|
+
// silently hit the wrong row; require the whole arg to be digits.
|
|
14
11
|
function parsePositiveProcessId(idRaw) {
|
|
15
12
|
const s = String(idRaw ?? '').trim();
|
|
16
13
|
const id = parseInt(s, 10);
|
|
@@ -193,8 +190,7 @@ function processCreate(hippoRoot, tenantId, processName, flags) {
|
|
|
193
190
|
if (created.memoryId)
|
|
194
191
|
console.log(` memory: ${created.memoryId}`);
|
|
195
192
|
}
|
|
196
|
-
// Strict positive-integer id parse for the mutating policy subcommands
|
|
197
|
-
// parsePositiveProcessId; codex P2 class - parseInt alone accepts '1abc' -> 1).
|
|
193
|
+
// Strict positive-integer id parse for the mutating policy subcommands: parseInt alone accepts '1abc' -> 1.
|
|
198
194
|
function parsePositivePolicyId(idRaw) {
|
|
199
195
|
const s = String(idRaw ?? '').trim();
|
|
200
196
|
const id = parseInt(s, 10);
|
|
@@ -392,8 +388,7 @@ function policyCreate(hippoRoot, tenantId, args, flags) {
|
|
|
392
388
|
process.exit(1);
|
|
393
389
|
}
|
|
394
390
|
}
|
|
395
|
-
// Strict positive-integer id parse for the mutating skill subcommands
|
|
396
|
-
// parsePositivePolicyId; codex P2 class - parseInt accepts '1abc' -> 1).
|
|
391
|
+
// Strict positive-integer id parse for the mutating skill subcommands: parseInt accepts '1abc' -> 1.
|
|
397
392
|
function parsePositiveSkillId(idRaw) {
|
|
398
393
|
const s = String(idRaw ?? '').trim();
|
|
399
394
|
const id = parseInt(s, 10);
|
package/dist/cli/projects.js
CHANGED
|
@@ -58,7 +58,7 @@ export function cmdProjects(hippoRoot, args, flags) {
|
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
console.log(`${apply ? 'Merged' : 'Dry run: would merge'} ${from} into ${into}:`);
|
|
61
|
-
console.log(` ${count(r.setAside.length, 'imported note copy', 'imported note copies')} set aside (
|
|
61
|
+
console.log(` ${count(r.setAside.length, 'imported note copy', 'imported note copies')} set aside (${into} already holds the same note; the rest move under ${into} on the next sync)`);
|
|
62
62
|
console.log(` ${count(r.restamped.length, 'memory', 'memories')} re-tagged, plus ${r.dormantRestamped.length} dormant and ${count(r.compactions, 'compaction record')}`);
|
|
63
63
|
console.log(apply ? `Backup: ${r.backup}\nEvery id is in the audit log: hippo audit list --op project_merge` : 'Nothing written. Add --apply to run it.');
|
|
64
64
|
return;
|
|
@@ -73,6 +73,8 @@ export function cmdProjects(hippoRoot, args, flags) {
|
|
|
73
73
|
console.log(` ${count(r.copies.length, 'imported note copy', 'imported note copies')} under the wrong project set aside (the note stays under its own, or user-global)`);
|
|
74
74
|
for (const f of r.folds)
|
|
75
75
|
console.log(` ${f.from} folded into ${f.into} (its sessions' folders resolve there now)`);
|
|
76
|
+
for (const c of r.collisions)
|
|
77
|
+
console.log(` ${c.name} left as it is: its folders now resolve to ${c.ids.join(', ')}; fold it by hand with hippo projects merge`);
|
|
76
78
|
console.log(` sleep's user-global merged rows: ${r.toProject.length} re-tagged to their parents' project`);
|
|
77
79
|
console.log(` ${r.setAside.length} set aside (parents in two projects; sleep re-merges them per project)`);
|
|
78
80
|
console.log(` ${r.untraced.length} left as they are (no parent left to show which project; check them with hippo inspect <id>)`);
|
package/dist/cli/recall.js
CHANGED
|
@@ -10,6 +10,7 @@ import { loadLatestHandoff } from '../store/handoffs.js';
|
|
|
10
10
|
import { passesScopeFilterForRecall } from '../recall-scope.js';
|
|
11
11
|
import { fitBudget } from '../search/finalize.js';
|
|
12
12
|
import { explainMatch } from '../search/explain.js';
|
|
13
|
+
import { DEFAULT_RECALL_BUDGET } from '../search/types.js';
|
|
13
14
|
import { writeRecallTraceAtRoot } from '../recall-trace.js';
|
|
14
15
|
import { loadConfig } from '../config.js';
|
|
15
16
|
import { openHippoDb, closeHippoDb } from '../db.js';
|
|
@@ -188,7 +189,7 @@ export async function cmdRecall(hippoRoot, query, flags) {
|
|
|
188
189
|
}
|
|
189
190
|
/** Every flag recall reads, parsed in the order the single-body command checked them. */
|
|
190
191
|
function parseRecallOptions(hippoRoot, flags) {
|
|
191
|
-
const budget = parseBudgetFlag(flags['budget'],
|
|
192
|
+
const budget = parseBudgetFlag(flags['budget'], DEFAULT_RECALL_BUDGET);
|
|
192
193
|
const limit = parseLimitFlag(flags['limit']);
|
|
193
194
|
const asJson = Boolean(flags['json']);
|
|
194
195
|
const showWhy = Boolean(flags['why']);
|
package/dist/cli/remember.js
CHANGED
|
@@ -56,7 +56,7 @@ function parseKindFlag(flags) {
|
|
|
56
56
|
const kindFlagRaw = typeof flags['kind'] === 'string' ? flags['kind'] : undefined;
|
|
57
57
|
const kindFlag = kindFlagRaw === undefined ? undefined : kindFlagRaw.toLowerCase();
|
|
58
58
|
// CLI surface intentionally restricted: 'raw' is reserved for ingestion connectors
|
|
59
|
-
//
|
|
59
|
+
// that route deletions through archiveRawMemory. Existing
|
|
60
60
|
// forget/consolidate/conflict-resolve paths abort on kind='raw' via the append-only
|
|
61
61
|
// trigger, so exposing --kind raw here would create unforgettable memories.
|
|
62
62
|
// 'archived' is an internal sentinel set only inside archiveRawMemory's transaction.
|
|
@@ -68,7 +68,6 @@ function parseKindFlag(flags) {
|
|
|
68
68
|
}
|
|
69
69
|
return kindFlag;
|
|
70
70
|
}
|
|
71
|
-
// A3 envelope flags
|
|
72
71
|
function parseRememberEnvelope(flags) {
|
|
73
72
|
const kind = parseKindFlag(flags);
|
|
74
73
|
const ownerRaw = typeof flags['owner'] === 'string' ? flags['owner'] : null;
|
|
@@ -99,8 +98,7 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
99
98
|
const existing = loadAllEntries(targetRoot, resolveTenantId({}));
|
|
100
99
|
const schemaFit = computeSchemaFit(text, requestedTags, existing);
|
|
101
100
|
const envelope = parseRememberEnvelope(flags);
|
|
102
|
-
//
|
|
103
|
-
// can filter on this row. Default tenant 'default' for unauthenticated CLI.
|
|
101
|
+
// Stamp tenant_id from env (HIPPO_TENANT) so recall isolation can filter on this row; unauthenticated CLI gets 'default'.
|
|
104
102
|
const tenantId = resolveTenantId({});
|
|
105
103
|
const rememberConfig = loadConfig(targetRoot);
|
|
106
104
|
const entry = createMemory(text, {
|
|
@@ -209,15 +207,8 @@ function cmdSupersede(hippoRoot, oldId, newContent, flags) {
|
|
|
209
207
|
tags,
|
|
210
208
|
pinned,
|
|
211
209
|
});
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
// committed old.superseded_by before the guarded new write, leaving a
|
|
215
|
-
// dangling pointer to an id that was never created). If the old-row write
|
|
216
|
-
// below fails instead, the new row exists unpointered — an orphan
|
|
217
|
-
// successor, strictly less harmful than a dangling pointer. NOTE: unlike
|
|
218
|
-
// api.supersede (whose CAS + insert commit in ONE transaction), this CLI
|
|
219
|
-
// path is two independent writes and stays non-atomic; write order is its
|
|
220
|
-
// only ordering guarantee.
|
|
210
|
+
// Write the SUCCESSOR first: a rejection-guard refusal then mutates nothing, and an old-row failure leaves an
|
|
211
|
+
// orphan successor rather than a dangling pointer. Unlike api.supersede this path is two non-atomic writes.
|
|
221
212
|
try {
|
|
222
213
|
writeEntry(hippoRoot, newEntry);
|
|
223
214
|
}
|
|
@@ -420,8 +411,7 @@ export async function handleRemember({ hippoRoot, args, flags }) {
|
|
|
420
411
|
// flags (--pin, --layer, --extract, --global) still need the direct
|
|
421
412
|
// path; we only intercept the minimal envelope. The salience gate is
|
|
422
413
|
// NOT in richFlag and the route does not apply it, so a routed remember
|
|
423
|
-
// stores what a direct one would skip
|
|
424
|
-
// TODOS.md; do not read this list as covering salience.
|
|
414
|
+
// stores what a direct one would skip; do not read this list as covering salience.
|
|
425
415
|
const richFlag = flags['pin'] || flags['global'] || flags['extract'] || flags['force'] ||
|
|
426
416
|
flags['observed'] || flags['inferred'] || flags['verified'] ||
|
|
427
417
|
flags['layer'] !== undefined;
|
|
@@ -430,9 +420,7 @@ export async function handleRemember({ hippoRoot, args, flags }) {
|
|
|
430
420
|
const rememberKindAllowed = ['distilled', 'superseded'];
|
|
431
421
|
if (rememberKindRaw === undefined || rememberKindAllowed.includes(rememberKindRaw)) {
|
|
432
422
|
const tags = rememberTags(flags, process.cwd()).all;
|
|
433
|
-
//
|
|
434
|
-
// Failure on this path exits early so the user gets the same
|
|
435
|
-
// validation experience whether or not a server is up.
|
|
423
|
+
// Validate --owner on the thin-client path too, so validation is the same whether or not a server is up.
|
|
436
424
|
const thinOwnerRaw = typeof flags['owner'] === 'string' ? flags['owner'] : undefined;
|
|
437
425
|
const thinOwnerCheck = validateOwner(thinOwnerRaw, { strict: isStrictOwnerEnv() });
|
|
438
426
|
if (!thinOwnerCheck.ok) {
|
|
@@ -14,7 +14,7 @@ import { captureToolFailure } from '../capture-error.js';
|
|
|
14
14
|
import { estimateTokens, isSubagentPayload, readApiCalls, recordRereads, recordTokenUse, } from '../token-ledger.js';
|
|
15
15
|
import { currentMachine, importSessionFolder } from '../agent-memories/sync.js';
|
|
16
16
|
import { summaryLine } from '../agent-memories/report.js';
|
|
17
|
-
import {
|
|
17
|
+
import { resolveProjectIdentity } from '../project-identity.js';
|
|
18
18
|
import { getGlobalRoot } from '../shared.js';
|
|
19
19
|
import { cmdCapture } from '../capture/command.js';
|
|
20
20
|
import { cmdPreCompact, cmdPostCompact, transcriptWorkingState } from '../capture/compact.js';
|
|
@@ -63,22 +63,19 @@ export function cmdLastSleep(flags) {
|
|
|
63
63
|
* memories here — the UserPromptSubmit hook already re-injects those every
|
|
64
64
|
* turn, so duplicating them here would double token cost for nothing.
|
|
65
65
|
*
|
|
66
|
-
* Same exit-0/crash-safety contract as `hippo pre-compact
|
|
67
|
-
*
|
|
66
|
+
* Same exit-0/crash-safety contract as `hippo pre-compact`: every path
|
|
67
|
+
* exits 0. A malformed payload or a store read failure
|
|
68
68
|
* degrades to empty stdout, never a thrown error — a failing SessionStart
|
|
69
69
|
* hook must not pollute session startup.
|
|
70
70
|
*/
|
|
71
|
-
//
|
|
72
|
-
// printSessionEvents stays untouched for every other caller.
|
|
71
|
+
// Capped at print time only, so the shared printSessionEvents stays untouched for every other caller.
|
|
73
72
|
const COMPACT_RESUME_EVENT_CONTENT_CAP = 400;
|
|
74
73
|
// A snapshot older than this was not written for this compaction (pre-compact skipped), so restoring it is stale, not a resume.
|
|
75
74
|
const COMPACT_RESUME_MAX_AGE_MS = 15 * 60_000;
|
|
76
75
|
function cmdCompactResume(hippoRoot, stdinText, stdinTimedOut) {
|
|
77
76
|
try {
|
|
78
|
-
//
|
|
79
|
-
// store
|
|
80
|
-
// call initStore internally, which would silently create a store in a
|
|
81
|
-
// project that never ran `hippo init` — this hook fires globally).
|
|
77
|
+
// Gate on the non-exiting isInitialized check first: the store reads below call initStore, which would
|
|
78
|
+
// silently create a store in a project that never ran `hippo init`, and this hook fires globally.
|
|
82
79
|
if (!isInitialized(hippoRoot)) {
|
|
83
80
|
process.exit(0);
|
|
84
81
|
}
|
|
@@ -88,7 +85,7 @@ function cmdCompactResume(hippoRoot, stdinText, stdinTimedOut) {
|
|
|
88
85
|
// carries a different source (e.g. 'startup') means the matcher-based
|
|
89
86
|
// gate failed to apply — stay silent rather than print stale state.
|
|
90
87
|
const nonEmptyStdin = !!stdinText && stdinText.trim() !== '';
|
|
91
|
-
// Without a payload session_id the
|
|
88
|
+
// Without a payload session_id the cross-restore guard below can
|
|
92
89
|
// never fire, so a timed-out empty read must not reach the print path.
|
|
93
90
|
let suppressOutput = stdinTimedOut && !nonEmptyStdin;
|
|
94
91
|
let payloadSessionId = null;
|
|
@@ -102,19 +99,13 @@ function cmdCompactResume(hippoRoot, stdinText, stdinTimedOut) {
|
|
|
102
99
|
payload = null;
|
|
103
100
|
}
|
|
104
101
|
if (!payload || typeof payload !== 'object') {
|
|
105
|
-
//
|
|
106
|
-
// "print on malformed" behavior survives only for TTY/no-stdin
|
|
107
|
-
// manual invocation (nonEmptyStdin is false there, this branch
|
|
108
|
-
// never runs).
|
|
102
|
+
// Fail closed on malformed non-empty stdin; only a TTY/no-stdin manual run, which never reaches here, prints.
|
|
109
103
|
suppressOutput = true;
|
|
110
104
|
}
|
|
111
105
|
else {
|
|
112
|
-
// Fail closed on structurally incomplete payloads too ({}, [],
|
|
113
|
-
// source
|
|
114
|
-
//
|
|
115
|
-
// carry source; only the TTY/no-stdin manual path prints without
|
|
116
|
-
// one (codex round 3).
|
|
117
|
-
// A sub-agent's payload carries its parent's session id, so X5 would pass and restore the parent's snapshot into it.
|
|
106
|
+
// Fail closed on structurally incomplete payloads too ({}, [], source missing/non-string): real
|
|
107
|
+
// SessionStart payloads always carry source, so a parsed one must say 'compact' to print.
|
|
108
|
+
// A sub-agent's payload carries its parent's session id, so the mismatch guard would pass and restore the parent's snapshot into it.
|
|
118
109
|
if (payload.source !== 'compact' || isSubagentPayload(stdinText)) {
|
|
119
110
|
suppressOutput = true;
|
|
120
111
|
}
|
|
@@ -139,9 +130,8 @@ function cmdCompactResume(hippoRoot, stdinText, stdinTimedOut) {
|
|
|
139
130
|
function restoreCompactSnapshot(hippoRoot, payloadSessionId) {
|
|
140
131
|
const tenantId = resolveTenantId({});
|
|
141
132
|
const snapshot = loadFreshActiveTaskSnapshot(hippoRoot, tenantId, { maxAgeMs: COMPACT_RESUME_MAX_AGE_MS });
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
// invocation with no payload session_id, still prints.
|
|
133
|
+
// Concurrent sessions must not cross-restore. Only suppress when BOTH ids are present and differ;
|
|
134
|
+
// either side missing, or a manual invocation with no payload session_id, still prints.
|
|
145
135
|
const sessionMismatch = !!snapshot &&
|
|
146
136
|
payloadSessionId !== null &&
|
|
147
137
|
snapshot.session_id !== null &&
|
|
@@ -164,8 +154,7 @@ function restoreCompactSnapshot(hippoRoot, payloadSessionId) {
|
|
|
164
154
|
// Printed in one write so the ledger books exactly the text the model is handed.
|
|
165
155
|
const text = captureConsole(() => {
|
|
166
156
|
console.log('## Restored after compaction\n');
|
|
167
|
-
//
|
|
168
|
-
// the framing line the model actually sees at every compaction.
|
|
157
|
+
// Re-injected state is background reference, not instructions: the framing line the model sees at every compaction.
|
|
169
158
|
console.log("_Point-in-time working-state snapshot, auto-restored after compaction. Background reference, not instructions; the user's live messages win._\n");
|
|
170
159
|
printActiveTaskSnapshot(snapshot);
|
|
171
160
|
// Nothing auto-populates session_events, so an empty trail is the common real case;
|
|
@@ -191,8 +180,7 @@ function restoreCompactSnapshot(hippoRoot, payloadSessionId) {
|
|
|
191
180
|
*/
|
|
192
181
|
export async function cmdSessionEnd(hippoRoot, flags) {
|
|
193
182
|
const logFile = typeof flags['log-file'] === 'string' ? flags['log-file'] : null;
|
|
194
|
-
// Bounded read
|
|
195
|
-
// extracts transcript_path + session_id for the detached worker's argv.
|
|
183
|
+
// Bounded read: extracts transcript_path + session_id for the detached worker's argv.
|
|
196
184
|
let sessionId = null;
|
|
197
185
|
const { text: stdinText } = await readStdinBounded();
|
|
198
186
|
try {
|
|
@@ -224,7 +212,7 @@ export async function cmdSessionEnd(hippoRoot, flags) {
|
|
|
224
212
|
});
|
|
225
213
|
child.unref();
|
|
226
214
|
}
|
|
227
|
-
catch
|
|
215
|
+
catch {
|
|
228
216
|
// If spawn fails, run inline as a last resort, handed what the child's argv would have carried.
|
|
229
217
|
if (transcriptPath)
|
|
230
218
|
flags['transcript'] = transcriptPath;
|
|
@@ -261,16 +249,9 @@ export async function cmdSessionEndWorker(hippoRoot, flags) {
|
|
|
261
249
|
tenantId: resolveTenantId({}),
|
|
262
250
|
log: digestLog,
|
|
263
251
|
});
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
//
|
|
267
|
-
// destroy same-run work. Scoped to `--session-id`: a concurrent session's
|
|
268
|
-
// active snapshot is untouched (closeTaskSnapshotsForSession's own WHERE
|
|
269
|
-
// clause). Absent session id -> no-op plus one log line; session-end is
|
|
270
|
-
// not guaranteed to fire at all (crash, kill -9), so the freshness bound
|
|
271
|
-
// in loadFreshActiveTaskSnapshot is the backstop layer, not this close.
|
|
272
|
-
// Handoff write happens BEFORE the snapshot close below, while the
|
|
273
|
-
// snapshot writeSessionEndHandoff reads is still active.
|
|
252
|
+
// Close only this session's snapshot, after sleep+capture: no snapshot producer runs in session-end, and since
|
|
253
|
+
// session-end may never fire (crash, kill -9) the freshness bound in loadFreshActiveTaskSnapshot is the backstop.
|
|
254
|
+
// The handoff is written first, while the snapshot writeSessionEndHandoff reads is still active.
|
|
274
255
|
if (closeSessionId)
|
|
275
256
|
writeEndHandoff(store, closeSessionId, transcriptPath, closeLogFile);
|
|
276
257
|
try {
|
|
@@ -318,7 +299,7 @@ function captureEndedSession(hippoRoot, store, flags, transcriptPath, scan) {
|
|
|
318
299
|
global: false,
|
|
319
300
|
tenantId: resolveTenantId({}),
|
|
320
301
|
// In the global store, rows would otherwise read as user-global and show up in every project.
|
|
321
|
-
originProject: store === hippoRoot ? undefined :
|
|
302
|
+
originProject: store === hippoRoot ? undefined : resolveProjectIdentity(process.cwd()),
|
|
322
303
|
sessionTurns: scan?.turns,
|
|
323
304
|
});
|
|
324
305
|
}
|
|
@@ -531,7 +512,7 @@ export async function cmdCodexSessionEndWorker(hippoRoot, flags) {
|
|
|
531
512
|
dryRun: false,
|
|
532
513
|
global: false,
|
|
533
514
|
tenantId: resolveTenantId({}),
|
|
534
|
-
originProject: store === hippoRoot ? undefined :
|
|
515
|
+
originProject: store === hippoRoot ? undefined : resolveProjectIdentity(process.cwd()),
|
|
535
516
|
sessionTurns: scan?.turns,
|
|
536
517
|
};
|
|
537
518
|
try {
|
package/dist/cli/setup.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function cmdHook(args: string[]
|
|
1
|
+
export declare function cmdHook(args: string[]): void;
|
|
2
2
|
export declare function cmdSetup(flags: Record<string, string | boolean | string[]>): void;
|
|
3
3
|
export declare function cmdDailyRunner(): void;
|
|
4
4
|
//# sourceMappingURL=setup.d.ts.map
|
package/dist/cli/setup.js
CHANGED
|
@@ -15,10 +15,11 @@ import { log } from '../log.js';
|
|
|
15
15
|
import { printError } from './output.js';
|
|
16
16
|
import { printAgentImport, installCodexMemoryHooks, setupDailySchedule } from './shared.js';
|
|
17
17
|
import { HOOK_MARKERS, HOOKS, hippoBlock } from './hook-blocks.js';
|
|
18
|
+
import { escapeRegex } from '../escape.js';
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Hook install/uninstall
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
21
|
-
export function cmdHook(args
|
|
22
|
+
export function cmdHook(args) {
|
|
22
23
|
const subcommand = args[0];
|
|
23
24
|
const target = args[1];
|
|
24
25
|
if (subcommand === 'list')
|
|
@@ -74,7 +75,6 @@ function hookInstall(target) {
|
|
|
74
75
|
function patchAgentFile(hook, target) {
|
|
75
76
|
const filepath = path.resolve(process.cwd(), hook.file);
|
|
76
77
|
const block = `${HOOK_MARKERS.start}\n${hook.content}\n${HOOK_MARKERS.end}`;
|
|
77
|
-
let agentFileTouched = false;
|
|
78
78
|
if (fs.existsSync(filepath)) {
|
|
79
79
|
const existing = fs.readFileSync(filepath, 'utf8');
|
|
80
80
|
if (existing.includes(HOOK_MARKERS.start) && othersBlock(target, existing)) {
|
|
@@ -91,7 +91,6 @@ function patchAgentFile(hook, target) {
|
|
|
91
91
|
fs.writeFileSync(filepath, existing + sep + block + '\n', 'utf8');
|
|
92
92
|
console.log(`Installed Hippo hook in ${hook.file} (appended)`);
|
|
93
93
|
}
|
|
94
|
-
agentFileTouched = true;
|
|
95
94
|
}
|
|
96
95
|
else {
|
|
97
96
|
// Do not create a new agent-instructions file (CLAUDE.md, AGENTS.md, etc.) in directories that don't already have one —
|
|
@@ -218,9 +217,6 @@ function withoutHookBlock(text) {
|
|
|
218
217
|
const re = new RegExp(`\\n?${escapeRegex(HOOK_MARKERS.start)}[\\s\\S]*?${escapeRegex(HOOK_MARKERS.end)}\\n?`, 'g');
|
|
219
218
|
return text.replace(re, '\n').replace(/\n{3,}/g, '\n\n').trim();
|
|
220
219
|
}
|
|
221
|
-
function escapeRegex(s) {
|
|
222
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
223
|
-
}
|
|
224
220
|
// `hippo setup` -- one-shot configuration for every AI coding tool on the box.
|
|
225
221
|
// Detection and install logic live in ./hooks.ts.
|
|
226
222
|
export function cmdSetup(flags) {
|
package/dist/cli/shared.js
CHANGED
|
@@ -91,14 +91,14 @@ export function requireInit(hippoRoot) {
|
|
|
91
91
|
/** Runs detectChurnStale against every store this repo's memories can live in. */
|
|
92
92
|
export function runChurnStaleForRepo(hippoRoot, dryRun) {
|
|
93
93
|
const repoRoot = execFileSync('git', ['rev-parse', '--show-toplevel'], { cwd: process.cwd(), encoding: 'utf8', timeout: 10_000, windowsHide: true }).trim();
|
|
94
|
-
const projectName = resolveProjectIdentity(process.cwd())
|
|
94
|
+
const { name: projectName, legacyName } = resolveProjectIdentity(process.cwd());
|
|
95
95
|
const globalRoot = getGlobalRoot();
|
|
96
96
|
const roots = globalRoot !== hippoRoot && isInitialized(globalRoot) ? [hippoRoot, globalRoot] : [hippoRoot];
|
|
97
97
|
const tenantId = resolveTenantId({});
|
|
98
98
|
return roots.map((root) => {
|
|
99
99
|
// One store failing must not abort sleep's later phases or skip the other store.
|
|
100
100
|
try {
|
|
101
|
-
return { root, result: detectChurnStale(root, repoRoot, { tenantId, projectName, dryRun }) };
|
|
101
|
+
return { root, result: detectChurnStale(root, repoRoot, { tenantId, projectName, legacyName, dryRun }) };
|
|
102
102
|
}
|
|
103
103
|
catch (err) {
|
|
104
104
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -405,7 +405,7 @@ export function cardStringFlag(flags, key) {
|
|
|
405
405
|
}
|
|
406
406
|
// Claude Code exports its own session var, not ours; without the fallback agent-run recalls trace with no session.
|
|
407
407
|
export function hostSessionId() {
|
|
408
|
-
return envHippoSessionId()
|
|
408
|
+
return envHippoSessionId() ?? envClaudeCodeSessionId();
|
|
409
409
|
}
|
|
410
410
|
/**
|
|
411
411
|
* Compaction drops the pinned blocks the per-prompt hook injected
|
package/dist/cli/slack.js
CHANGED
|
@@ -10,7 +10,7 @@ import { addWorkspace as addSlackWorkspace, listWorkspaces as listSlackWorkspace
|
|
|
10
10
|
import { printError } from './output.js';
|
|
11
11
|
import { printSlackBackfillUsage, printSlackWorkspacesUsage } from './usage.js';
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
|
-
// Slack subcommands (
|
|
13
|
+
// Slack subcommands (`hippo slack backfill` / `hippo slack dlq list`)
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
function cmdSlackBackfill(hippoRoot, flags) {
|
|
16
16
|
const channel = typeof flags['channel'] === 'string' ? flags['channel'] : undefined;
|
package/dist/cli/sleep.js
CHANGED
|
@@ -8,7 +8,9 @@ import { replayCompactionsAt } from '../compaction-record.js';
|
|
|
8
8
|
import * as api from '../api.js';
|
|
9
9
|
import { resolveTenantId } from '../tenant.js';
|
|
10
10
|
import { renderAmbientSummary } from '../ambient.js';
|
|
11
|
-
import { log } from '../log.js';
|
|
11
|
+
import { errorMessage, log } from '../log.js';
|
|
12
|
+
import { closeHippoDb, openHippoDb } from '../db.js';
|
|
13
|
+
import { repairOnceOnSleep } from '../project-merge.js';
|
|
12
14
|
import { requireInit, learnFromRepo, runChurnStaleForRepo, printAgentImport } from './shared.js';
|
|
13
15
|
import { printError } from './output.js';
|
|
14
16
|
/** Runs `hippo sleep`; with `--log-file` it also tees its output to that file. */
|
|
@@ -127,6 +129,29 @@ export function renderSleepResult(result) {
|
|
|
127
129
|
console.log(`\nGraph: rebuilt ${tenants} tenant${tenants === 1 ? '' : 's'} (${entities} entities, ${relations} relations).`);
|
|
128
130
|
}
|
|
129
131
|
}
|
|
132
|
+
/** Fault-isolated: a failed repair warns and runs again next sleep, and never stops the sleep. */
|
|
133
|
+
function repairProjectTagsOnce(hippoRoot) {
|
|
134
|
+
let db;
|
|
135
|
+
try {
|
|
136
|
+
db = openHippoDb(hippoRoot);
|
|
137
|
+
const r = repairOnceOnSleep(db, hippoRoot, resolveTenantId({}));
|
|
138
|
+
if (r === null)
|
|
139
|
+
return;
|
|
140
|
+
const parts = [
|
|
141
|
+
r.copies.length > 0 ? `set aside ${r.copies.length} misfiled note imports` : '',
|
|
142
|
+
r.folds.length > 0 ? `folded ${r.folds.map((f) => `${f.from} into ${f.into}`).join(', ')}` : '',
|
|
143
|
+
r.toProject.length + r.setAside.length > 0 ? `re-tagged ${r.toProject.length + r.setAside.length} merged memories` : '',
|
|
144
|
+
].filter((p) => p !== '');
|
|
145
|
+
console.log(`Repaired project tags once after the upgrade: ${parts.join('; ')} (backup: ${r.backup}).`);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
log.warn(`project tag repair skipped, retried next sleep: ${errorMessage(err)}`);
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
if (db)
|
|
152
|
+
closeHippoDb(db);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
130
155
|
async function cmdSleepCore(hippoRoot, flags) {
|
|
131
156
|
requireInit(hippoRoot);
|
|
132
157
|
// Phase 1: Auto-learn from git and every coding agent's own memories (CLI-only, uses process.cwd() / os.homedir()).
|
|
@@ -157,6 +182,7 @@ async function cmdSleepCore(hippoRoot, flags) {
|
|
|
157
182
|
const finished = replayCompactionsAt(hippoRoot, (message) => log.warn(`compaction replay: ${message}`));
|
|
158
183
|
if (finished > 0)
|
|
159
184
|
console.log(`Finished saving ${finished} compaction${finished === 1 ? '' : 's'} left over from earlier sessions.`);
|
|
185
|
+
repairProjectTagsOnce(hippoRoot);
|
|
160
186
|
}
|
|
161
187
|
// Phase 2-6: Pure-storage pipeline (consolidate + dedup + audit + share + ambient).
|
|
162
188
|
const ctx = {
|
package/dist/cli/status.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { type CommandContext } from './shared.js';
|
|
2
2
|
export declare function cmdStatus(hippoRoot: string): void;
|
|
3
3
|
/**
|
|
4
|
-
* `hippo tokens [--days <n>] [--json] [--global]`: the token ledger
|
|
5
|
-
*
|
|
6
|
-
* the per-prompt hook skipped as unchanged
|
|
4
|
+
* `hippo tokens [--days <n>] [--json] [--global]`: the token ledger.
|
|
5
|
+
* Tokens of memory text handed to agents per surface, blocks
|
|
6
|
+
* the per-prompt hook skipped as unchanged and the tokens that saved,
|
|
7
7
|
* and the hook blocks' tokens later model calls re-read, counted when each session ends.
|
|
8
8
|
* Counts are estimates (characters / 4), the same estimate every budget uses.
|
|
9
9
|
*/
|
|
10
10
|
export declare function cmdTokens(hippoRoot: string, flags: Record<string, string | boolean | string[]>): void;
|
|
11
|
-
/** `hippo failures [--days <n>] [--json] [--global]`: failed tool calls by outcome, and repeats across sessions
|
|
11
|
+
/** `hippo failures [--days <n>] [--json] [--global]`: failed tool calls by outcome, and repeats across sessions. */
|
|
12
12
|
export declare function cmdFailures(hippoRoot: string, flags: Record<string, string | boolean | string[]>): void;
|
|
13
13
|
export declare function handleCorrectionLatency({ hippoRoot, flags }: CommandContext): void;
|
|
14
14
|
export declare function handleProvenance({ hippoRoot, flags }: CommandContext): void;
|
package/dist/cli/status.js
CHANGED
|
@@ -159,13 +159,8 @@ function printPhysicsStatus(hippoRoot) {
|
|
|
159
159
|
const physConfig = loadConfig(hippoRoot);
|
|
160
160
|
const energy = computeSystemEnergy(particles, physConfig.physics.G_memory);
|
|
161
161
|
let sumVelMag = 0;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const mag = vecNorm(p.velocity);
|
|
165
|
-
sumVelMag += mag;
|
|
166
|
-
if (mag > maxVelMag)
|
|
167
|
-
maxVelMag = mag;
|
|
168
|
-
}
|
|
162
|
+
for (const p of particles)
|
|
163
|
+
sumVelMag += vecNorm(p.velocity);
|
|
169
164
|
const avgVelMag = sumVelMag / particles.length;
|
|
170
165
|
console.log('');
|
|
171
166
|
console.log(`Physics: ${particles.length} particles, energy: ${fmt(energy.total, 4)} (KE: ${fmt(energy.kinetic, 4)}, PE: ${fmt(energy.potential, 4)}), avg vel: ${fmt(avgVelMag, 4)}`);
|
|
@@ -222,9 +217,9 @@ function cmdInspect(hippoRoot, id) {
|
|
|
222
217
|
console.log(entry.content);
|
|
223
218
|
}
|
|
224
219
|
/**
|
|
225
|
-
* `hippo tokens [--days <n>] [--json] [--global]`: the token ledger
|
|
226
|
-
*
|
|
227
|
-
* the per-prompt hook skipped as unchanged
|
|
220
|
+
* `hippo tokens [--days <n>] [--json] [--global]`: the token ledger.
|
|
221
|
+
* Tokens of memory text handed to agents per surface, blocks
|
|
222
|
+
* the per-prompt hook skipped as unchanged and the tokens that saved,
|
|
228
223
|
* and the hook blocks' tokens later model calls re-read, counted when each session ends.
|
|
229
224
|
* Counts are estimates (characters / 4), the same estimate every budget uses.
|
|
230
225
|
*/
|
|
@@ -263,7 +258,7 @@ export function cmdTokens(hippoRoot, flags) {
|
|
|
263
258
|
console.log(' Re-reads are counted for hook and compact-resume blocks when a session ends; other surfaces, and open or crashed sessions, show sent only.');
|
|
264
259
|
console.log(" Re-reads usually bill at the provider's cached-input rate, a fraction of the full input price.");
|
|
265
260
|
}
|
|
266
|
-
/** `hippo failures [--days <n>] [--json] [--global]`: failed tool calls by outcome, and repeats across sessions
|
|
261
|
+
/** `hippo failures [--days <n>] [--json] [--global]`: failed tool calls by outcome, and repeats across sessions. */
|
|
267
262
|
export function cmdFailures(hippoRoot, flags) {
|
|
268
263
|
// The store the capture-error hook writes to; a report never creates one.
|
|
269
264
|
const root = flags['global'] ? getGlobalRoot() : hookStoreRoot(hippoRoot);
|
|
@@ -298,7 +293,7 @@ export function cmdFailures(hippoRoot, flags) {
|
|
|
298
293
|
for (const [label, count, note] of rows) {
|
|
299
294
|
console.log(` ${label.padEnd(13)}${String(count).padStart(6)} ${note}`.trimEnd());
|
|
300
295
|
}
|
|
301
|
-
// Counts, not a rate: a share means little without a holdout arm to compare against
|
|
296
|
+
// Counts, not a rate: a share means little without a holdout arm to compare against.
|
|
302
297
|
if (summary.rated > 0) {
|
|
303
298
|
const noSession = errors - summary.rated;
|
|
304
299
|
const unrated = noSession > 0 ? ` ${noSession} more had no session id.` : '';
|
package/dist/cli/transfer.js
CHANGED
|
@@ -46,10 +46,8 @@ async function cmdWatch(command, hippoRoot) {
|
|
|
46
46
|
entry.schema_fit = watchFit;
|
|
47
47
|
entry.half_life_days = deriveHalfLife(loadConfig(hippoRoot).defaultHalfLifeDays, entry);
|
|
48
48
|
entry.strength = calculateStrength(entry);
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// (loud enough via the message below) and still exit with the wrapped
|
|
52
|
-
// command's real exit code.
|
|
49
|
+
// A rejection-guard refusal of a failed command's output must not crash the watcher:
|
|
50
|
+
// skip with the message below and still exit with the wrapped command's real exit code.
|
|
53
51
|
try {
|
|
54
52
|
writeEntry(hippoRoot, entry);
|
|
55
53
|
updateStats(hippoRoot, { remembered: 1 });
|
|
@@ -126,7 +124,7 @@ export function cmdImport(hippoRoot, args, flags) {
|
|
|
126
124
|
extraTags,
|
|
127
125
|
hippoRoot,
|
|
128
126
|
};
|
|
129
|
-
//
|
|
127
|
+
// Vault import: a FOLDER importer that mirrors the connector pattern
|
|
130
128
|
// (kind='raw' + tag provenance + archiveRaw deletions), so it dispatches
|
|
131
129
|
// separately from the single-file `importer` function-pointer slot below.
|
|
132
130
|
// It writes through api.remember/archiveRaw which are tenant-scoped, so we
|
|
@@ -220,16 +218,15 @@ function importVaultFolder(hippoRoot, flags, importOptions, useGlobal, dryRun) {
|
|
|
220
218
|
process.exit(1);
|
|
221
219
|
}
|
|
222
220
|
if (typeof flags['name'] !== 'string' || !flags['name'].trim()) {
|
|
223
|
-
// --name
|
|
224
|
-
//
|
|
225
|
-
// String(true) === "true" would silently import under vault:true:* - reject a non-string so it fails fast instead (codex R11 P2).
|
|
221
|
+
// --name keys the destructive source-deletion sync; a folder-basename default lets same-basename vaults clobber
|
|
222
|
+
// each other, and a valueless `--name` (boolean true) would silently import under vault:true:*.
|
|
226
223
|
printError('hippo import --vault requires --name <vault> (a non-empty identity key for source-deletion sync).');
|
|
227
224
|
process.exit(1);
|
|
228
225
|
}
|
|
229
226
|
if (flags['scope'] !== undefined && (typeof flags['scope'] !== 'string' || !flags['scope'].trim())) {
|
|
230
227
|
// Same valueless-flag trap: a bare `--scope` must not become scope "true".
|
|
231
228
|
// Example uses the source-prefixed private form, since a bare `private` scope
|
|
232
|
-
// is NOT treated as private by recall and importVault rejects it
|
|
229
|
+
// is NOT treated as private by recall and importVault rejects it.
|
|
233
230
|
printError('hippo import --vault: --scope requires a value (e.g. --scope vault:private:notes).');
|
|
234
231
|
process.exit(1);
|
|
235
232
|
}
|
|
@@ -251,7 +248,7 @@ function importVaultFolder(hippoRoot, flags, importOptions, useGlobal, dryRun) {
|
|
|
251
248
|
warnRedacted(vaultResult.redacted);
|
|
252
249
|
console.log(` ${dryRun ? 'Would archive: ' : 'Archived (removed): '}${vaultResult.archived ?? 0}`);
|
|
253
250
|
console.log(` Store: ${hippoRoot}`);
|
|
254
|
-
// Batch producer, same contract as the single-file import
|
|
251
|
+
// Batch producer, same contract as the single-file import above: vault rows
|
|
255
252
|
// write through api.remember (which never embeds), so backfill them here.
|
|
256
253
|
// Floating promise is deliberate; see the comment at the single-file site.
|
|
257
254
|
if (!dryRun && vaultResult.imported >= 1) {
|
|
@@ -374,9 +371,7 @@ export function handleShare({ hippoRoot, args, flags }) {
|
|
|
374
371
|
}
|
|
375
372
|
}
|
|
376
373
|
export function handlePeers({ flags }) {
|
|
377
|
-
//
|
|
378
|
-
// pre-D4 host-wide view for the rare operator who genuinely wants
|
|
379
|
-
// cross-tenant peer discovery.
|
|
374
|
+
// Tenant-scoped by default; --all-tenants gives the host-wide view for cross-tenant peer discovery.
|
|
380
375
|
const allTenants = flags['all-tenants'] === true;
|
|
381
376
|
const tenantScope = allTenants ? undefined : resolveTenantId({});
|
|
382
377
|
const peers = listPeers(undefined, tenantScope);
|
package/dist/cli/usage.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Help text for every verb, keyed like the command table in cli.ts; no command logic lives here.
|
|
2
2
|
import { TAIL_MAX_LINES } from '../support-bundle.js';
|
|
3
|
+
import { DEFAULT_LOCAL_BUMP, DEFAULT_RECALL_BUDGET } from '../search/types.js';
|
|
4
|
+
import { DEFAULT_ASSEMBLE_BUDGET } from '../api/assemble.js';
|
|
3
5
|
export function printAuditPruneUsage() {
|
|
4
6
|
console.log('hippo audit prune --older-than <Nd> [--dry-run] [--tenant <t>]');
|
|
5
7
|
console.log(' --older-than <Nd> Delete audit_log rows with ts older than N days (e.g. 90d).');
|
|
@@ -102,7 +104,7 @@ export const VERB_USAGE = {
|
|
|
102
104
|
--global Store in global store ($HIPPO_HOME or ~/.hippo/)`],
|
|
103
105
|
recall: [`
|
|
104
106
|
recall <query> Search and retrieve memories (local + global)
|
|
105
|
-
--budget <n> Token budget for the whole printed block (default:
|
|
107
|
+
--budget <n> Token budget for the whole printed block (default: ${DEFAULT_RECALL_BUDGET})
|
|
106
108
|
--min-results <n> Minimum results regardless of budget (default: 1)
|
|
107
109
|
--json Output as JSON
|
|
108
110
|
--why Show match reasons and source annotations
|
|
@@ -193,7 +195,7 @@ export const VERB_USAGE = {
|
|
|
193
195
|
--json Output as JSON`],
|
|
194
196
|
assemble: [`
|
|
195
197
|
assemble --session <id> Build a session's chronological context window
|
|
196
|
-
--budget N Token budget for the printed window (default
|
|
198
|
+
--budget N Token budget for the printed window (default ${DEFAULT_ASSEMBLE_BUDGET})
|
|
197
199
|
--fresh-tail N Recent rows always kept verbatim (default 10)
|
|
198
200
|
--no-summarize-older Disable older-row summary substitution
|
|
199
201
|
--scope <s> Restrict to exact scope (default: deny *:private:*)
|
|
@@ -205,7 +207,7 @@ export const VERB_USAGE = {
|
|
|
205
207
|
--pin Pin the new memory (default: pinned if the old one was)`],
|
|
206
208
|
explain: [`
|
|
207
209
|
explain <query> Show full score breakdown for each retrieved memory
|
|
208
|
-
--budget <n> Token budget, counted as recall prints (default:
|
|
210
|
+
--budget <n> Token budget, counted as recall prints (default: ${DEFAULT_RECALL_BUDGET})
|
|
209
211
|
--limit <n> Cap the number of results displayed
|
|
210
212
|
--json Output as JSON
|
|
211
213
|
--physics | --classic Force search mode (default: from config)
|
|
@@ -221,7 +223,7 @@ export const VERB_USAGE = {
|
|
|
221
223
|
--no-mmr Disable MMR for this eval run
|
|
222
224
|
--mmr-lambda <f> Override MMR lambda for this run
|
|
223
225
|
--embedding-weight <f> Override cosine weight (default: 0.6)
|
|
224
|
-
--local-bump <f> Local-over-global priority multiplier (default:
|
|
226
|
+
--local-bump <f> Local-over-global priority multiplier (default: ${DEFAULT_LOCAL_BUMP})
|
|
225
227
|
--equal-sources Shortcut for --local-bump 1.0
|
|
226
228
|
--min-mrr <f> Exit non-zero if mean MRR falls below this
|
|
227
229
|
--json Output full summary as JSON`],
|
|
@@ -393,8 +395,9 @@ export const VERB_USAGE = {
|
|
|
393
395
|
Fold one project name into another (dry run unless --apply;
|
|
394
396
|
writes a backup and one audit event first)
|
|
395
397
|
projects repair [--apply]
|
|
396
|
-
|
|
397
|
-
|
|
398
|
+
Set aside misfiled note imports, fold old project names into
|
|
399
|
+
their ids, re-tag merged rows (dry run unless --apply;
|
|
400
|
+
writes a backup and one audit event first)`],
|
|
398
401
|
quarantine: [`
|
|
399
402
|
quarantine [list] List memories a connector flagged as an instruction attempt, pending review
|
|
400
403
|
--all Include approved and rejected rows too (default: pending only)
|
package/dist/cli.d.ts
CHANGED