hippo-memory 1.71.0 → 2.0.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 +7 -5
- package/dist/agent-memories/apply.d.ts +0 -11
- package/dist/agent-memories/apply.js +11 -26
- package/dist/agent-memories/claude-code.js +1 -1
- package/dist/agent-memories/codex.js +1 -1
- package/dist/agent-memories/copilot.d.ts +1 -3
- package/dist/agent-memories/copilot.js +1 -17
- package/dist/agent-memories/project-folds.d.ts +10 -0
- package/dist/agent-memories/project-folds.js +34 -0
- package/dist/agent-memories/sync.js +8 -6
- package/dist/api/assemble.js +3 -2
- package/dist/api/audit.d.ts +30 -2
- package/dist/api/audit.js +48 -7
- package/dist/api/auth.d.ts +11 -9
- package/dist/api/auth.js +39 -40
- package/dist/api/auto-sleep.d.ts +5 -2
- package/dist/api/auto-sleep.js +7 -3
- package/dist/api/availability.js +2 -3
- package/dist/api/cards.d.ts +42 -0
- package/dist/api/cards.js +52 -0
- package/dist/api/conflicts.d.ts +28 -0
- package/dist/api/conflicts.js +61 -0
- package/dist/api/context-auto.js +4 -2
- package/dist/api/context-render.js +4 -3
- package/dist/api/context-select.js +15 -29
- package/dist/api/context.js +29 -18
- package/dist/api/continuity.d.ts +47 -0
- package/dist/api/continuity.js +66 -0
- package/dist/api/dormant.js +4 -2
- package/dist/api/drill-down.js +3 -2
- package/dist/api/embeddings.d.ts +17 -0
- package/dist/api/embeddings.js +28 -0
- package/dist/api/error-reply.d.ts +8 -0
- package/dist/api/error-reply.js +21 -0
- package/dist/api/forget.d.ts +7 -3
- package/dist/api/forget.js +24 -14
- package/dist/api/goals.d.ts +1 -1
- package/dist/api/goals.js +5 -9
- package/dist/api/graph.js +2 -1
- package/dist/api/index.d.ts +4 -2
- package/dist/api/index.js +4 -2
- package/dist/api/instruction-detect.js +5 -1
- package/dist/api/learn.d.ts +5 -1
- package/dist/api/learn.js +71 -44
- package/dist/api/ledger-db.d.ts +2 -6
- package/dist/api/ledger-db.js +4 -36
- package/dist/api/memories.d.ts +21 -1
- package/dist/api/memories.js +51 -1
- package/dist/api/objects.d.ts +1 -1
- package/dist/api/objects.js +2 -1
- package/dist/api/outcome.d.ts +5 -5
- package/dist/api/outcome.js +17 -16
- package/dist/api/pilot-arm.d.ts +1 -11
- package/dist/api/pilot-arm.js +5 -45
- package/dist/api/predictions.d.ts +3 -1
- package/dist/api/predictions.js +8 -1
- package/dist/api/projects.d.ts +21 -0
- package/dist/api/projects.js +24 -0
- package/dist/api/promote.d.ts +3 -3
- package/dist/api/promote.js +26 -28
- package/dist/api/prompt-hook.d.ts +17 -2
- package/dist/api/prompt-hook.js +45 -4
- package/dist/api/quarantine.js +2 -1
- package/dist/api/recall-cli.d.ts +3 -0
- package/dist/api/recall-cli.js +13 -4
- package/dist/api/recall-core.js +10 -5
- package/dist/api/recall-pipeline.js +23 -24
- package/dist/api/recall-request.js +1 -1
- package/dist/api/recall-types.d.ts +3 -1
- package/dist/api/recall.d.ts +0 -3
- package/dist/api/recall.js +51 -73
- package/dist/api/remember-local.d.ts +5 -2
- package/dist/api/remember-local.js +15 -7
- package/dist/api/remember.d.ts +7 -3
- package/dist/api/remember.js +19 -16
- package/dist/api/session-end.d.ts +46 -0
- package/dist/api/session-end.js +131 -0
- package/dist/api/sleep-run.d.ts +1 -1
- package/dist/api/sleep-run.js +16 -11
- package/dist/api/sleep.js +4 -3
- package/dist/api/status.d.ts +24 -0
- package/dist/api/status.js +40 -0
- package/dist/api/store-init.d.ts +4 -0
- package/dist/api/store-init.js +9 -0
- package/dist/api/tokens.js +2 -2
- package/dist/api/types.d.ts +3 -7
- package/dist/api/types.js +6 -1
- package/dist/capture/caller-session.d.ts +0 -3
- package/dist/capture/caller-session.js +1 -12
- package/dist/capture/capture-error.d.ts +2 -2
- package/dist/capture/capture-error.js +23 -18
- package/dist/capture/codex-patch.js +3 -1
- package/dist/capture/command.js +36 -95
- package/dist/capture/compact.js +10 -5
- package/dist/capture/compaction-items-caller.js +11 -20
- package/dist/capture/compaction-record.d.ts +7 -93
- package/dist/capture/compaction-record.js +29 -426
- package/dist/capture/compaction-spool.d.ts +7 -7
- package/dist/capture/compaction-spool.js +60 -51
- package/dist/capture/copilot-transcript.d.ts +2 -1
- package/dist/capture/copilot-transcript.js +2 -1
- package/dist/capture/extract.d.ts +5 -2
- package/dist/capture/extract.js +4 -3
- package/dist/capture/failure-caller.d.ts +1 -1
- package/dist/capture/failure-caller.js +21 -16
- package/dist/capture/failure-reading.d.ts +2 -1
- package/dist/capture/failure-reading.js +7 -9
- package/dist/capture/pre-compact-caller.js +5 -4
- package/dist/capture/session-digest.js +4 -3
- package/dist/capture/session-end-caller.js +3 -2
- package/dist/capture/session-worker.js +22 -10
- package/dist/capture/transcript.d.ts +2 -1
- package/dist/capture/transcript.js +6 -3
- package/dist/capture/working-state.d.ts +4 -2
- package/dist/capture/working-state.js +4 -2
- package/dist/cli/audit-prune.d.ts +0 -25
- package/dist/cli/audit-prune.js +1 -27
- package/dist/cli/audit.js +20 -20
- package/dist/cli/auth.d.ts +1 -1
- package/dist/cli/auth.js +16 -17
- package/dist/cli/briefs.d.ts +1 -4
- package/dist/cli/briefs.js +37 -292
- package/dist/cli/card.js +41 -33
- package/dist/cli/client.d.ts +6 -2
- package/dist/cli/client.js +37 -21
- package/dist/cli/compact-resume-payload.js +1 -1
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +13 -13
- package/dist/cli/continuity.d.ts +1 -1
- package/dist/cli/continuity.js +36 -39
- package/dist/cli/curate.d.ts +2 -2
- package/dist/cli/curate.js +32 -36
- package/dist/cli/dag.d.ts +1 -1
- package/dist/cli/dag.js +23 -8
- package/dist/cli/decisions.d.ts +0 -2
- package/dist/cli/decisions.js +7 -285
- package/dist/cli/eval.d.ts +1 -1
- package/dist/cli/eval.js +12 -13
- package/dist/cli/explain.d.ts +1 -1
- package/dist/cli/explain.js +21 -25
- package/dist/cli/flag-values.js +16 -6
- package/dist/cli/flags.d.ts +0 -289
- package/dist/cli/flags.js +3 -138
- package/dist/cli/graph.d.ts +3 -0
- package/dist/cli/graph.js +83 -0
- package/dist/cli/hook-runtime.d.ts +6 -6
- package/dist/cli/hook-runtime.js +9 -36
- package/dist/cli/incidents.d.ts +3 -0
- package/dist/cli/incidents.js +112 -0
- package/dist/cli/init.d.ts +1 -1
- package/dist/cli/init.js +28 -19
- package/dist/cli/install-steps.d.ts +2 -1
- package/dist/cli/install-steps.js +11 -3
- package/dist/cli/last-sleep.js +1 -1
- package/dist/cli/maintenance.d.ts +3 -3
- package/dist/cli/maintenance.js +29 -30
- package/dist/cli/notes.d.ts +2 -0
- package/dist/cli/notes.js +41 -0
- package/dist/cli/object-verbs.d.ts +2 -2
- package/dist/cli/object-verbs.js +4 -4
- package/dist/cli/open-browser.d.ts +14 -0
- package/dist/cli/open-browser.js +26 -0
- package/dist/cli/playbooks.d.ts +3 -4
- package/dist/cli/playbooks.js +126 -290
- package/dist/cli/predictions.d.ts +3 -0
- package/dist/cli/predictions.js +174 -0
- package/dist/cli/print.js +2 -1
- package/dist/cli/projects.js +30 -22
- package/dist/cli/quality-repair-once.d.ts +1 -1
- package/dist/cli/quality-repair-once.js +6 -5
- package/dist/cli/recall.js +13 -7
- package/dist/cli/refine-llm.js +18 -17
- package/dist/cli/remember.js +17 -17
- package/dist/cli/scheduler.js +2 -1
- package/dist/cli/serve.js +11 -6
- package/dist/cli/session-hooks.d.ts +1 -5
- package/dist/cli/session-hooks.js +89 -168
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +17 -10
- package/dist/cli/shared.d.ts +2 -6
- package/dist/cli/shared.js +9 -29
- package/dist/cli/sleep-render.js +6 -3
- package/dist/cli/sleep.js +6 -37
- package/dist/cli/status.d.ts +3 -3
- package/dist/cli/status.js +32 -35
- package/dist/cli/transfer.d.ts +3 -3
- package/dist/cli/transfer.js +64 -43
- package/dist/cli/usage.d.ts +1 -80
- package/dist/cli/usage.js +2 -696
- package/dist/cli/verb-row.d.ts +34 -0
- package/dist/cli/verb-row.js +6 -0
- package/dist/cli/verbs/health.d.ts +27 -0
- package/dist/cli/verbs/health.js +234 -0
- package/dist/cli/verbs/memory.d.ts +16 -0
- package/dist/cli/verbs/memory.js +236 -0
- package/dist/cli/verbs/objects.d.ts +20 -0
- package/dist/cli/verbs/objects.js +257 -0
- package/dist/cli/verbs/sessions.d.ts +31 -0
- package/dist/cli/verbs/sessions.js +314 -0
- package/dist/cli/verbs.d.ts +81 -0
- package/dist/cli/verbs.js +7 -0
- package/dist/cli/versioned-verbs.d.ts +51 -0
- package/dist/cli/versioned-verbs.js +79 -0
- package/dist/cli.d.ts +1 -272
- package/dist/cli.js +24 -315
- package/dist/connectors/dlq.d.ts +39 -3
- package/dist/connectors/dlq.js +39 -4
- package/dist/connectors/github/backfill.js +12 -3
- package/dist/connectors/github/deletion.js +2 -1
- package/dist/connectors/github/dlq.js +31 -73
- package/dist/connectors/github/ingest.d.ts +2 -6
- package/dist/connectors/github/ingest.js +5 -29
- package/dist/connectors/github/tenant-routing.js +2 -1
- package/dist/connectors/github/webhook.d.ts +2 -1
- package/dist/connectors/github/webhook.js +35 -2
- package/dist/connectors/ingest.d.ts +10 -0
- package/dist/connectors/ingest.js +29 -0
- package/dist/connectors/slack/deletion.js +2 -1
- package/dist/connectors/slack/dlq.js +49 -71
- package/dist/connectors/slack/ingest.d.ts +2 -6
- package/dist/connectors/slack/ingest.js +4 -28
- package/dist/connectors/slack/tenant-routing.js +2 -1
- package/dist/connectors/slack/webhook.d.ts +2 -1
- package/dist/connectors/slack/webhook.js +2 -1
- package/dist/consolidate/conflicts.js +2 -2
- package/dist/consolidate/dag.js +29 -18
- package/dist/consolidate/dedupe.d.ts +7 -0
- package/dist/consolidate/dedupe.js +6 -4
- package/dist/consolidate/llm-passes.js +45 -19
- package/dist/consolidate/memory-value.js +3 -2
- package/dist/consolidate/merge.js +8 -8
- package/dist/consolidate/physics-pass.d.ts +6 -1
- package/dist/consolidate/physics-pass.js +26 -6
- package/dist/consolidate/replay.js +11 -4
- package/dist/consolidate/sleep.js +9 -6
- package/dist/consolidate/traces.js +5 -5
- package/dist/core/ablation.d.ts +10 -0
- package/dist/core/ablation.js +12 -0
- package/dist/{sharing/scope.d.ts → core/active-scope.d.ts} +1 -1
- package/dist/{sharing/scope.js → core/active-scope.js} +1 -1
- package/dist/core/ambient.d.ts +4 -0
- package/dist/core/ambient.js +39 -18
- package/dist/core/api-errors.d.ts +16 -0
- package/dist/core/api-errors.js +20 -0
- package/dist/core/card.js +3 -1
- package/dist/core/compaction-timing.d.ts +7 -0
- package/dist/core/compaction-timing.js +9 -0
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.js +22 -18
- package/dist/core/cosine.d.ts +3 -0
- package/dist/core/cosine.js +19 -0
- package/dist/{store → core}/markdown.d.ts +1 -1
- package/dist/{store → core}/markdown.js +4 -4
- package/dist/core/memory-audit.d.ts +17 -0
- package/dist/core/memory-audit.js +54 -0
- package/dist/core/memory.d.ts +14 -8
- package/dist/core/memory.js +35 -23
- package/dist/{consolidate → core}/merged-row.d.ts +1 -1
- package/dist/{consolidate → core}/merged-row.js +1 -1
- package/dist/core/physics.d.ts +3 -1
- package/dist/core/physics.js +23 -18
- package/dist/core/prediction.d.ts +3 -0
- package/dist/core/prediction.js +6 -0
- package/dist/core/project-identity.d.ts +3 -0
- package/dist/core/project-identity.js +12 -2
- package/dist/{store → core}/recall-scope.d.ts +1 -10
- package/dist/{store → core}/recall-scope.js +2 -19
- package/dist/core/search-types.d.ts +1 -1
- package/dist/dashboard/dashboard-actions.d.ts +2 -2
- package/dist/dashboard/dashboard-actions.js +5 -5
- package/dist/dashboard/dashboard-queries.js +2 -7
- package/dist/dashboard/dashboard-snapshot.js +1 -3
- package/dist/dashboard/dashboard.js +16 -5
- package/dist/db/busy.d.ts +2 -7
- package/dist/db/busy.js +21 -26
- package/dist/db/connect.d.ts +2 -2
- package/dist/db/connect.js +7 -7
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.js +3 -3
- package/dist/db/migrate.js +14 -7
- package/dist/db/migrations/index.d.ts +1 -1
- package/dist/db/migrations/index.js +3 -1
- package/dist/db/migrations/v11.js +1 -0
- package/dist/db/migrations/v14.js +1 -0
- package/dist/db/migrations/v55.d.ts +3 -0
- package/dist/db/migrations/v55.js +17 -0
- package/dist/db/open.d.ts +0 -2
- package/dist/db/open.js +6 -10
- package/dist/db/physics-state.d.ts +0 -4
- package/dist/db/physics-state.js +7 -33
- package/dist/db/request-stores.d.ts +1 -0
- package/dist/db/request-stores.js +2 -1
- package/dist/db/tables.d.ts +2 -0
- package/dist/db/tables.js +6 -2
- package/dist/db/vector-store.js +19 -5
- package/dist/db/wal-checkpointer.js +2 -1
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.js +18 -15
- package/dist/embeddings/local.d.ts +62 -0
- package/dist/embeddings/local.js +146 -0
- package/dist/{store/embeddings → embeddings}/provider.d.ts +5 -2
- package/dist/{store/embeddings → embeddings}/provider.js +19 -25
- package/dist/embeddings/transformers.d.ts +26 -0
- package/dist/embeddings/transformers.js +89 -0
- package/dist/entry/session-text.d.ts +1 -1
- package/dist/entry/session-text.js +1 -1
- package/dist/entry/store-kit.d.ts +37 -0
- package/dist/entry/store-kit.js +25 -0
- package/dist/entry/testing.d.ts +6 -0
- package/dist/entry/testing.js +7 -0
- package/dist/eval/eval-suite.js +17 -11
- package/dist/eval/eval.js +1 -1
- package/dist/eval/judgment.js +12 -5
- package/dist/graph/extract.js +3 -3
- package/dist/graph/recall.js +1 -1
- package/dist/graph/view.js +13 -5
- package/dist/graph/write.d.ts +1 -1
- package/dist/graph/write.js +9 -9
- package/dist/hooks/codex-session.js +3 -2
- package/dist/hooks/codex-wrapper.js +2 -1
- package/dist/hooks/json-hooks.js +10 -4
- package/dist/hooks/opencode.js +8 -5
- package/dist/hooks/shared.d.ts +0 -6
- package/dist/hooks/shared.js +4 -15
- package/dist/importers/core.js +4 -4
- package/dist/importers/sources.js +5 -4
- package/dist/importers/vault.d.ts +1 -1
- package/dist/importers/vault.js +25 -23
- package/dist/index.d.ts +5 -4
- package/dist/index.js +4 -3
- package/dist/learn/autolearn.d.ts +15 -3
- package/dist/learn/autolearn.js +38 -16
- package/dist/learn/churn-git.js +13 -4
- package/dist/learn/extract.d.ts +3 -2
- package/dist/learn/extract.js +7 -5
- package/dist/learn/forward-claim-detector.js +4 -2
- package/dist/learn/invalidation.d.ts +2 -1
- package/dist/learn/invalidation.js +18 -9
- package/dist/mcp/admin-tools.d.ts +2 -2
- package/dist/mcp/admin-tools.js +27 -48
- package/dist/mcp/format.js +3 -2
- package/dist/mcp/framing.d.ts +1 -0
- package/dist/mcp/framing.js +1 -1
- package/dist/mcp/memory-tools.d.ts +1 -1
- package/dist/mcp/memory-tools.js +8 -9
- package/dist/mcp/protocol.d.ts +11 -7
- package/dist/mcp/protocol.js +25 -12
- package/dist/mcp/recall-tools.js +12 -9
- package/dist/mcp/request.js +22 -20
- package/dist/mcp/stdio.js +37 -16
- package/dist/mcp/tool-args.js +2 -1
- package/dist/mcp/tools.js +44 -21
- package/dist/objects/customer-notes.d.ts +2 -2
- package/dist/objects/decisions.d.ts +2 -2
- package/dist/objects/descriptor.d.ts +1 -1
- package/dist/objects/incidents.d.ts +2 -2
- package/dist/objects/lifecycle.d.ts +1 -1
- package/dist/objects/lifecycle.js +2 -1
- package/dist/objects/policies.d.ts +2 -2
- package/dist/objects/policies.js +2 -1
- package/dist/objects/processes.d.ts +2 -2
- package/dist/objects/project-briefs.d.ts +2 -2
- package/dist/objects/project-briefs.js +2 -3
- package/dist/objects/skills.d.ts +2 -2
- package/dist/postinstall.js +1 -1
- package/dist/rerankers/clef.js +3 -6
- package/dist/rerankers/cross-encoder.d.ts +31 -2
- package/dist/rerankers/cross-encoder.js +71 -98
- package/dist/rerankers/index.js +5 -4
- package/dist/rerankers/jev.js +2 -4
- package/dist/rerankers/outage-warning.d.ts +3 -1
- package/dist/rerankers/outage-warning.js +5 -3
- package/dist/search/bm25-search.js +1 -1
- package/dist/search/boosts.js +1 -1
- package/dist/search/embed-memories.d.ts +12 -0
- package/dist/search/embed-memories.js +389 -0
- package/dist/search/engine.d.ts +8 -0
- package/dist/search/engine.js +10 -0
- package/dist/search/goal-boost.d.ts +1 -1
- package/dist/search/goal-boost.js +6 -3
- package/dist/search/hybrid.d.ts +9 -2
- package/dist/search/hybrid.js +9 -4
- package/dist/search/physics-search.d.ts +6 -3
- package/dist/search/physics-search.js +22 -15
- package/dist/search/rerank.js +1 -1
- package/dist/search/vector.d.ts +8 -6
- package/dist/search/vector.js +14 -17
- package/dist/server/auth.d.ts +3 -1
- package/dist/server/auth.js +24 -15
- package/dist/server/boot.d.ts +2 -1
- package/dist/server/boot.js +34 -84
- package/dist/server/client-ip.d.ts +9 -6
- package/dist/server/client-ip.js +36 -17
- package/dist/server/deadline.d.ts +0 -2
- package/dist/server/deadline.js +1 -7
- package/dist/server/defaults.d.ts +1 -0
- package/dist/server/defaults.js +1 -0
- package/dist/server/mcp-http.js +16 -11
- package/dist/server/request.js +7 -2
- package/dist/server/route-checks.d.ts +7 -0
- package/dist/server/route-checks.js +42 -0
- package/dist/server/route-table.d.ts +9 -8
- package/dist/server/route-table.js +127 -133
- package/dist/server/routes/admin.d.ts +8 -8
- package/dist/server/routes/admin.js +13 -21
- package/dist/server/routes/customer-notes.d.ts +6 -6
- package/dist/server/routes/customer-notes.js +1 -2
- package/dist/server/routes/decisions.d.ts +6 -6
- package/dist/server/routes/decisions.js +2 -4
- package/dist/server/routes/incidents.d.ts +6 -6
- package/dist/server/routes/incidents.js +2 -5
- package/dist/server/routes/memories.d.ts +9 -9
- package/dist/server/routes/memories.js +19 -40
- package/dist/server/routes/object-routes.d.ts +6 -6
- package/dist/server/routes/object-routes.js +4 -7
- package/dist/server/routes/policies.d.ts +7 -7
- package/dist/server/routes/policies.js +2 -4
- package/dist/server/routes/predictions.d.ts +6 -6
- package/dist/server/routes/predictions.js +9 -13
- package/dist/server/routes/processes.d.ts +6 -6
- package/dist/server/routes/processes.js +1 -2
- package/dist/server/routes/project-briefs.d.ts +7 -7
- package/dist/server/routes/project-briefs.js +2 -4
- package/dist/server/routes/recall.d.ts +5 -5
- package/dist/server/routes/recall.js +6 -10
- package/dist/server/routes/skills.d.ts +7 -7
- package/dist/server/routes/skills.js +2 -4
- package/dist/server/server-detect.d.ts +7 -1
- package/dist/server/server-detect.js +36 -11
- package/dist/server/sleep-child.js +26 -7
- package/dist/server/sleep-offload.d.ts +11 -5
- package/dist/server/sleep-offload.js +17 -11
- package/dist/server/tls.d.ts +7 -2
- package/dist/server/tls.js +17 -5
- package/dist/server/types.d.ts +29 -12
- package/dist/server/validation.d.ts +1 -2
- package/dist/server/validation.js +6 -11
- package/dist/server.d.ts +4 -40
- package/dist/server.js +3 -29
- package/dist/sharing/global-store.d.ts +4 -5
- package/dist/sharing/global-store.js +8 -13
- package/dist/sharing/global-sync.js +38 -45
- package/dist/sharing/project-merge.d.ts +7 -14
- package/dist/sharing/project-merge.js +57 -121
- package/dist/sharing/search-both.js +10 -3
- package/dist/sharing/share.d.ts +2 -0
- package/dist/sharing/share.js +39 -38
- package/dist/store/ambient.js +7 -7
- package/dist/store/audit-event.d.ts +1 -1
- package/dist/store/audit.d.ts +0 -16
- package/dist/store/audit.js +4 -55
- package/dist/store/auth.d.ts +4 -2
- package/dist/store/auth.js +7 -3
- package/dist/store/candidates.d.ts +3 -2
- package/dist/store/candidates.js +59 -30
- package/dist/store/capture-write.d.ts +17 -0
- package/dist/store/capture-write.js +35 -0
- package/dist/store/cards.js +6 -5
- package/dist/store/compaction-caller.d.ts +18 -0
- package/dist/store/compaction-caller.js +29 -0
- package/dist/store/compactions-record.d.ts +115 -0
- package/dist/store/compactions-record.js +418 -0
- package/dist/store/compactions.js +6 -4
- package/dist/store/conflicts.d.ts +7 -1
- package/dist/store/conflicts.js +13 -9
- package/dist/store/connectors/dlq.d.ts +10 -0
- package/dist/store/connectors/dlq.js +33 -0
- package/dist/store/connectors/event-log.d.ts +13 -0
- package/dist/store/connectors/event-log.js +24 -0
- package/dist/store/connectors/github.d.ts +7 -9
- package/dist/store/connectors/github.js +35 -60
- package/dist/store/connectors/slack.d.ts +2 -11
- package/dist/store/connectors/slack.js +24 -57
- package/dist/store/dashboard-reads.js +8 -6
- package/dist/store/delete-and-batch.d.ts +6 -0
- package/dist/store/delete-and-batch.js +40 -6
- package/dist/store/delivery-recorder.d.ts +12 -5
- package/dist/store/delivery-recorder.js +13 -11
- package/dist/store/descendant-page.js +8 -4
- package/dist/store/dormant.d.ts +1 -1
- package/dist/store/dormant.js +10 -4
- package/dist/store/embeddings/index.d.ts +2 -12
- package/dist/store/embeddings/index.js +5 -374
- package/dist/store/entry-reads.d.ts +35 -4
- package/dist/store/entry-reads.js +86 -19
- package/dist/store/entry-row.js +9 -2
- package/dist/store/entry-writes.d.ts +15 -12
- package/dist/store/entry-writes.js +54 -22
- package/dist/store/failure-log-at.d.ts +8 -0
- package/dist/store/failure-log-at.js +16 -0
- package/dist/store/failure-log.d.ts +2 -2
- package/dist/store/failure-log.js +5 -3
- package/dist/{trust → store}/gated-write.d.ts +3 -1
- package/dist/{trust → store}/gated-write.js +7 -5
- package/dist/store/goals.js +22 -19
- package/dist/store/graph-reads.js +9 -6
- package/dist/store/graph-view-rows.js +2 -1
- package/dist/store/graph-writes.d.ts +6 -6
- package/dist/store/graph-writes.js +48 -71
- package/dist/store/half-life.js +2 -2
- package/dist/store/handoffs.d.ts +10 -4
- package/dist/store/handoffs.js +10 -9
- package/dist/store/index-and-stats.js +2 -2
- package/dist/store/index.d.ts +2 -2
- package/dist/store/index.js +1 -1
- package/dist/store/key-writes.js +1 -1
- package/dist/store/ledger-turn.d.ts +9 -0
- package/dist/store/ledger-turn.js +38 -0
- package/dist/store/mirrors.js +19 -10
- package/dist/store/open.d.ts +2 -5
- package/dist/store/open.js +42 -54
- package/dist/store/pilot-arm.d.ts +12 -0
- package/dist/store/pilot-arm.js +42 -0
- package/dist/store/port.d.ts +68 -6
- package/dist/store/port.js +8 -0
- package/dist/store/predictions.d.ts +1 -2
- package/dist/store/predictions.js +3 -6
- package/dist/store/project-tags.d.ts +62 -0
- package/dist/store/project-tags.js +67 -0
- package/dist/store/quality-repair.js +1 -1
- package/dist/store/quarantine.js +2 -1
- package/dist/store/recall-trace.d.ts +2 -0
- package/dist/store/recall-trace.js +20 -3
- package/dist/store/rejected-values.js +16 -10
- package/dist/store/rejection-probe.d.ts +4 -0
- package/dist/store/rejection-probe.js +19 -0
- package/dist/store/rejection.d.ts +0 -17
- package/dist/store/rejection.js +1 -21
- package/dist/store/rows.js +2 -2
- package/dist/store/rule-sql.d.ts +11 -0
- package/dist/store/rule-sql.js +31 -6
- package/dist/store/search-rows.d.ts +5 -5
- package/dist/store/search-rows.js +18 -16
- package/dist/store/sessions.js +4 -2
- package/dist/store/set-aside.d.ts +14 -0
- package/dist/store/set-aside.js +23 -0
- package/dist/store/sqlite/busy.d.ts +3 -0
- package/dist/store/sqlite/busy.js +8 -0
- package/dist/store/sqlite/connector-events-group.js +4 -7
- package/dist/store/sqlite/connector-writes-group.js +6 -4
- package/dist/store/sqlite/entry-writes-group.d.ts +3 -3
- package/dist/store/sqlite/entry-writes-group.js +3 -3
- package/dist/store/sqlite/error-codec.js +4 -3
- package/dist/store/sqlite/executor.js +10 -4
- package/dist/store/sqlite/graph-reads-group.js +1 -1
- package/dist/store/sqlite/held-connection.d.ts +11 -0
- package/dist/store/sqlite/held-connection.js +41 -0
- package/dist/store/sqlite/last-recall-group.d.ts +13 -0
- package/dist/store/sqlite/last-recall-group.js +57 -0
- package/dist/store/sqlite/local.d.ts +0 -17
- package/dist/store/sqlite/local.js +0 -31
- package/dist/store/sqlite/maintenance-groups.d.ts +6 -0
- package/dist/store/sqlite/maintenance-groups.js +60 -0
- package/dist/store/sqlite/object-rows.d.ts +1 -1
- package/dist/store/sqlite/objects-group.d.ts +1 -1
- package/dist/store/sqlite/objects-group.js +15 -7
- package/dist/store/sqlite/store.d.ts +1 -8
- package/dist/store/sqlite/store.js +13 -22
- package/dist/store/summaries.d.ts +10 -3
- package/dist/store/summaries.js +54 -11
- package/dist/store/token-ledger-rows.js +3 -2
- package/dist/store/token-ledger.d.ts +0 -7
- package/dist/store/token-ledger.js +0 -35
- package/dist/store/vector-index.js +8 -4
- package/dist/support-bundle.js +2 -3
- package/dist/trust/reject-flow.js +2 -2
- package/dist/util/agent-homes.d.ts +15 -0
- package/dist/util/agent-homes.js +34 -0
- package/dist/util/anthropic-messages.d.ts +6 -1
- package/dist/util/anthropic-messages.js +26 -7
- package/dist/util/atomic-write.d.ts +5 -2
- package/dist/util/atomic-write.js +12 -8
- package/dist/util/chunked.d.ts +3 -0
- package/dist/util/chunked.js +10 -0
- package/dist/util/ellipsize.d.ts +3 -0
- package/dist/util/ellipsize.js +5 -0
- package/dist/util/env.d.ts +12 -2
- package/dist/util/env.js +12 -2
- package/dist/util/format.d.ts +5 -0
- package/dist/util/format.js +10 -0
- package/dist/util/hook-payload.d.ts +8 -0
- package/dist/util/hook-payload.js +37 -0
- package/dist/util/http-retry.d.ts +6 -0
- package/dist/util/http-retry.js +43 -5
- package/dist/util/http-util.d.ts +0 -8
- package/dist/util/http-util.js +10 -21
- package/dist/util/limits.d.ts +7 -0
- package/dist/util/limits.js +14 -0
- package/dist/util/log.d.ts +4 -0
- package/dist/util/log.js +9 -0
- package/dist/util/request-scope.d.ts +9 -3
- package/dist/util/request-scope.js +18 -9
- package/dist/util/secret-detect.js +6 -1
- package/dist/util/spawn-argv.d.ts +9 -0
- package/dist/util/spawn-argv.js +57 -0
- package/dist/util/sql.d.ts +3 -0
- package/dist/util/sql.js +6 -0
- package/dist/util/sqlite-blocked.d.ts +2 -0
- package/dist/util/sqlite-blocked.js +5 -0
- package/dist/util/stream-tee.d.ts +3 -0
- package/dist/util/stream-tee.js +35 -0
- package/dist/util/time.d.ts +4 -0
- package/dist/util/time.js +4 -0
- package/dist/util/vector-codec.d.ts +4 -0
- package/dist/util/vector-codec.js +15 -0
- package/dist/util/version.d.ts +1 -1
- package/dist/util/version.js +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 +4 -2
- package/dist/api/on-store.d.ts +0 -16
- package/dist/api/on-store.js +0 -38
- package/dist/store/embeddings/local.d.ts +0 -15
- package/dist/store/embeddings/local.js +0 -175
- /package/dist/{cli → api}/correction-latency.d.ts +0 -0
- /package/dist/{cli → api}/correction-latency.js +0 -0
- /package/dist/{cli → api}/provenance-coverage.d.ts +0 -0
- /package/dist/{cli → api}/provenance-coverage.js +0 -0
- /package/dist/{store → core}/object-types.d.ts +0 -0
- /package/dist/{store → core}/object-types.js +0 -0
- /package/dist/{capture → util}/compaction-items.d.ts +0 -0
- /package/dist/{capture → util}/compaction-items.js +0 -0
- /package/dist/{store → util}/yaml.d.ts +0 -0
- /package/dist/{store → util}/yaml.js +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Summaries post-compact could not record because the store was busy, waiting on disk for the next replay.
|
|
2
|
+
import { MINUTE_MS } from '../util/time.js';
|
|
2
3
|
import { randomBytes } from 'crypto';
|
|
3
4
|
import * as fs from 'fs';
|
|
4
5
|
import * as path from 'path';
|
|
@@ -7,11 +8,12 @@ import { isSqliteBusy } from '../db/busy.js';
|
|
|
7
8
|
import { errorMessage } from '../util/log.js';
|
|
8
9
|
const STAMP_DIGITS = 13;
|
|
9
10
|
export const SPOOL_DIR = 'compactions-spool';
|
|
10
|
-
/** Starts the log line of a step that broke with an unexpected error, so the session-start banner counts it; a set-aside file is counted
|
|
11
|
+
/** Starts the log line of a step that broke with an unexpected error, so the session-start banner counts it; a set-aside file is counted
|
|
12
|
+
* by its `.bad` name instead. */
|
|
11
13
|
export const SPOOL_PROBLEM = 'spool problem: ';
|
|
12
14
|
const LOCK = 'replay.lock';
|
|
13
15
|
/** Long enough that a live replayer has finished with its claim. */
|
|
14
|
-
const STALE_MS = 10 *
|
|
16
|
+
const STALE_MS = 10 * MINUTE_MS;
|
|
15
17
|
const MAX_ATTEMPTS = 3;
|
|
16
18
|
const BUSY_RETRIES = 3;
|
|
17
19
|
const BUSY_WAIT_MS = 50;
|
|
@@ -27,11 +29,6 @@ const BAD = /^([\w-]+)\.(?:\w+\.)?bad$/;
|
|
|
27
29
|
const BAD_TMP = /^[\w-]+\.\w+\.bad\.[0-9a-f]{8}\.tmp$/;
|
|
28
30
|
const NEW_STEM = /^(\d{13})-[0-9a-f]{8}$/;
|
|
29
31
|
const LEGACY_STEM_TIME = /-(\d+)$/;
|
|
30
|
-
let fsx = fs;
|
|
31
|
-
/** Test-only seam, so a test can make one fs call fail; null restores the real fs. */
|
|
32
|
-
export function _setSpoolFsForTests(next) {
|
|
33
|
-
fsx = next ?? fs;
|
|
34
|
-
}
|
|
35
32
|
const stamp = (ms) => String(Math.trunc(ms)).padStart(STAMP_DIGITS, '0');
|
|
36
33
|
const isTime = (value) => typeof value === 'number' && Number.isFinite(value);
|
|
37
34
|
const idle = new Int32Array(new SharedArrayBuffer(4));
|
|
@@ -97,10 +94,19 @@ function claimOf(name) {
|
|
|
97
94
|
function spoolFile(hippoRoot) {
|
|
98
95
|
return path.join(hippoRoot, SPOOL_DIR, `${stamp(Date.now())}-${randomBytes(4).toString('hex')}.a0.json`);
|
|
99
96
|
}
|
|
100
|
-
export function spool(hippoRoot, tenantId, payload, text, at) {
|
|
97
|
+
export function spool(hippoRoot, tenantId, payload, text, at, fsx = fs) {
|
|
101
98
|
const file = spoolFile(hippoRoot);
|
|
102
99
|
fsx.mkdirSync(path.dirname(file), { recursive: true });
|
|
103
|
-
const body = {
|
|
100
|
+
const body = {
|
|
101
|
+
tenantId,
|
|
102
|
+
sessionId: payload.sessionId,
|
|
103
|
+
trigger: payload.trigger,
|
|
104
|
+
cwd: payload.cwd,
|
|
105
|
+
transcriptPath: payload.transcriptPath,
|
|
106
|
+
at: at.toISOString(),
|
|
107
|
+
summary: text.summary,
|
|
108
|
+
items: text.items,
|
|
109
|
+
};
|
|
104
110
|
// Renamed into place so a replayer listing `.json` files never reads half a file.
|
|
105
111
|
fsx.writeFileSync(`${file}.tmp`, JSON.stringify(body), { encoding: 'utf8', flag: 'wx' });
|
|
106
112
|
// A rename that stays busy leaves a whole tmp, which a replay promotes once it is STALE_MS old.
|
|
@@ -149,7 +155,7 @@ function parseLock(text) {
|
|
|
149
155
|
return { pid, at: raw.at, token };
|
|
150
156
|
}
|
|
151
157
|
/** The lock's body; its mtime stands in for the time when the body does not parse. */
|
|
152
|
-
function readLock(lock, log) {
|
|
158
|
+
function readLock(fsx, lock, log) {
|
|
153
159
|
let text = '';
|
|
154
160
|
const read = settle(() => { text = fsx.readFileSync(lock, 'utf8'); }, log, 'spool lock not read');
|
|
155
161
|
if (read !== 'done')
|
|
@@ -161,7 +167,7 @@ function readLock(lock, log) {
|
|
|
161
167
|
const stat = settle(() => { mtime = fsx.statSync(lock).mtimeMs; }, log, 'spool lock not read');
|
|
162
168
|
return stat === 'done' ? { pid: null, at: mtime, token: null } : stat;
|
|
163
169
|
}
|
|
164
|
-
function createLock(lock, body, log) {
|
|
170
|
+
function createLock(fsx, lock, body, log) {
|
|
165
171
|
try {
|
|
166
172
|
fsx.writeFileSync(lock, body, { encoding: 'utf8', flag: 'wx' });
|
|
167
173
|
return 'taken';
|
|
@@ -177,18 +183,18 @@ function createLock(lock, body, log) {
|
|
|
177
183
|
}
|
|
178
184
|
}
|
|
179
185
|
/** This run's token and take time once it holds `replay.lock`, else null: another replayer holds it, or it could not be made. */
|
|
180
|
-
function takeLock(dir, log) {
|
|
186
|
+
function takeLock(fsx, dir, log) {
|
|
181
187
|
const lock = path.join(dir, LOCK);
|
|
182
188
|
const token = randomBytes(8).toString('hex');
|
|
183
189
|
const at = Date.now();
|
|
184
190
|
const body = JSON.stringify({ pid: process.pid, at, token });
|
|
185
191
|
for (let tries = 0; tries < 2; tries++) {
|
|
186
|
-
const made = createLock(lock, body, log);
|
|
192
|
+
const made = createLock(fsx, lock, body, log);
|
|
187
193
|
if (made === 'taken')
|
|
188
194
|
return { token, at };
|
|
189
195
|
if (made === 'skip')
|
|
190
196
|
break;
|
|
191
|
-
const held = readLock(lock, log);
|
|
197
|
+
const held = readLock(fsx, lock, log);
|
|
192
198
|
if (held === 'gone')
|
|
193
199
|
continue;
|
|
194
200
|
if (held === 'busy')
|
|
@@ -205,24 +211,24 @@ function takeLock(dir, log) {
|
|
|
205
211
|
return null;
|
|
206
212
|
}
|
|
207
213
|
/** False, after saying so, once `replay.lock` no longer holds this run's token or cannot be read. */
|
|
208
|
-
function ownsLock(dir, token, log) {
|
|
209
|
-
const held = readLock(path.join(dir, LOCK), log);
|
|
214
|
+
function ownsLock(fsx, dir, token, log) {
|
|
215
|
+
const held = readLock(fsx, path.join(dir, LOCK), log);
|
|
210
216
|
if (held !== 'gone' && held !== 'busy' && held.token === token)
|
|
211
217
|
return true;
|
|
212
218
|
log(held === 'busy' ? 'spool lock could not be read, stopping' : 'spool left to another replayer (lock taken over)');
|
|
213
219
|
return false;
|
|
214
220
|
}
|
|
215
221
|
/** Removes `replay.lock` only while it holds this run's token, so a run never deletes a successor's lock. Never throws. */
|
|
216
|
-
function releaseLock(dir, mine, log) {
|
|
222
|
+
function releaseLock(fsx, dir, mine, log) {
|
|
217
223
|
const lock = path.join(dir, LOCK);
|
|
218
|
-
const held = readLock(lock, log);
|
|
224
|
+
const held = readLock(fsx, lock, log);
|
|
219
225
|
// A takeover needs a lock over STALE_MS old, so a busy read of one this run took more recently is still this run's.
|
|
220
226
|
const ours = held === 'busy' ? Date.now() - mine.at < STALE_MS : held !== 'gone' && held.token === mine.token;
|
|
221
227
|
if (ours)
|
|
222
228
|
settle(() => fsx.unlinkSync(lock), log, 'spool lock not released');
|
|
223
229
|
}
|
|
224
230
|
/** Claim time sits in the claim's name, so a claim over STALE_MS away from now belongs to a replayer that never finished. True when one was put back. */
|
|
225
|
-
function recoverStaleClaims(dir, names, log) {
|
|
231
|
+
function recoverStaleClaims(fsx, dir, names, log) {
|
|
226
232
|
const now = Date.now();
|
|
227
233
|
// A claim whose unlink stayed busy after its `.bad` landed is a spare copy, not a second failure.
|
|
228
234
|
const setAside = new Set(names.flatMap((name) => BAD.exec(name)?.[1] ?? []));
|
|
@@ -245,21 +251,21 @@ function recoverStaleClaims(dir, names, log) {
|
|
|
245
251
|
putBackOne = true;
|
|
246
252
|
}
|
|
247
253
|
}
|
|
248
|
-
else if (moveBad(dir, file, { stem: claim.stem, attempt: claim.attempt, cause: 'interrupted', log })) {
|
|
254
|
+
else if (moveBad(fsx, dir, file, { stem: claim.stem, attempt: claim.attempt, cause: 'interrupted', log })) {
|
|
249
255
|
log(`spool file ${claim.name} was claimed by a replayer that never finished ${MAX_ATTEMPTS} times, set aside as .bad`);
|
|
250
256
|
}
|
|
251
257
|
}
|
|
252
258
|
return putBackOne;
|
|
253
259
|
}
|
|
254
260
|
/** Returns a claim to the waiting files as `<stem>.a<attempt>.json`; one that stays busy is left for stale recovery. */
|
|
255
|
-
function putBack(dir, claim, stem, attempt, log) {
|
|
261
|
+
function putBack(fsx, dir, claim, stem, attempt, log) {
|
|
256
262
|
const name = path.basename(claim);
|
|
257
263
|
if (settle(() => fsx.renameSync(claim, path.join(dir, `${stem}.a${attempt}.json`)), log, `spool file ${name} not put back`) === 'busy') {
|
|
258
|
-
log(`spool file ${name} could not be put back; it returns ${STALE_MS /
|
|
264
|
+
log(`spool file ${name} could not be put back; it returns ${STALE_MS / MINUTE_MS} minutes after its claim`);
|
|
259
265
|
}
|
|
260
266
|
}
|
|
261
267
|
/** Writes `<stem>.<cause>.bad` through a random temp file, so the rename replaces any torn `.bad` a crash left. */
|
|
262
|
-
function writeBad(dir, options) {
|
|
268
|
+
function writeBad(fsx, dir, options) {
|
|
263
269
|
const { stem, cause, text, log, what } = options;
|
|
264
270
|
const tmp = path.join(dir, `${stem}.${cause}.bad.${randomBytes(4).toString('hex')}.tmp`);
|
|
265
271
|
const written = settle(() => fsx.writeFileSync(tmp, text, { encoding: 'utf8', flag: 'wx' }), log, what);
|
|
@@ -269,21 +275,21 @@ function writeBad(dir, options) {
|
|
|
269
275
|
return moved === 'done';
|
|
270
276
|
}
|
|
271
277
|
/** Sets a claim aside as `.bad` before the claim goes, so a crash between leaves a whole copy; a busy write puts the claim back. */
|
|
272
|
-
function moveBad(dir, claim, options) {
|
|
278
|
+
function moveBad(fsx, dir, claim, options) {
|
|
273
279
|
const { stem, attempt, cause, log, raw } = options;
|
|
274
280
|
const what = `spool file ${path.basename(claim)} not set aside`;
|
|
275
281
|
let text = raw ?? '';
|
|
276
282
|
if (raw === undefined && settle(() => { text = fsx.readFileSync(claim, 'utf8'); }, log, what) !== 'done')
|
|
277
283
|
return false;
|
|
278
|
-
if (!writeBad(dir, { stem, cause, text, log, what })) {
|
|
279
|
-
putBack(dir, claim, stem, attempt, log);
|
|
284
|
+
if (!writeBad(fsx, dir, { stem, cause, text, log, what })) {
|
|
285
|
+
putBack(fsx, dir, claim, stem, attempt, log);
|
|
280
286
|
return false;
|
|
281
287
|
}
|
|
282
288
|
settle(() => fsx.unlinkSync(claim), log, what);
|
|
283
289
|
return true;
|
|
284
290
|
}
|
|
285
291
|
/** A tmp over STALE_MS old belongs to a spool that never renamed it: a whole one joins the waiting files, a torn one is set aside. True when one joined. */
|
|
286
|
-
function promoteTmp(dir, names, tenantId, log) {
|
|
292
|
+
function promoteTmp(fsx, dir, names, tenantId, log) {
|
|
287
293
|
const now = Date.now();
|
|
288
294
|
let promoted = false;
|
|
289
295
|
for (const name of names) {
|
|
@@ -309,7 +315,7 @@ function promoteTmp(dir, names, tenantId, log) {
|
|
|
309
315
|
promoted = true;
|
|
310
316
|
}
|
|
311
317
|
}
|
|
312
|
-
else if (writeBad(dir, { stem: m[1], cause: 'unreadable', text, log, what })) {
|
|
318
|
+
else if (writeBad(fsx, dir, { stem: m[1], cause: 'unreadable', text, log, what })) {
|
|
313
319
|
settle(() => fsx.unlinkSync(file), log, what);
|
|
314
320
|
log(`spool file ${name} was never finished, set aside as .bad`);
|
|
315
321
|
}
|
|
@@ -317,38 +323,40 @@ function promoteTmp(dir, names, tenantId, log) {
|
|
|
317
323
|
return promoted;
|
|
318
324
|
}
|
|
319
325
|
/** Removes a claim once the store holds its summary; a claim left behind is imported again, so the log says so. */
|
|
320
|
-
function removeClaim(claim, name, log) {
|
|
326
|
+
function removeClaim(fsx, claim, name, log) {
|
|
321
327
|
const removed = settleCode(() => fsx.unlinkSync(claim), log, `spool file ${name} claim not removed`);
|
|
322
328
|
if (removed.settled === 'busy')
|
|
323
329
|
log(`spool file ${name} saved; its claim could not be removed (${removed.code}); it will be imported again`);
|
|
324
330
|
}
|
|
325
331
|
/** After an importer throw: a busy store stops the run with the count unchanged, any other error counts one try toward .bad. */
|
|
326
|
-
function importFailed(dir, claim, entry, options) {
|
|
332
|
+
function importFailed(fsx, dir, claim, entry, options) {
|
|
327
333
|
const { text, recorded, cause, log } = options;
|
|
328
334
|
const { name } = entry;
|
|
329
335
|
const busy = isSqliteBusy(cause);
|
|
330
336
|
if (recorded) {
|
|
331
337
|
// The record stays `summarised`, so the stalled-record step of a later replay writes its items.
|
|
332
|
-
log(busy
|
|
338
|
+
log(busy
|
|
339
|
+
? `spool file ${name} saved; its memories wait for the next sleep (store busy)`
|
|
340
|
+
: `spool file ${name} saved; writing its memories failed: ${errorMessage(cause)}`);
|
|
333
341
|
return busy ? 'stop' : 'skipped';
|
|
334
342
|
}
|
|
335
343
|
if (busy) {
|
|
336
|
-
putBack(dir, claim, entry.stem, entry.attempt, log);
|
|
344
|
+
putBack(fsx, dir, claim, entry.stem, entry.attempt, log);
|
|
337
345
|
log(`spool file ${name} waits for the next run: the store is busy`);
|
|
338
346
|
return 'stop';
|
|
339
347
|
}
|
|
340
348
|
const next = entry.attempt + 1;
|
|
341
349
|
if (next < MAX_ATTEMPTS) {
|
|
342
|
-
putBack(dir, claim, entry.stem, next, log);
|
|
350
|
+
putBack(fsx, dir, claim, entry.stem, next, log);
|
|
343
351
|
log(`spool file ${name} failed to import (try ${next} of ${MAX_ATTEMPTS}): ${errorMessage(cause)}`);
|
|
344
352
|
}
|
|
345
|
-
else if (moveBad(dir, claim, { stem: entry.stem, attempt: entry.attempt, cause: 'failed', log, raw: text })) {
|
|
353
|
+
else if (moveBad(fsx, dir, claim, { stem: entry.stem, attempt: entry.attempt, cause: 'failed', log, raw: text })) {
|
|
346
354
|
log(`spool file ${name} set aside as .bad after ${MAX_ATTEMPTS} tries: ${errorMessage(cause)}`);
|
|
347
355
|
}
|
|
348
356
|
return 'skipped';
|
|
349
357
|
}
|
|
350
358
|
/** Claims, reads and imports one waiting file; `stop` ends the run because the store is busy. */
|
|
351
|
-
function importFile(dir, entry, tenantId, log, importOne) {
|
|
359
|
+
function importFile(fsx, dir, entry, tenantId, log, importOne) {
|
|
352
360
|
const { name } = entry;
|
|
353
361
|
const claim = path.join(dir, `${entry.stem}.a${entry.attempt}.claim-${stamp(Date.now())}`);
|
|
354
362
|
const taken = settleCode(() => fsx.renameSync(path.join(dir, name), claim), log, `spool file ${name} not claimed`);
|
|
@@ -361,13 +369,14 @@ function importFile(dir, entry, tenantId, log, importOne) {
|
|
|
361
369
|
if (read === 'gone')
|
|
362
370
|
log(`spool file ${name} vanished`);
|
|
363
371
|
if (read === 'busy')
|
|
364
|
-
putBack(dir, claim, entry.stem, entry.attempt, log);
|
|
372
|
+
putBack(fsx, dir, claim, entry.stem, entry.attempt, log);
|
|
365
373
|
if (read !== 'done')
|
|
366
374
|
return 'skipped';
|
|
367
375
|
const spooled = parseSpooled(text, tenantId);
|
|
368
376
|
if (spooled === null) {
|
|
369
|
-
if (moveBad(dir, claim, { stem: entry.stem, attempt: entry.attempt, cause: 'unreadable', log, raw: text }))
|
|
377
|
+
if (moveBad(fsx, dir, claim, { stem: entry.stem, attempt: entry.attempt, cause: 'unreadable', log, raw: text })) {
|
|
370
378
|
log(`spool file ${name} is not readable, set aside as .bad`);
|
|
379
|
+
}
|
|
371
380
|
return 'skipped';
|
|
372
381
|
}
|
|
373
382
|
let recorded = false;
|
|
@@ -375,7 +384,7 @@ function importFile(dir, entry, tenantId, log, importOne) {
|
|
|
375
384
|
if (recorded)
|
|
376
385
|
return;
|
|
377
386
|
recorded = true;
|
|
378
|
-
removeClaim(claim, name, log);
|
|
387
|
+
removeClaim(fsx, claim, name, log);
|
|
379
388
|
};
|
|
380
389
|
try {
|
|
381
390
|
importOne(spooled, markRecorded);
|
|
@@ -383,10 +392,10 @@ function importFile(dir, entry, tenantId, log, importOne) {
|
|
|
383
392
|
return 'imported';
|
|
384
393
|
}
|
|
385
394
|
catch (err) {
|
|
386
|
-
return importFailed(dir, claim, entry, { text, recorded, cause: err, log });
|
|
395
|
+
return importFailed(fsx, dir, claim, entry, { text, recorded, cause: err, log });
|
|
387
396
|
}
|
|
388
397
|
}
|
|
389
|
-
function mtimeOf(file) {
|
|
398
|
+
function mtimeOf(fsx, file) {
|
|
390
399
|
try {
|
|
391
400
|
return fsx.statSync(file).mtimeMs;
|
|
392
401
|
}
|
|
@@ -399,7 +408,7 @@ function mtimeOf(file) {
|
|
|
399
408
|
}
|
|
400
409
|
}
|
|
401
410
|
/** What doctor reports, read only: files a replay should have taken by now, claims and tmp files a dead process left, and `.bad` files. */
|
|
402
|
-
export function spoolCounts(hippoRoot, now, waitingAfterMs) {
|
|
411
|
+
export function spoolCounts(hippoRoot, now, waitingAfterMs, fsx = fs) {
|
|
403
412
|
const counts = { waiting: 0, stale: 0, bad: 0 };
|
|
404
413
|
const dir = path.join(hippoRoot, SPOOL_DIR);
|
|
405
414
|
if (!fsx.existsSync(dir))
|
|
@@ -412,12 +421,12 @@ export function spoolCounts(hippoRoot, now, waitingAfterMs) {
|
|
|
412
421
|
if (name.endsWith('.bad'))
|
|
413
422
|
counts.bad++;
|
|
414
423
|
else if (waiting !== null) {
|
|
415
|
-
const spooled = NEW_STEM.test(waiting[1]) ? created(waiting[1]) : mtimeOf(file);
|
|
424
|
+
const spooled = NEW_STEM.test(waiting[1]) ? created(waiting[1]) : mtimeOf(fsx, file);
|
|
416
425
|
if (spooled !== null && at - spooled > waitingAfterMs)
|
|
417
426
|
counts.waiting++;
|
|
418
427
|
}
|
|
419
428
|
else if (claim !== null || TMP.test(name)) {
|
|
420
|
-
const since = claim?.claimedAt ?? mtimeOf(file);
|
|
429
|
+
const since = claim?.claimedAt ?? mtimeOf(fsx, file);
|
|
421
430
|
if (since !== null && Math.abs(at - since) > STALE_MS)
|
|
422
431
|
counts.stale++;
|
|
423
432
|
}
|
|
@@ -425,25 +434,25 @@ export function spoolCounts(hippoRoot, now, waitingAfterMs) {
|
|
|
425
434
|
return counts;
|
|
426
435
|
}
|
|
427
436
|
/** One replayer at a time holds `replay.lock`, so only one process claims a file even where Windows lets two renames of it both land. */
|
|
428
|
-
export function importSpool(hippoRoot, tenantId, log, deadline, importOne) {
|
|
437
|
+
export function importSpool(hippoRoot, tenantId, log, deadline, importOne, fsx = fs) {
|
|
429
438
|
const dir = path.join(hippoRoot, SPOOL_DIR);
|
|
430
439
|
if (!fsx.existsSync(dir))
|
|
431
440
|
return 0;
|
|
432
|
-
const mine = takeLock(dir, log);
|
|
441
|
+
const mine = takeLock(fsx, dir, log);
|
|
433
442
|
if (mine === null)
|
|
434
443
|
return 0;
|
|
435
444
|
try {
|
|
436
|
-
if (!ownsLock(dir, mine.token, log))
|
|
445
|
+
if (!ownsLock(fsx, dir, mine.token, log))
|
|
437
446
|
return 0;
|
|
438
447
|
const names = fsx.readdirSync(dir);
|
|
439
|
-
const promoted = promoteTmp(dir, names, tenantId, log);
|
|
440
|
-
const recovered = recoverStaleClaims(dir, names, log);
|
|
448
|
+
const promoted = promoteTmp(fsx, dir, names, tenantId, log);
|
|
449
|
+
const recovered = recoverStaleClaims(fsx, dir, names, log);
|
|
441
450
|
let finished = 0;
|
|
442
451
|
// Only promotion and recovery add waiting names, so the folder is listed again only after one of them did.
|
|
443
452
|
for (const entry of waitingFiles(promoted || recovered ? fsx.readdirSync(dir) : names)) {
|
|
444
|
-
if (Date.now() > deadline || !ownsLock(dir, mine.token, log))
|
|
453
|
+
if (Date.now() > deadline || !ownsLock(fsx, dir, mine.token, log))
|
|
445
454
|
break;
|
|
446
|
-
const outcome = importFile(dir, entry, tenantId, log, importOne);
|
|
455
|
+
const outcome = importFile(fsx, dir, entry, tenantId, log, importOne);
|
|
447
456
|
if (outcome === 'imported')
|
|
448
457
|
finished++;
|
|
449
458
|
if (outcome === 'stop')
|
|
@@ -452,7 +461,7 @@ export function importSpool(hippoRoot, tenantId, log, deadline, importOne) {
|
|
|
452
461
|
return finished;
|
|
453
462
|
}
|
|
454
463
|
finally {
|
|
455
|
-
releaseLock(dir, mine, log);
|
|
464
|
+
releaseLock(fsx, dir, mine, log);
|
|
456
465
|
}
|
|
457
466
|
}
|
|
458
467
|
//# sourceMappingURL=compaction-spool.js.map
|
|
@@ -13,6 +13,7 @@ export declare const SESSION_ID_RE: RegExp;
|
|
|
13
13
|
export declare function copilotTranscriptFor(sessionId: string): string | null;
|
|
14
14
|
/** True for VS Code's own chat log, `<workspaceStorage>/<id>/github.copilot-chat/transcripts/<session id>.jsonl`, in either slash and any case. */
|
|
15
15
|
export declare function isVscodeTranscript(file: string | null): boolean;
|
|
16
|
-
/** The turn one Copilot event-log line carries: the text of a human user.message or of an assistant.message; null for any other line, a
|
|
16
|
+
/** The turn one Copilot event-log line carries: the text of a human user.message or of an assistant.message; null for any other line, a
|
|
17
|
+
* sub-agent's included. */
|
|
17
18
|
export declare function copilotTurn(line: CopilotEventLine): CopilotTurn | null;
|
|
18
19
|
//# sourceMappingURL=copilot-transcript.d.ts.map
|
|
@@ -33,7 +33,8 @@ function isInjectedUserMessage(data) {
|
|
|
33
33
|
const source = data.source;
|
|
34
34
|
return isStringValue(source) && INJECTED_SOURCE_PREFIXES.some((prefix) => source.startsWith(prefix));
|
|
35
35
|
}
|
|
36
|
-
/** The turn one Copilot event-log line carries: the text of a human user.message or of an assistant.message; null for any other line, a
|
|
36
|
+
/** The turn one Copilot event-log line carries: the text of a human user.message or of an assistant.message; null for any other line, a
|
|
37
|
+
* sub-agent's included. */
|
|
37
38
|
export function copilotTurn(line) {
|
|
38
39
|
const role = line.type === 'user.message' ? 'user' : line.type === 'assistant.message' ? 'assistant' : null;
|
|
39
40
|
const data = isObjectLike(line.data) ? line.data : null;
|
|
@@ -2,8 +2,11 @@ export interface ExtractedItem {
|
|
|
2
2
|
content: string;
|
|
3
3
|
category: string;
|
|
4
4
|
tags: string[];
|
|
5
|
+
/** A person said it, not the agent: capture pins a rule that carries this. */
|
|
6
|
+
fromUser?: boolean;
|
|
5
7
|
}
|
|
6
|
-
/** Captures complete supported statements, each text parsed alone so a fence or heading in one never reaches the next.
|
|
7
|
-
|
|
8
|
+
/** Captures complete supported statements, each text parsed alone so a fence or heading in one never reaches the next.
|
|
9
|
+
* The first `userTexts` texts are a person's own words; on a repeat their copy wins, so it keeps `fromUser`. */
|
|
10
|
+
export declare function extractFromTexts(texts: readonly string[], userTexts?: number): ExtractedItem[];
|
|
8
11
|
export declare function extractFromText(text: string): ExtractedItem[];
|
|
9
12
|
//# sourceMappingURL=extract.d.ts.map
|
package/dist/capture/extract.js
CHANGED
|
@@ -158,10 +158,11 @@ function extractOne(text) {
|
|
|
158
158
|
}
|
|
159
159
|
return items;
|
|
160
160
|
}
|
|
161
|
-
/** Captures complete supported statements, each text parsed alone so a fence or heading in one never reaches the next.
|
|
162
|
-
|
|
161
|
+
/** Captures complete supported statements, each text parsed alone so a fence or heading in one never reaches the next.
|
|
162
|
+
* The first `userTexts` texts are a person's own words; on a repeat their copy wins, so it keeps `fromUser`. */
|
|
163
|
+
export function extractFromTexts(texts, userTexts = 0) {
|
|
163
164
|
const seen = new Set();
|
|
164
|
-
return texts.flatMap(extractOne).filter((item) => {
|
|
165
|
+
return texts.flatMap((text, i) => extractOne(text).map((item) => (i < userTexts ? { ...item, fromUser: true } : item))).filter((item) => {
|
|
165
166
|
const key = duplicateKey(item.content);
|
|
166
167
|
if (seen.has(key) || !assessAutomaticMemory(item.content).accepted)
|
|
167
168
|
return false;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Context } from '../api/types.js';
|
|
2
|
-
import {
|
|
2
|
+
import type { CaptureErrorOutcome, RoutineRule } from '../store/failure-log.js';
|
|
3
3
|
import type { CallerProject } from '../api/prompt-hook.js';
|
|
4
4
|
type FailureSkip = Exclude<CaptureErrorOutcome, 'stored' | 'duplicate'>;
|
|
5
5
|
/** failureReport's reading of the payload, read on the caller's machine, plus the id its retries carry. */
|
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
// PostToolUseFailure for a caller on another machine: the lesson and its log row carry the caller's owner and project, and a retried
|
|
1
|
+
// PostToolUseFailure for a caller on another machine: the lesson and its log row carry the caller's owner and project, and a retried
|
|
2
|
+
// request id gets the first answer.
|
|
2
3
|
import { BadRequestError } from '../core/api-errors.js';
|
|
3
4
|
import { storeLesson } from './capture-error.js';
|
|
4
|
-
import {
|
|
5
|
+
import { recordFailureAt, requestOutcomeAt, settleFailureOutcomeAt } from '../store/failure-log-at.js';
|
|
5
6
|
import { errorMessage, log } from '../util/log.js';
|
|
6
7
|
import { scrubForSharing } from './share-scrub.js';
|
|
7
8
|
import { truncateCodePointSafe } from '../util/transcript-tail.js';
|
|
8
|
-
import { assertRequestId, bindCaller
|
|
9
|
+
import { assertRequestId, bindCaller } from './caller-session.js';
|
|
9
10
|
import { FAILURE_TEXT_MAX_CHARS, failureHash } from './failure-reading.js';
|
|
10
11
|
const SKIPS = { 'skipped-interrupt': true, 'skipped-routine': true, 'skipped-invalid': true };
|
|
11
|
-
const ROUTINE_RULES = {
|
|
12
|
+
const ROUTINE_RULES = {
|
|
13
|
+
declined: true,
|
|
14
|
+
'os-permission': true,
|
|
15
|
+
'no-match': true,
|
|
16
|
+
'search-tool': true,
|
|
17
|
+
'quiet-exit': true,
|
|
18
|
+
};
|
|
12
19
|
/** The shapes lessonFromFailure gives: text for a lesson or a routine skip, none for an interrupt or an unreadable payload, a rule only on a routine skip. */
|
|
13
20
|
function checkedFailure(req) {
|
|
14
21
|
assertRequestId(req.requestId);
|
|
@@ -35,7 +42,7 @@ function checkedFailure(req) {
|
|
|
35
42
|
export function captureFailureForCaller(ctx, req) {
|
|
36
43
|
const failure = checkedFailure(req);
|
|
37
44
|
const key = bindCaller(ctx, req.sessionId, req.project);
|
|
38
|
-
const earlier =
|
|
45
|
+
const earlier = requestOutcomeAt(ctx.hippoRoot, ctx.tenantId, req.requestId, req.sessionId);
|
|
39
46
|
// A retry after a lost reply gets the first answer and writes nothing; one whose store failed tries the store again.
|
|
40
47
|
if (earlier !== null && earlier !== 'store-failed')
|
|
41
48
|
return { outcome: earlier };
|
|
@@ -54,17 +61,15 @@ export function captureFailureForCaller(ctx, req) {
|
|
|
54
61
|
/** Runs after the outcome in its own try, so a log error never hides the store's error or its outcome. */
|
|
55
62
|
function logOutcome(ctx, req, key, outcome, retried) {
|
|
56
63
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
ownerSubject: key.owner, originProject: req.project.name, requestId: req.requestId,
|
|
67
|
-
});
|
|
64
|
+
// The request id allows one row, so a retry rewrites the first try's outcome.
|
|
65
|
+
if (retried) {
|
|
66
|
+
settleFailureOutcomeAt(ctx.hippoRoot, ctx.tenantId, req.requestId, outcome);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
recordFailureAt(ctx.hippoRoot, {
|
|
70
|
+
tenantId: ctx.tenantId, sessionId: req.sessionId, tool: req.tool, outcome, rule: req.rule,
|
|
71
|
+
sigHash: req.text?.trim() ? failureHash(req.text) : null, detailHash: req.detailHash,
|
|
72
|
+
ownerSubject: key.owner, originProject: req.project.name, requestId: req.requestId,
|
|
68
73
|
});
|
|
69
74
|
}
|
|
70
75
|
catch (err) {
|
|
@@ -22,7 +22,8 @@ export declare function payloadString(payload: JsonValue, key: 'session_id' | 't
|
|
|
22
22
|
export declare function failureSignature(text: string): string;
|
|
23
23
|
/** The hash the failure log stores for a lesson text or a detail; one function so every writer counts repeats alike. */
|
|
24
24
|
export declare function failureHash(text: string): string;
|
|
25
|
-
/** The memory text for a failure payload, or why it is not stored; a routine skip keeps its text for the log. `scrub` runs before the
|
|
25
|
+
/** The memory text for a failure payload, or why it is not stored; a routine skip keeps its text for the log. `scrub` runs before the
|
|
26
|
+
* cap, as a mask can be longer than what it hides. Pure. */
|
|
26
27
|
export declare function lessonFromFailure(payload: JsonValue, scrub?: (text: string) => string): FailureReading;
|
|
27
28
|
/** A failure as it may leave the machine: the capped lesson text and the detail's hash, never the untruncated detail. */
|
|
28
29
|
export interface FailureReport {
|
|
@@ -3,7 +3,7 @@ import { redactSecretsStrict } from '../util/secret-detect.js';
|
|
|
3
3
|
import { scrubForSharing } from './share-scrub.js';
|
|
4
4
|
import { blockHash } from '../util/token-text.js';
|
|
5
5
|
import { truncateCodePointSafe } from '../util/transcript-tail.js';
|
|
6
|
-
import { isJsonObjectLiteral } from '../util/json.js';
|
|
6
|
+
import { isJsonObjectLiteral, isJsonString } from '../util/json.js';
|
|
7
7
|
const COMMAND_HEAD_WORDS = 2;
|
|
8
8
|
/** The longest lesson text a reading gives, so a check of a sent one imports it instead of copying it. */
|
|
9
9
|
export const FAILURE_TEXT_MAX_CHARS = 200;
|
|
@@ -19,15 +19,12 @@ const QUIET_EXIT_1 = /^\s*(?:grep|rg|egrep|fgrep|find|test|\[|diff|cmp|git diff|
|
|
|
19
19
|
// Claude Code's tool names, then the Copilot CLI's and VS Code's; tests/copilot-failure-reading.test.ts cites where each comes from.
|
|
20
20
|
const SEARCH_TOOLS = new Set(['Grep', 'Glob', 'grep', 'glob', 'rg', 'grep_search', 'file_search', 'semantic_search']);
|
|
21
21
|
const SHELL_TOOLS = new Set(['Bash', 'bash', 'powershell', 'run_in_terminal']);
|
|
22
|
-
function isString(v) {
|
|
23
|
-
return v !== undefined && v !== null && v.constructor === String;
|
|
24
|
-
}
|
|
25
22
|
/** A non-blank string field of the payload, or null. */
|
|
26
23
|
export function payloadString(payload, key) {
|
|
27
24
|
if (!isJsonObjectLiteral(payload))
|
|
28
25
|
return null;
|
|
29
26
|
const value = payload[key];
|
|
30
|
-
return
|
|
27
|
+
return isJsonString(value) && value.trim() !== '' ? value : null;
|
|
31
28
|
}
|
|
32
29
|
/** Normalised form used to spot repeats. The failure log keeps only its hash, so changing it breaks repeat counts. */
|
|
33
30
|
export function failureSignature(text) {
|
|
@@ -37,7 +34,8 @@ export function failureSignature(text) {
|
|
|
37
34
|
export function failureHash(text) {
|
|
38
35
|
return blockHash(failureSignature(text));
|
|
39
36
|
}
|
|
40
|
-
/** The memory text for a failure payload, or why it is not stored; a routine skip keeps its text for the log. `scrub` runs before the
|
|
37
|
+
/** The memory text for a failure payload, or why it is not stored; a routine skip keeps its text for the log. `scrub` runs before the
|
|
38
|
+
* cap, as a mask can be longer than what it hides. Pure. */
|
|
41
39
|
export function lessonFromFailure(payload, scrub = (text) => text) {
|
|
42
40
|
if (!isJsonObjectLiteral(payload))
|
|
43
41
|
return { skip: 'skipped-invalid', text: null, detail: null };
|
|
@@ -45,12 +43,12 @@ export function lessonFromFailure(payload, scrub = (text) => text) {
|
|
|
45
43
|
const p = payload;
|
|
46
44
|
if (p.is_interrupt === true)
|
|
47
45
|
return { skip: 'skipped-interrupt', text: null, detail: null };
|
|
48
|
-
if (!
|
|
46
|
+
if (!isJsonString(p.error) || p.error.trim().length < 12)
|
|
49
47
|
return { skip: 'skipped-invalid', text: null, detail: null };
|
|
50
|
-
const tool =
|
|
48
|
+
const tool = isJsonString(p.tool_name) ? p.tool_name : 'tool';
|
|
51
49
|
const error = redactSecretsStrict(p.error.replace(/\s+/g, ' ').trim());
|
|
52
50
|
const text = truncateCodePointSafe(scrub(`${tool}: ${error}`), FAILURE_TEXT_MAX_CHARS);
|
|
53
|
-
const command = isJsonObjectLiteral(p.tool_input) &&
|
|
51
|
+
const command = isJsonObjectLiteral(p.tool_input) && isJsonString(p.tool_input['command']) ? p.tool_input['command'].replace(LEADING_CD, '') : '';
|
|
54
52
|
const head = command.trim().split(/\s+/).slice(0, COMMAND_HEAD_WORDS).join(' ');
|
|
55
53
|
const detail = `${tool}${head ? ` ${head}` : ''}: ${error}`;
|
|
56
54
|
const routine = (rule) => ({ skip: 'skipped-routine', rule, text, detail });
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PRE_COMPACT_INSTRUCTION } from './compaction-record.js';
|
|
2
|
+
import { markSnapshotSavedAt, startCompactionAt } from '../store/compaction-caller.js';
|
|
2
3
|
import { errorMessage, log } from '../util/log.js';
|
|
3
4
|
import { loadActiveTaskSnapshot, saveActiveTaskSnapshot } from '../store/sessions.js';
|
|
4
|
-
import { assertTrigger, bindCaller, callerInHoldout, checkedWorkingState
|
|
5
|
+
import { assertTrigger, bindCaller, callerInHoldout, checkedWorkingState } from './caller-session.js';
|
|
5
6
|
import { mergeWorkingState } from './working-state.js';
|
|
6
7
|
/** A failed step is logged and the instruction still goes out, as the local hook prints it before any store work. */
|
|
7
8
|
function logged(what, fn) {
|
|
@@ -20,10 +21,10 @@ export function preCompactForCaller(ctx, req) {
|
|
|
20
21
|
if (callerInHoldout(ctx, req.sessionId))
|
|
21
22
|
return { stdout: '' };
|
|
22
23
|
const start = { sessionId: req.sessionId, originProject: req.project.name, trigger: req.trigger, cwd: null, transcriptPath: null };
|
|
23
|
-
const recordId = logged('compaction record not started', () =>
|
|
24
|
+
const recordId = logged('compaction record not started', () => startCompactionAt(ctx.hippoRoot, ctx.tenantId, start));
|
|
24
25
|
if (state !== null && saveOwnerSnapshot(ctx, req.sessionId, key, state) && recordId !== null) {
|
|
25
26
|
// Marked under ctx.tenantId, which the environment's tenant may not be.
|
|
26
|
-
logged('compaction record not marked with its snapshot', () =>
|
|
27
|
+
logged('compaction record not marked with its snapshot', () => markSnapshotSavedAt(ctx.hippoRoot, ctx.tenantId, recordId));
|
|
27
28
|
}
|
|
28
29
|
return { stdout: PRE_COMPACT_INSTRUCTION };
|
|
29
30
|
}
|
|
@@ -10,9 +10,9 @@ import { USER_SEGMENT } from '../util/home-path.js';
|
|
|
10
10
|
import { errorMessage } from '../util/log.js';
|
|
11
11
|
import { SESSION_DIGEST_TAG } from '../core/session-digest-row.js';
|
|
12
12
|
import { createMemory, Layer } from '../core/memory.js';
|
|
13
|
-
import { RejectedValueError } from '../
|
|
13
|
+
import { RejectedValueError } from '../core/api-errors.js';
|
|
14
14
|
import { maskEmails, redactSecretsStrict } from '../util/secret-detect.js';
|
|
15
|
-
import { isInitialized } from '../
|
|
15
|
+
import { isInitialized } from '../core/project-identity.js';
|
|
16
16
|
import { writeEntry } from '../store/entry-writes.js';
|
|
17
17
|
import { loadLiveContentsBySourceAndTag } from '../store/entry-reads.js';
|
|
18
18
|
import { SNAPSHOT_AMBIENT_MAX_AGE_MS } from '../store/sessions.js';
|
|
@@ -336,7 +336,8 @@ const ANCHORS = [
|
|
|
336
336
|
/(?:^|\s)#\d+\b/,
|
|
337
337
|
];
|
|
338
338
|
/** Each marker states a cause or a choice, the part of a lesson that transfers. */
|
|
339
|
-
const MARKERS =
|
|
339
|
+
const MARKERS = new RegExp('\\b(?:because|caused by|due to|root cause|the (?:bug|issue|problem) was|fail(?:s|ed) when|so that|otherwise|' +
|
|
340
|
+
'instead of|rather than|switched to|decided|chose|must|never|always|do not)\\b', 'i');
|
|
340
341
|
const FENCE = /^\s*(`{3,}|~{3,})/;
|
|
341
342
|
const STRUCTURE_LINE = /^\s*(?:#{1,6}\s|\||>|([-*_])(?:\s*\1){2,}\s*$)/;
|
|
342
343
|
const PROTECTED = /`[^`\n]+`|\b(?:e\.g|i\.e)\./gi;
|
|
@@ -11,7 +11,8 @@ function checkedEvidence(evidence) {
|
|
|
11
11
|
const { gitRef = null, dirtyTree = null, testStatus = null } = evidence;
|
|
12
12
|
// `git rev-parse HEAD` gives 40 hex, or 64 in a SHA-256 repository.
|
|
13
13
|
if (gitRef !== null && !/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(gitRef))
|
|
14
|
-
throw new BadRequestError('evidence gitRef: 40 or 64 lowercase hex characters or
|
|
14
|
+
throw new BadRequestError('evidence gitRef: 40 or 64 lowercase hex characters or ' +
|
|
15
|
+
'null');
|
|
15
16
|
if (dirtyTree !== null && dirtyTree !== true && dirtyTree !== false)
|
|
16
17
|
throw new BadRequestError('evidence dirtyTree: true, false or null');
|
|
17
18
|
if (testStatus !== null && !TEST_STATUSES.has(testStatus))
|
|
@@ -23,7 +24,7 @@ export function sessionEndHandoffForCaller(ctx, req) {
|
|
|
23
24
|
const state = checkedWorkingState(req.workingState);
|
|
24
25
|
const evidence = checkedEvidence(req.evidence);
|
|
25
26
|
const key = bindCaller(ctx, req.sessionId, req.project);
|
|
26
|
-
const handoff = writeSessionEndHandoff(ctx.hippoRoot, ctx.tenantId, req.sessionId, evidence, state, key);
|
|
27
|
+
const handoff = writeSessionEndHandoff(ctx.hippoRoot, { tenantId: ctx.tenantId, sessionId: req.sessionId, evidence, derived: state, key });
|
|
27
28
|
const snapshotsClosed = closeTaskSnapshotsForSession(ctx.hippoRoot, ctx.tenantId, req.sessionId, 'session-ended', key);
|
|
28
29
|
return { handoffWritten: handoff !== null, snapshotsClosed };
|
|
29
30
|
}
|