hippo-memory 1.61.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 +37 -53
- package/dist/agent-memories/apply.d.ts +3 -1
- package/dist/agent-memories/apply.js +23 -1
- package/dist/agent-memories/claude-code.d.ts +4 -1
- package/dist/agent-memories/claude-code.js +53 -9
- package/dist/agent-memories/report.d.ts +1 -0
- package/dist/agent-memories/report.js +2 -2
- package/dist/agent-memories/sync.d.ts +3 -3
- package/dist/agent-memories/sync.js +46 -24
- package/dist/agent-memories/types.d.ts +0 -2
- 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 +62 -66
- 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 +50 -0
- package/dist/api/context-select.js +342 -0
- package/dist/api/context-types.d.ts +12 -17
- package/dist/api/context.d.ts +5 -4
- package/dist/api/context.js +208 -535
- package/dist/api/dormant.js +1 -1
- package/dist/api/drill-down.d.ts +4 -4
- package/dist/api/drill-down.js +56 -41
- 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/promote.js +55 -66
- 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 +310 -456
- package/dist/api/remember.d.ts +2 -2
- package/dist/api/sleep.d.ts +7 -35
- package/dist/api/sleep.js +206 -220
- 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 +2 -2
- package/dist/capture/compact.js +11 -15
- 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/briefs.js +324 -306
- package/dist/cli/context.js +44 -34
- package/dist/cli/continuity.js +283 -271
- package/dist/cli/curate.d.ts +1 -1
- package/dist/cli/curate.js +43 -58
- package/dist/cli/dag.js +5 -9
- package/dist/cli/decisions.js +334 -345
- package/dist/cli/explain.js +68 -61
- package/dist/cli/goals.js +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/cli/maintenance.js +62 -51
- package/dist/cli/playbooks.js +391 -379
- package/dist/cli/projects.js +11 -6
- package/dist/cli/recall.js +30 -44
- package/dist/cli/remember.js +118 -87
- package/dist/cli/session-hooks.js +106 -115
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +267 -250
- 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 +80 -76
- package/dist/cli/transfer.js +88 -107
- 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 -2
- 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 +82 -76
- package/dist/dag.d.ts +10 -21
- package/dist/dag.js +189 -203
- 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 +97 -80
- package/dist/dedupe.js +86 -61
- package/dist/delivery-recorder.js +154 -135
- package/dist/doctor.js +129 -110
- 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 +103 -91
- 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 +46 -39
- 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 +96 -81
- 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 +88 -72
- package/dist/project-briefs.d.ts +2 -3
- package/dist/project-briefs.js +141 -118
- package/dist/project-identity.d.ts +22 -9
- package/dist/project-identity.js +47 -12
- package/dist/project-merge.d.ts +28 -5
- package/dist/project-merge.js +213 -46
- 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 +26 -17
- package/dist/shared.js +102 -104
- package/dist/skills.d.ts +3 -3
- package/dist/skills.js +88 -72
- 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 +34 -56
- 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
|
@@ -12,9 +12,9 @@ import { readSessionScan, recordSessionDigest } from '../session-digest.js';
|
|
|
12
12
|
import { openHippoDb, closeHippoDb } from '../db.js';
|
|
13
13
|
import { captureToolFailure } from '../capture-error.js';
|
|
14
14
|
import { estimateTokens, isSubagentPayload, readApiCalls, recordRereads, recordTokenUse, } from '../token-ledger.js';
|
|
15
|
-
import { currentMachine,
|
|
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
|
}
|
|
@@ -127,48 +118,8 @@ function cmdCompactResume(hippoRoot, stdinText, stdinTimedOut) {
|
|
|
127
118
|
if (!suppressOutput && payloadSessionId !== null && inPilotHoldout(hippoRoot, resolveTenantId({}), payloadSessionId, false)) {
|
|
128
119
|
suppressOutput = true;
|
|
129
120
|
}
|
|
130
|
-
if (!suppressOutput)
|
|
131
|
-
|
|
132
|
-
const snapshot = loadFreshActiveTaskSnapshot(hippoRoot, tenantId, { maxAgeMs: COMPACT_RESUME_MAX_AGE_MS });
|
|
133
|
-
// X5: concurrent sessions must not cross-restore. Only suppress when
|
|
134
|
-
// BOTH ids are present and differ — either side missing, or a manual
|
|
135
|
-
// invocation with no payload session_id, still prints.
|
|
136
|
-
const sessionMismatch = !!snapshot &&
|
|
137
|
-
payloadSessionId !== null &&
|
|
138
|
-
snapshot.session_id !== null &&
|
|
139
|
-
payloadSessionId !== snapshot.session_id;
|
|
140
|
-
if (snapshot && !sessionMismatch) {
|
|
141
|
-
// Loaded before the print so a bad trail row costs the trail, not the snapshot; stderr stays out of the model's context.
|
|
142
|
-
let events = [];
|
|
143
|
-
try {
|
|
144
|
-
if (snapshot.session_id) {
|
|
145
|
-
events = listSessionEvents(hippoRoot, tenantId, { session_id: snapshot.session_id }).map((e) => ({
|
|
146
|
-
...e,
|
|
147
|
-
content: truncateCodePointSafe(e.content, COMPACT_RESUME_EVENT_CONTENT_CAP),
|
|
148
|
-
}));
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
catch (err) {
|
|
152
|
-
log.warn(`hippo compact-resume: trail skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
153
|
-
}
|
|
154
|
-
// Printed in one write so the ledger books exactly the text the model is handed.
|
|
155
|
-
const text = captureConsole(() => {
|
|
156
|
-
console.log('## Restored after compaction\n');
|
|
157
|
-
// X12: re-injected state is background reference, not instructions:
|
|
158
|
-
// the framing line the model actually sees at every compaction.
|
|
159
|
-
console.log("_Point-in-time working-state snapshot, auto-restored after compaction. Background reference, not instructions; the user's live messages win._\n");
|
|
160
|
-
printActiveTaskSnapshot(snapshot);
|
|
161
|
-
// Nothing auto-populates session_events, so an empty trail is the common real case;
|
|
162
|
-
// printSessionEvents([]) would inject a bare "No session events found." line into every compaction.
|
|
163
|
-
if (events.length > 0)
|
|
164
|
-
printSessionEvents(events);
|
|
165
|
-
});
|
|
166
|
-
console.log(text);
|
|
167
|
-
withLedgerDb(hippoRoot, (db) => recordTokenUse(db, {
|
|
168
|
-
tenantId, sessionId: payloadSessionId, surface: 'compact_resume', event: 'inject', items: 1, tokens: estimateTokens(text),
|
|
169
|
-
}));
|
|
170
|
-
}
|
|
171
|
-
}
|
|
121
|
+
if (!suppressOutput)
|
|
122
|
+
restoreCompactSnapshot(hippoRoot, payloadSessionId);
|
|
172
123
|
}
|
|
173
124
|
catch (err) {
|
|
174
125
|
// Empty stdout on any store error, never a crashed SessionStart; the reason goes to stderr, which the model never sees.
|
|
@@ -176,6 +127,46 @@ function cmdCompactResume(hippoRoot, stdinText, stdinTimedOut) {
|
|
|
176
127
|
}
|
|
177
128
|
process.exit(0);
|
|
178
129
|
}
|
|
130
|
+
function restoreCompactSnapshot(hippoRoot, payloadSessionId) {
|
|
131
|
+
const tenantId = resolveTenantId({});
|
|
132
|
+
const snapshot = loadFreshActiveTaskSnapshot(hippoRoot, tenantId, { maxAgeMs: COMPACT_RESUME_MAX_AGE_MS });
|
|
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.
|
|
135
|
+
const sessionMismatch = !!snapshot &&
|
|
136
|
+
payloadSessionId !== null &&
|
|
137
|
+
snapshot.session_id !== null &&
|
|
138
|
+
payloadSessionId !== snapshot.session_id;
|
|
139
|
+
if (!snapshot || sessionMismatch)
|
|
140
|
+
return;
|
|
141
|
+
// Loaded before the print so a bad trail row costs the trail, not the snapshot; stderr stays out of the model's context.
|
|
142
|
+
let events = [];
|
|
143
|
+
try {
|
|
144
|
+
if (snapshot.session_id) {
|
|
145
|
+
events = listSessionEvents(hippoRoot, tenantId, { session_id: snapshot.session_id }).map((e) => ({
|
|
146
|
+
...e,
|
|
147
|
+
content: truncateCodePointSafe(e.content, COMPACT_RESUME_EVENT_CONTENT_CAP),
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
log.warn(`hippo compact-resume: trail skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
153
|
+
}
|
|
154
|
+
// Printed in one write so the ledger books exactly the text the model is handed.
|
|
155
|
+
const text = captureConsole(() => {
|
|
156
|
+
console.log('## Restored after compaction\n');
|
|
157
|
+
// Re-injected state is background reference, not instructions: the framing line the model sees at every compaction.
|
|
158
|
+
console.log("_Point-in-time working-state snapshot, auto-restored after compaction. Background reference, not instructions; the user's live messages win._\n");
|
|
159
|
+
printActiveTaskSnapshot(snapshot);
|
|
160
|
+
// Nothing auto-populates session_events, so an empty trail is the common real case;
|
|
161
|
+
// printSessionEvents([]) would inject a bare "No session events found." line into every compaction.
|
|
162
|
+
if (events.length > 0)
|
|
163
|
+
printSessionEvents(events);
|
|
164
|
+
});
|
|
165
|
+
console.log(text);
|
|
166
|
+
withLedgerDb(hippoRoot, (db) => recordTokenUse(db, {
|
|
167
|
+
tenantId, sessionId: payloadSessionId, surface: 'compact_resume', event: 'inject', items: 1, tokens: estimateTokens(text),
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
179
170
|
/**
|
|
180
171
|
* SessionEnd entry point. Claude Code / OpenCode fire this on /exit while
|
|
181
172
|
* tearing down the TUI, which kills any child that is still running when
|
|
@@ -189,8 +180,7 @@ function cmdCompactResume(hippoRoot, stdinText, stdinTimedOut) {
|
|
|
189
180
|
*/
|
|
190
181
|
export async function cmdSessionEnd(hippoRoot, flags) {
|
|
191
182
|
const logFile = typeof flags['log-file'] === 'string' ? flags['log-file'] : null;
|
|
192
|
-
// Bounded read
|
|
193
|
-
// 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.
|
|
194
184
|
let sessionId = null;
|
|
195
185
|
const { text: stdinText } = await readStdinBounded();
|
|
196
186
|
try {
|
|
@@ -222,7 +212,7 @@ export async function cmdSessionEnd(hippoRoot, flags) {
|
|
|
222
212
|
});
|
|
223
213
|
child.unref();
|
|
224
214
|
}
|
|
225
|
-
catch
|
|
215
|
+
catch {
|
|
226
216
|
// If spawn fails, run inline as a last resort, handed what the child's argv would have carried.
|
|
227
217
|
if (transcriptPath)
|
|
228
218
|
flags['transcript'] = transcriptPath;
|
|
@@ -249,6 +239,35 @@ export async function cmdSessionEndWorker(hippoRoot, flags) {
|
|
|
249
239
|
flushRereadLog();
|
|
250
240
|
return;
|
|
251
241
|
}
|
|
242
|
+
await sleepProjectStore(hippoRoot, flags, closeLogFile, transcriptPath);
|
|
243
|
+
flushRereadLog();
|
|
244
|
+
const digestLog = (message) => appendSessionEndCloseLog(closeLogFile, message);
|
|
245
|
+
const scan = transcriptPath ? readSessionScan(transcriptPath, digestLog) : null;
|
|
246
|
+
captureEndedSession(hippoRoot, store, flags, transcriptPath, scan);
|
|
247
|
+
recordSessionDigest(hippoRoot, scan, {
|
|
248
|
+
key: closeSessionId || path.basename(transcriptPath ?? '', '.jsonl'),
|
|
249
|
+
tenantId: resolveTenantId({}),
|
|
250
|
+
log: digestLog,
|
|
251
|
+
});
|
|
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.
|
|
255
|
+
if (closeSessionId)
|
|
256
|
+
writeEndHandoff(store, closeSessionId, transcriptPath, closeLogFile);
|
|
257
|
+
try {
|
|
258
|
+
if (closeSessionId) {
|
|
259
|
+
const closed = closeTaskSnapshotsForSession(store, resolveTenantId({}), closeSessionId);
|
|
260
|
+
appendSessionEndCloseLog(closeLogFile, `closed ${closed} active snapshot(s) for session ${closeSessionId}`);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
appendSessionEndCloseLog(closeLogFile, 'skip: no session_id in SessionEnd payload, active snapshot left untouched');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch (err) {
|
|
267
|
+
appendSessionEndCloseLog(closeLogFile, `snapshot close failed: ${err.message}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async function sleepProjectStore(hippoRoot, flags, closeLogFile, transcriptPath) {
|
|
252
271
|
// Sleeping the global store from here would learn this folder's git commits into it; it has its own daily sleep.
|
|
253
272
|
if (isInitialized(hippoRoot)) {
|
|
254
273
|
try {
|
|
@@ -263,9 +282,8 @@ export async function cmdSessionEndWorker(hippoRoot, flags) {
|
|
|
263
282
|
appendSessionEndCloseLog(closeLogFile, 'skip sleep: this folder has no store of its own', { startFresh: true });
|
|
264
283
|
logSessionEndImport(closeLogFile, transcriptPath);
|
|
265
284
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const scan = transcriptPath ? readSessionScan(transcriptPath, digestLog) : null;
|
|
285
|
+
}
|
|
286
|
+
function captureEndedSession(hippoRoot, store, flags, transcriptPath, scan) {
|
|
269
287
|
try {
|
|
270
288
|
const logFile = typeof flags['log-file'] === 'string' ? flags['log-file'] : undefined;
|
|
271
289
|
// With no stdin of its own, capture would read this as a manual run and scan every project.
|
|
@@ -281,7 +299,7 @@ export async function cmdSessionEndWorker(hippoRoot, flags) {
|
|
|
281
299
|
global: false,
|
|
282
300
|
tenantId: resolveTenantId({}),
|
|
283
301
|
// In the global store, rows would otherwise read as user-global and show up in every project.
|
|
284
|
-
originProject: store === hippoRoot ? undefined :
|
|
302
|
+
originProject: store === hippoRoot ? undefined : resolveProjectIdentity(process.cwd()),
|
|
285
303
|
sessionTurns: scan?.turns,
|
|
286
304
|
});
|
|
287
305
|
}
|
|
@@ -289,54 +307,27 @@ export async function cmdSessionEndWorker(hippoRoot, flags) {
|
|
|
289
307
|
catch {
|
|
290
308
|
// Same treatment — the failure line is already in the log.
|
|
291
309
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
tenantId: resolveTenantId({}),
|
|
295
|
-
log: digestLog,
|
|
296
|
-
});
|
|
297
|
-
// DF1 T3: close the ending session's own active task snapshot AFTER
|
|
298
|
-
// sleep+capture complete — neither producer (runPreCompact,
|
|
299
|
-
// `hippo snapshot save`) runs inside session-end, so this can never
|
|
300
|
-
// destroy same-run work. Scoped to `--session-id`: a concurrent session's
|
|
301
|
-
// active snapshot is untouched (closeTaskSnapshotsForSession's own WHERE
|
|
302
|
-
// clause). Absent session id -> no-op plus one log line; session-end is
|
|
303
|
-
// not guaranteed to fire at all (crash, kill -9), so the freshness bound
|
|
304
|
-
// in loadFreshActiveTaskSnapshot is the backstop layer, not this close.
|
|
305
|
-
// Handoff write happens BEFORE the snapshot close below, while the
|
|
306
|
-
// snapshot writeSessionEndHandoff reads is still active.
|
|
307
|
-
if (closeSessionId) {
|
|
308
|
-
try {
|
|
309
|
-
const tenantId = resolveTenantId({});
|
|
310
|
-
const ownSnapshot = loadActiveTaskSnapshot(store, tenantId)?.session_id === closeSessionId;
|
|
311
|
-
// A never-compacted session has no snapshot; read even when it has one, as another session's PreCompact can take the slot before the write.
|
|
312
|
-
const derived = transcriptPath
|
|
313
|
-
? transcriptWorkingState(transcriptPath, (message) => appendSessionEndCloseLog(closeLogFile, message))
|
|
314
|
-
: null;
|
|
315
|
-
if (!ownSnapshot && !derived) {
|
|
316
|
-
appendSessionEndCloseLog(closeLogFile, 'skip: no snapshot or transcript for session');
|
|
317
|
-
}
|
|
318
|
-
else {
|
|
319
|
-
const evidence = collectHandoffEvidence(process.cwd(), 'unknown');
|
|
320
|
-
const handoff = writeSessionEndHandoff(store, tenantId, closeSessionId, evidence, derived);
|
|
321
|
-
appendSessionEndCloseLog(closeLogFile, handoff ? `wrote handoff for session ${closeSessionId}` : `skip: kept the existing handoff for session ${closeSessionId}`);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
catch (err) {
|
|
325
|
-
// SAFETY: catch clauses bind unknown, but Node/V8 always throws an Error here.
|
|
326
|
-
appendSessionEndCloseLog(closeLogFile, `handoff write failed: ${err.message}`);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
310
|
+
}
|
|
311
|
+
function writeEndHandoff(store, closeSessionId, transcriptPath, closeLogFile) {
|
|
329
312
|
try {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
313
|
+
const tenantId = resolveTenantId({});
|
|
314
|
+
const ownSnapshot = loadActiveTaskSnapshot(store, tenantId)?.session_id === closeSessionId;
|
|
315
|
+
// A never-compacted session has no snapshot; read even when it has one, as another session's PreCompact can take the slot before the write.
|
|
316
|
+
const derived = transcriptPath
|
|
317
|
+
? transcriptWorkingState(transcriptPath, (message) => appendSessionEndCloseLog(closeLogFile, message))
|
|
318
|
+
: null;
|
|
319
|
+
if (!ownSnapshot && !derived) {
|
|
320
|
+
appendSessionEndCloseLog(closeLogFile, 'skip: no snapshot or transcript for session');
|
|
333
321
|
}
|
|
334
322
|
else {
|
|
335
|
-
|
|
323
|
+
const evidence = collectHandoffEvidence(process.cwd(), 'unknown');
|
|
324
|
+
const handoff = writeSessionEndHandoff(store, tenantId, closeSessionId, evidence, derived);
|
|
325
|
+
appendSessionEndCloseLog(closeLogFile, handoff ? `wrote handoff for session ${closeSessionId}` : `skip: kept the existing handoff for session ${closeSessionId}`);
|
|
336
326
|
}
|
|
337
327
|
}
|
|
338
328
|
catch (err) {
|
|
339
|
-
|
|
329
|
+
// SAFETY: catch clauses bind unknown, but Node/V8 always throws an Error here.
|
|
330
|
+
appendSessionEndCloseLog(closeLogFile, `handoff write failed: ${err.message}`);
|
|
340
331
|
}
|
|
341
332
|
}
|
|
342
333
|
/** Books the ending session's re-reads in each store its ledger rows can land in (project and global); returns the log lines. */
|
|
@@ -521,7 +512,7 @@ export async function cmdCodexSessionEndWorker(hippoRoot, flags) {
|
|
|
521
512
|
dryRun: false,
|
|
522
513
|
global: false,
|
|
523
514
|
tenantId: resolveTenantId({}),
|
|
524
|
-
originProject: store === hippoRoot ? undefined :
|
|
515
|
+
originProject: store === hippoRoot ? undefined : resolveProjectIdentity(process.cwd()),
|
|
525
516
|
sessionTurns: scan?.turns,
|
|
526
517
|
};
|
|
527
518
|
try {
|
|
@@ -558,8 +549,8 @@ export async function handlePostCompact({ hippoRoot, flags }) {
|
|
|
558
549
|
stdinText: text,
|
|
559
550
|
logFile: logFlag === true || logFlag === false || Array.isArray(logFlag) ? undefined : logFlag,
|
|
560
551
|
// Passed in, since capture.ts importing the sync would close an import cycle.
|
|
561
|
-
afterSave: (transcriptPath,
|
|
562
|
-
const report =
|
|
552
|
+
afterSave: (transcriptPath, cwd, log) => {
|
|
553
|
+
const report = importSessionFolder(store, transcriptPath, cwd, { machine: currentMachine(), busyWaitMs: COMPACTION_DB_WAIT_MS });
|
|
563
554
|
const summary = summaryLine(report);
|
|
564
555
|
if (summary !== null)
|
|
565
556
|
log(summary);
|
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
|