hippo-memory 1.70.0 → 1.72.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 +2 -2
- package/dist/agent-memories/apply.d.ts +0 -11
- package/dist/agent-memories/apply.js +6 -21
- package/dist/agent-memories/claude-code.d.ts +4 -2
- package/dist/agent-memories/claude-code.js +15 -6
- 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/files.js +23 -12
- package/dist/agent-memories/markdown.d.ts +1 -3
- package/dist/agent-memories/markdown.js +1 -3
- package/dist/agent-memories/project-folds.d.ts +10 -0
- package/dist/agent-memories/project-folds.js +34 -0
- package/dist/agent-memories/report.js +2 -1
- package/dist/agent-memories/sync.d.ts +4 -2
- package/dist/agent-memories/sync.js +18 -11
- package/dist/api/assemble.d.ts +7 -44
- package/dist/api/assemble.js +3 -23
- package/dist/api/audit.d.ts +33 -1
- package/dist/api/audit.js +48 -1
- package/dist/api/auth.d.ts +20 -26
- package/dist/api/auth.js +43 -29
- package/dist/api/auto-sleep.d.ts +5 -2
- package/dist/api/auto-sleep.js +9 -5
- package/dist/api/availability.d.ts +2 -15
- package/dist/api/availability.js +4 -18
- 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-render.js +4 -3
- package/dist/api/context-select.js +12 -15
- package/dist/api/context-types.d.ts +10 -35
- package/dist/api/context.d.ts +5 -22
- package/dist/api/context.js +38 -46
- package/dist/api/continuity.d.ts +47 -0
- package/dist/api/continuity.js +66 -0
- package/dist/{cli → api}/correction-latency.d.ts +2 -14
- package/dist/{cli → api}/correction-latency.js +2 -14
- package/dist/api/dormant.d.ts +5 -21
- package/dist/api/dormant.js +11 -28
- package/dist/api/drill-down.d.ts +7 -46
- package/dist/api/drill-down.js +6 -27
- 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 +11 -26
- package/dist/api/forget.js +23 -35
- package/dist/api/goals.d.ts +1 -1
- package/dist/api/goals.js +5 -9
- package/dist/api/graph.d.ts +8 -0
- package/dist/api/graph.js +7 -0
- package/dist/api/index.d.ts +6 -2
- package/dist/api/index.js +6 -2
- package/dist/api/instruction-detect.js +21 -6
- package/dist/api/learn.d.ts +4 -0
- package/dist/api/learn.js +53 -27
- package/dist/api/ledger-db.d.ts +2 -5
- package/dist/api/ledger-db.js +5 -35
- package/dist/api/memories.d.ts +23 -0
- package/dist/api/memories.js +46 -0
- package/dist/api/objects.d.ts +9 -0
- package/dist/api/objects.js +11 -0
- package/dist/api/on-store.js +5 -3
- package/dist/api/outcome.js +1 -1
- package/dist/api/pilot-arm.d.ts +1 -11
- package/dist/api/pilot-arm.js +5 -45
- package/dist/api/predictions.d.ts +11 -0
- package/dist/api/predictions.js +24 -0
- package/dist/api/projects.d.ts +21 -0
- package/dist/api/projects.js +24 -0
- package/dist/api/promote.d.ts +13 -17
- package/dist/api/promote.js +12 -20
- package/dist/api/prompt-hook.d.ts +19 -6
- package/dist/api/prompt-hook.js +54 -13
- package/dist/api/provenance-coverage.d.ts +14 -0
- package/dist/{cli → api}/provenance-coverage.js +2 -6
- package/dist/api/recall-cli.d.ts +58 -0
- package/dist/api/recall-cli.js +103 -0
- package/dist/api/recall-core.js +17 -9
- package/dist/api/recall-finish.d.ts +53 -0
- package/dist/api/recall-finish.js +30 -0
- package/dist/api/recall-history.d.ts +17 -84
- package/dist/api/recall-history.js +15 -88
- package/dist/api/recall-pipeline.d.ts +2 -3
- package/dist/api/recall-pipeline.js +21 -15
- package/dist/api/recall-request.js +1 -1
- package/dist/api/recall-types.d.ts +64 -304
- package/dist/api/recall.d.ts +3 -34
- package/dist/api/recall.js +63 -89
- package/dist/api/refine.d.ts +7 -0
- package/dist/api/refine.js +10 -0
- package/dist/api/remember-local.d.ts +57 -0
- package/dist/api/remember-local.js +90 -0
- package/dist/api/remember.d.ts +20 -2
- package/dist/api/remember.js +16 -3
- package/dist/api/session-end.d.ts +22 -0
- package/dist/api/session-end.js +101 -0
- package/dist/api/sleep-run.d.ts +2 -4
- package/dist/api/sleep-run.js +28 -28
- package/dist/api/sleep.d.ts +9 -28
- 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.d.ts +3 -10
- package/dist/api/tokens.js +4 -11
- package/dist/api/types.d.ts +8 -29
- package/dist/api/types.js +10 -23
- 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.d.ts +4 -12
- package/dist/capture/command.js +39 -114
- package/dist/capture/compact.d.ts +4 -15
- package/dist/capture/compact.js +26 -30
- package/dist/capture/compaction-items-caller.js +11 -20
- package/dist/capture/compaction-record.d.ts +7 -93
- package/dist/capture/compaction-record.js +34 -399
- package/dist/capture/compaction-spool.d.ts +5 -3
- package/dist/capture/compaction-spool.js +21 -7
- 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.d.ts +1 -1
- package/dist/capture/session-digest.js +17 -10
- package/dist/capture/session-end-caller.js +2 -1
- package/dist/capture/session-worker.js +3 -4
- package/dist/capture/transcript.d.ts +4 -11
- package/dist/capture/transcript.js +10 -21
- package/dist/capture/working-state.d.ts +4 -2
- package/dist/capture/working-state.js +4 -2
- package/dist/cli/api-context.d.ts +3 -0
- package/dist/cli/api-context.js +6 -0
- package/dist/cli/audit-prune.d.ts +1 -59
- package/dist/cli/audit-prune.js +2 -61
- package/dist/cli/audit.d.ts +1 -1
- package/dist/cli/audit.js +42 -43
- package/dist/cli/auth.d.ts +2 -2
- package/dist/cli/auth.js +61 -44
- package/dist/cli/briefs.d.ts +1 -4
- package/dist/cli/briefs.js +42 -301
- package/dist/cli/card.d.ts +2 -2
- package/dist/cli/card.js +63 -56
- package/dist/cli/client.d.ts +12 -27
- package/dist/cli/client.js +41 -44
- package/dist/cli/compact-resume-payload.js +4 -3
- package/dist/cli/context.d.ts +2 -3
- package/dist/cli/context.js +22 -18
- package/dist/cli/continuity.d.ts +6 -6
- package/dist/cli/continuity.js +81 -86
- package/dist/cli/curate.d.ts +13 -17
- package/dist/cli/curate.js +88 -116
- package/dist/cli/dag.d.ts +4 -4
- package/dist/cli/dag.js +55 -34
- package/dist/cli/decisions.d.ts +2 -4
- package/dist/cli/decisions.js +18 -309
- package/dist/cli/eval.d.ts +1 -1
- package/dist/cli/eval.js +27 -26
- package/dist/cli/exit.d.ts +6 -0
- package/dist/cli/exit.js +11 -0
- package/dist/cli/explain.d.ts +2 -3
- package/dist/cli/explain.js +25 -27
- package/dist/cli/flag-values.d.ts +6 -1
- package/dist/cli/flag-values.js +42 -15
- package/dist/cli/flags.d.ts +0 -288
- package/dist/cli/flags.js +3 -138
- package/dist/cli/github.d.ts +14 -0
- package/dist/{connectors/github/cli-impl.js → cli/github.js} +43 -71
- package/dist/cli/goals.d.ts +2 -2
- package/dist/cli/goals.js +46 -50
- package/dist/cli/graph.d.ts +3 -0
- package/dist/cli/graph.js +83 -0
- package/dist/cli/hook-runtime.d.ts +12 -32
- package/dist/cli/hook-runtime.js +21 -64
- package/dist/cli/incidents.d.ts +3 -0
- package/dist/cli/incidents.js +112 -0
- package/dist/cli/init.d.ts +2 -2
- package/dist/cli/init.js +33 -30
- package/dist/cli/install-steps.d.ts +2 -1
- package/dist/cli/install-steps.js +13 -14
- package/dist/cli/last-sleep.d.ts +2 -1
- package/dist/cli/last-sleep.js +4 -1
- package/dist/cli/lenient-id.d.ts +2 -0
- package/dist/cli/lenient-id.js +13 -0
- package/dist/cli/maintenance.d.ts +5 -5
- package/dist/cli/maintenance.js +37 -43
- package/dist/cli/notes.d.ts +2 -0
- package/dist/cli/notes.js +41 -0
- package/dist/cli/object-verbs.js +4 -3
- package/dist/cli/open-browser.d.ts +14 -0
- package/dist/cli/open-browser.js +26 -0
- package/dist/cli/owner-validation.d.ts +5 -28
- package/dist/cli/owner-validation.js +5 -28
- package/dist/cli/playbooks.d.ts +3 -4
- package/dist/cli/playbooks.js +131 -300
- package/dist/cli/predictions.d.ts +3 -0
- package/dist/cli/predictions.js +175 -0
- package/dist/cli/print.d.ts +2 -5
- package/dist/cli/print.js +3 -5
- package/dist/cli/projects.d.ts +2 -2
- package/dist/cli/projects.js +31 -25
- package/dist/cli/quality-repair-once.d.ts +1 -1
- package/dist/cli/quality-repair-once.js +7 -6
- package/dist/cli/recall.d.ts +2 -4
- package/dist/cli/recall.js +67 -137
- package/dist/cli/refine-llm.d.ts +5 -31
- package/dist/cli/refine-llm.js +23 -50
- package/dist/cli/remember.d.ts +3 -3
- package/dist/cli/remember.js +134 -192
- package/dist/cli/scheduler.d.ts +2 -17
- package/dist/cli/scheduler.js +14 -19
- package/dist/cli/serve.js +23 -14
- package/dist/cli/session-hooks.d.ts +11 -19
- package/dist/cli/session-hooks.js +143 -214
- package/dist/cli/setup.d.ts +4 -4
- package/dist/cli/setup.js +35 -30
- package/dist/cli/shared.d.ts +7 -25
- package/dist/cli/shared.js +17 -60
- package/dist/cli/slack.d.ts +2 -2
- package/dist/cli/slack.js +19 -23
- package/dist/cli/sleep-render.js +6 -3
- package/dist/cli/sleep.d.ts +3 -2
- package/dist/cli/sleep.js +17 -49
- package/dist/cli/status.d.ts +11 -14
- package/dist/cli/status.js +74 -120
- package/dist/cli/stdin.d.ts +4 -6
- package/dist/cli/stdin.js +2 -3
- package/dist/cli/transfer.d.ts +9 -9
- package/dist/cli/transfer.js +87 -108
- package/dist/cli/usage.d.ts +0 -79
- package/dist/cli/usage.js +1 -689
- package/dist/cli/verb-row.d.ts +32 -0
- package/dist/cli/verb-row.js +6 -0
- package/dist/cli/verbs/health.d.ts +27 -0
- package/dist/cli/verbs/health.js +232 -0
- package/dist/cli/verbs/memory.d.ts +16 -0
- package/dist/cli/verbs/memory.js +244 -0
- package/dist/cli/verbs/objects.d.ts +20 -0
- package/dist/cli/verbs/objects.js +254 -0
- package/dist/cli/verbs/sessions.d.ts +31 -0
- package/dist/cli/verbs/sessions.js +312 -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 -654
- package/dist/cli.js +44 -510
- package/dist/connectors/dlq.d.ts +39 -3
- package/dist/connectors/dlq.js +37 -3
- package/dist/connectors/github/backfill.d.ts +5 -25
- package/dist/connectors/github/backfill.js +26 -52
- package/dist/connectors/github/deletion.d.ts +4 -18
- package/dist/connectors/github/deletion.js +2 -15
- package/dist/connectors/github/dlq.d.ts +8 -33
- package/dist/connectors/github/dlq.js +34 -93
- package/dist/connectors/github/ingest.d.ts +4 -12
- package/dist/connectors/github/ingest.js +5 -36
- package/dist/connectors/github/octokit-client.d.ts +4 -16
- package/dist/connectors/github/octokit-client.js +27 -24
- package/dist/connectors/github/ratelimit.d.ts +3 -14
- package/dist/connectors/github/ratelimit.js +3 -14
- package/dist/connectors/github/scope.d.ts +3 -5
- package/dist/connectors/github/scope.js +3 -5
- package/dist/connectors/github/signature.d.ts +4 -26
- package/dist/connectors/github/signature.js +4 -26
- package/dist/connectors/github/tenant-routing.d.ts +2 -24
- package/dist/connectors/github/tenant-routing.js +4 -26
- package/dist/connectors/github/transform.js +2 -16
- package/dist/connectors/github/types.d.ts +3 -15
- package/dist/connectors/github/types.js +2 -9
- package/dist/connectors/github/webhook.d.ts +3 -16
- package/dist/connectors/github/webhook.js +38 -23
- package/dist/connectors/ingest.d.ts +10 -0
- package/dist/connectors/ingest.js +28 -0
- package/dist/connectors/slack/backfill.d.ts +4 -17
- package/dist/connectors/slack/backfill.js +4 -13
- package/dist/connectors/slack/dlq.d.ts +2 -19
- package/dist/connectors/slack/dlq.js +51 -90
- package/dist/connectors/slack/ingest.d.ts +4 -9
- package/dist/connectors/slack/ingest.js +4 -30
- package/dist/connectors/slack/scope.d.ts +2 -8
- package/dist/connectors/slack/scope.js +2 -8
- package/dist/connectors/slack/signature.d.ts +1 -6
- package/dist/connectors/slack/tenant-routing.d.ts +2 -19
- package/dist/connectors/slack/tenant-routing.js +2 -21
- package/dist/connectors/slack/transform.d.ts +2 -18
- package/dist/connectors/slack/transform.js +2 -18
- package/dist/connectors/slack/types.d.ts +3 -9
- package/dist/connectors/slack/types.js +2 -4
- package/dist/connectors/slack/web-client.js +33 -27
- package/dist/connectors/slack/webhook.d.ts +3 -19
- package/dist/connectors/slack/webhook.js +6 -26
- package/dist/connectors/slack/workspaces.d.ts +4 -24
- package/dist/connectors/slack/workspaces.js +4 -24
- package/dist/consolidate/conflicts.js +7 -15
- package/dist/consolidate/dag-summary.d.ts +8 -0
- package/dist/consolidate/dag-summary.js +41 -0
- package/dist/consolidate/dag.d.ts +5 -28
- package/dist/consolidate/dag.js +29 -84
- package/dist/consolidate/decay.js +7 -19
- package/dist/consolidate/dedupe.d.ts +13 -52
- package/dist/consolidate/dedupe.js +18 -74
- package/dist/consolidate/flush-units.d.ts +3 -4
- package/dist/consolidate/flush-units.js +3 -3
- package/dist/consolidate/half-life-migration.d.ts +3 -26
- package/dist/consolidate/half-life-migration.js +11 -28
- package/dist/consolidate/llm-passes.js +49 -40
- package/dist/consolidate/memory-value-weights.d.ts +2 -13
- package/dist/consolidate/memory-value-weights.js +2 -13
- package/dist/consolidate/memory-value.d.ts +11 -84
- package/dist/consolidate/memory-value.js +18 -105
- package/dist/consolidate/merge.js +12 -33
- package/dist/consolidate/physics-pass.d.ts +6 -1
- package/dist/consolidate/physics-pass.js +27 -9
- package/dist/consolidate/replay.d.ts +6 -38
- package/dist/consolidate/replay.js +25 -56
- package/dist/consolidate/run.js +1 -1
- package/dist/consolidate/sleep.d.ts +1 -8
- package/dist/consolidate/sleep.js +13 -22
- package/dist/consolidate/trace.d.ts +3 -18
- package/dist/consolidate/trace.js +3 -18
- package/dist/consolidate/traces.js +9 -25
- package/dist/core/ablation.d.ts +14 -91
- package/dist/core/ablation.js +16 -91
- package/dist/core/active-scope.d.ts +7 -0
- package/dist/{sharing/scope.js → core/active-scope.js} +5 -12
- package/dist/core/ambient.d.ts +5 -8
- package/dist/core/ambient.js +40 -26
- package/dist/core/api-errors.d.ts +16 -0
- package/dist/core/api-errors.js +20 -0
- package/dist/core/capture-contract.d.ts +4 -2
- package/dist/core/capture-contract.js +4 -2
- package/dist/core/card.d.ts +4 -1
- package/dist/core/card.js +11 -1
- package/dist/core/compaction-timing.d.ts +7 -0
- package/dist/core/compaction-timing.js +9 -0
- package/dist/core/compare.d.ts +11 -67
- package/dist/core/compare.js +9 -63
- package/dist/core/config.d.ts +10 -24
- package/dist/core/config.js +20 -16
- package/dist/core/cosine.d.ts +3 -0
- package/dist/core/cosine.js +19 -0
- package/dist/core/handoff.d.ts +1 -7
- package/dist/core/handoff.js +1 -7
- package/dist/core/markdown.d.ts +6 -0
- package/dist/{store → core}/markdown.js +23 -22
- package/dist/core/memory-audit.d.ts +17 -0
- package/dist/core/memory-audit.js +54 -0
- package/dist/core/memory-quality.js +1 -1
- package/dist/core/memory.d.ts +51 -168
- package/dist/core/memory.js +76 -239
- package/dist/{consolidate → core}/merged-row.d.ts +1 -1
- package/dist/{consolidate → core}/merged-row.js +3 -2
- package/dist/core/package-root.d.ts +3 -0
- package/dist/core/package-root.js +5 -0
- package/dist/core/physics-config.d.ts +1 -4
- package/dist/core/physics-config.js +3 -8
- package/dist/core/physics.d.ts +15 -61
- package/dist/core/physics.js +65 -138
- package/dist/core/prediction.d.ts +3 -0
- package/dist/core/prediction.js +6 -0
- package/dist/core/project-identity.d.ts +20 -58
- package/dist/core/project-identity.js +27 -39
- package/dist/core/project-remote.js +13 -2
- package/dist/core/raw-append-only.d.ts +5 -0
- package/dist/core/raw-append-only.js +7 -0
- package/dist/core/recall-scope.d.ts +69 -0
- package/dist/core/recall-scope.js +138 -0
- package/dist/core/salience.d.ts +1 -7
- package/dist/core/salience.js +1 -7
- package/dist/dashboard/dashboard-actions.js +2 -2
- package/dist/dashboard/dashboard-snapshot.d.ts +2 -1
- package/dist/dashboard/dashboard-snapshot.js +11 -2
- package/dist/dashboard/dashboard-types.d.ts +2 -1
- package/dist/dashboard/dashboard.d.ts +1 -0
- package/dist/dashboard/dashboard.js +50 -4
- package/dist/db/busy.d.ts +3 -8
- package/dist/db/busy.js +37 -33
- package/dist/db/connect.js +7 -8
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.js +3 -3
- package/dist/db/migrate.js +3 -3
- package/dist/db/migrations/index.d.ts +1 -1
- package/dist/db/migrations/index.js +3 -1
- package/dist/db/migrations/types.d.ts +2 -5
- package/dist/db/migrations/v14.js +2 -3
- package/dist/db/migrations/v15.js +2 -8
- package/dist/db/migrations/v16.js +2 -3
- package/dist/db/migrations/v17.js +2 -3
- package/dist/db/migrations/v19.js +2 -5
- package/dist/db/migrations/v20.js +2 -7
- package/dist/db/migrations/v22.js +4 -17
- package/dist/db/migrations/v23.js +3 -14
- package/dist/db/migrations/v24.js +2 -4
- package/dist/db/migrations/v25.js +3 -8
- package/dist/db/migrations/v26.js +2 -13
- package/dist/db/migrations/v27.js +3 -11
- package/dist/db/migrations/v28.js +2 -14
- package/dist/db/migrations/v29.js +4 -18
- package/dist/db/migrations/v30.js +4 -16
- package/dist/db/migrations/v31.js +2 -15
- package/dist/db/migrations/v32.js +4 -22
- package/dist/db/migrations/v33.js +2 -15
- package/dist/db/migrations/v34.js +2 -11
- package/dist/db/migrations/v35.js +2 -11
- package/dist/db/migrations/v36.js +2 -11
- package/dist/db/migrations/v37.js +8 -33
- package/dist/db/migrations/v38.js +5 -38
- package/dist/db/migrations/v39.js +9 -20
- package/dist/db/migrations/v40.js +2 -9
- package/dist/db/migrations/v41.js +2 -24
- package/dist/db/migrations/v43.js +1 -1
- package/dist/db/migrations/v44.js +2 -8
- package/dist/db/migrations/v45.js +2 -7
- package/dist/db/migrations/v47.js +2 -3
- package/dist/db/migrations/v51.js +1 -1
- package/dist/db/migrations/v55.d.ts +3 -0
- package/dist/db/migrations/v55.js +17 -0
- package/dist/db/open.d.ts +2 -2
- package/dist/db/open.js +21 -9
- package/dist/db/physics-state.d.ts +6 -22
- package/dist/db/physics-state.js +28 -39
- package/dist/db/raw-archive-mirror-cleanup.d.ts +2 -17
- package/dist/db/raw-archive-mirror-cleanup.js +2 -17
- package/dist/db/tables.d.ts +2 -0
- package/dist/db/tables.js +6 -2
- package/dist/db/vector-store.d.ts +2 -0
- package/dist/db/vector-store.js +25 -5
- package/dist/db/wal-checkpointer.js +2 -1
- package/dist/doctor.js +85 -27
- package/dist/embeddings/local.d.ts +62 -0
- package/dist/embeddings/local.js +146 -0
- package/dist/embeddings/provider.d.ts +43 -0
- package/dist/{store/embeddings → embeddings}/provider.js +58 -83
- 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 +3 -2
- package/dist/eval/eval-stats.d.ts +15 -53
- package/dist/eval/eval-stats.js +12 -42
- package/dist/eval/eval-suite.d.ts +2 -13
- package/dist/eval/eval-suite.js +91 -45
- package/dist/eval/eval.d.ts +6 -24
- package/dist/eval/eval.js +8 -35
- package/dist/eval/judgment.d.ts +0 -3
- package/dist/eval/judgment.js +30 -15
- package/dist/extensions/openclaw-plugin/index.js +1 -1
- package/dist/graph/extract.d.ts +5 -27
- package/dist/graph/extract.js +10 -36
- package/dist/graph/recall.d.ts +7 -20
- package/dist/graph/recall.js +15 -77
- package/dist/graph/stream.d.ts +7 -39
- package/dist/graph/stream.js +11 -34
- package/dist/graph/view.d.ts +9 -35
- package/dist/graph/view.js +24 -44
- 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 +4 -3
- package/dist/hooks/copilot.js +2 -1
- package/dist/hooks/hook-blocks.d.ts +6 -2
- package/dist/hooks/hook-blocks.js +37 -124
- package/dist/hooks/json-hooks.d.ts +4 -36
- package/dist/hooks/json-hooks.js +22 -59
- package/dist/hooks/opencode.d.ts +0 -38
- package/dist/hooks/opencode.js +17 -81
- package/dist/hooks/shared.d.ts +6 -21
- package/dist/hooks/shared.js +31 -33
- package/dist/importers/core.d.ts +12 -37
- package/dist/importers/core.js +10 -28
- package/dist/importers/markdown-parse.d.ts +8 -22
- package/dist/importers/markdown-parse.js +8 -25
- package/dist/importers/markdown.js +3 -12
- package/dist/importers/sources.js +12 -39
- package/dist/importers/vault.d.ts +2 -8
- package/dist/importers/vault.js +31 -85
- package/dist/index.d.ts +8 -3
- package/dist/index.js +8 -3
- package/dist/learn/autolearn.d.ts +23 -42
- package/dist/learn/autolearn.js +45 -52
- package/dist/learn/churn-git.js +13 -4
- package/dist/learn/extract.d.ts +3 -2
- package/dist/learn/extract.js +8 -8
- package/dist/learn/forward-claim-detector.d.ts +6 -30
- package/dist/learn/forward-claim-detector.js +18 -68
- package/dist/learn/invalidation.d.ts +6 -18
- package/dist/learn/invalidation.js +18 -31
- package/dist/mcp/admin-tools.d.ts +2 -2
- package/dist/mcp/admin-tools.js +30 -53
- 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.js +7 -10
- package/dist/mcp/protocol.d.ts +15 -29
- package/dist/mcp/protocol.js +26 -16
- package/dist/mcp/recall-tools.js +14 -11
- package/dist/mcp/request.d.ts +3 -11
- package/dist/mcp/request.js +12 -27
- package/dist/mcp/server.d.ts +3 -9
- package/dist/mcp/server.js +5 -16
- package/dist/mcp/session-state.d.ts +1 -1
- package/dist/mcp/session-state.js +5 -11
- package/dist/mcp/stdio.d.ts +2 -6
- package/dist/mcp/stdio.js +68 -16
- package/dist/mcp/tool-args.js +2 -1
- package/dist/mcp/tools.js +47 -22
- package/dist/objects/customer-notes.d.ts +9 -44
- package/dist/objects/customer-notes.js +7 -48
- package/dist/objects/decisions.d.ts +14 -52
- package/dist/objects/decisions.js +15 -53
- package/dist/objects/descriptor.d.ts +1 -1
- package/dist/objects/incidents.d.ts +9 -40
- package/dist/objects/incidents.js +7 -41
- package/dist/objects/lifecycle.d.ts +1 -1
- package/dist/objects/lifecycle.js +2 -1
- package/dist/objects/policies.d.ts +13 -91
- package/dist/objects/policies.js +13 -99
- package/dist/objects/processes.d.ts +9 -54
- package/dist/objects/processes.js +7 -61
- package/dist/objects/project-briefs.d.ts +13 -57
- package/dist/objects/project-briefs.js +16 -78
- package/dist/objects/skills.d.ts +9 -44
- package/dist/objects/skills.js +8 -54
- package/dist/postinstall.js +7 -20
- package/dist/predictions/planning-fallacy.d.ts +11 -34
- package/dist/rerankers/clef.js +6 -37
- package/dist/rerankers/cross-encoder.d.ts +31 -2
- package/dist/rerankers/cross-encoder.js +65 -101
- package/dist/rerankers/index.js +5 -4
- package/dist/rerankers/jev.js +11 -10
- package/dist/rerankers/llm.d.ts +2 -11
- package/dist/rerankers/llm.js +14 -14
- package/dist/rerankers/outage-warning.d.ts +5 -2
- package/dist/rerankers/outage-warning.js +7 -4
- package/dist/rerankers/remote.d.ts +1 -0
- package/dist/rerankers/remote.js +2 -0
- package/dist/rerankers/types.d.ts +2 -14
- package/dist/search/bm25-search.js +1 -1
- package/dist/search/boosts.d.ts +0 -2
- package/dist/search/boosts.js +3 -3
- package/dist/search/embed-memories.d.ts +9 -0
- package/dist/search/embed-memories.js +377 -0
- package/dist/search/goal-boost.d.ts +23 -0
- package/dist/search/goal-boost.js +93 -0
- package/dist/search/hybrid.d.ts +11 -2
- package/dist/search/hybrid.js +9 -4
- package/dist/search/multihop.js +2 -3
- package/dist/search/path-context.d.ts +5 -18
- package/dist/search/path-context.js +5 -18
- package/dist/search/physics-search.d.ts +6 -3
- package/dist/search/physics-search.js +29 -19
- package/dist/search/rerank.js +1 -1
- package/dist/search/rrf.d.ts +7 -35
- package/dist/search/rrf.js +5 -30
- package/dist/search/vector.d.ts +13 -4
- package/dist/search/vector.js +40 -13
- package/dist/server/auth.d.ts +11 -28
- package/dist/server/auth.js +49 -32
- package/dist/server/boot.d.ts +2 -21
- package/dist/server/boot.js +69 -161
- package/dist/server/client-ip.d.ts +3 -21
- package/dist/server/client-ip.js +8 -30
- package/dist/server/deadline.d.ts +0 -2
- package/dist/server/deadline.js +1 -7
- package/dist/server/defaults.d.ts +4 -0
- package/dist/server/defaults.js +5 -0
- package/dist/server/key-check-bounds.d.ts +2 -1
- package/dist/server/lifecycle.d.ts +5 -4
- package/dist/server/lifecycle.js +19 -4
- package/dist/server/mcp-http.js +24 -53
- package/dist/server/rate-limit.d.ts +5 -18
- package/dist/server/rate-limit.js +4 -13
- package/dist/server/request.d.ts +4 -8
- package/dist/server/request.js +16 -19
- 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 -139
- package/dist/server/routes/admin.d.ts +8 -8
- package/dist/server/routes/admin.js +35 -49
- package/dist/server/routes/customer-notes.d.ts +6 -6
- package/dist/server/routes/customer-notes.js +8 -14
- package/dist/server/routes/decisions.d.ts +6 -6
- package/dist/server/routes/decisions.js +12 -21
- package/dist/server/routes/incidents.d.ts +6 -6
- package/dist/server/routes/incidents.js +14 -25
- package/dist/server/routes/memories.d.ts +9 -9
- package/dist/server/routes/memories.js +20 -63
- package/dist/server/routes/object-routes.d.ts +6 -11
- package/dist/server/routes/object-routes.js +11 -22
- package/dist/server/routes/policies.d.ts +7 -7
- package/dist/server/routes/policies.js +12 -22
- package/dist/server/routes/predictions.d.ts +6 -6
- package/dist/server/routes/predictions.js +22 -38
- package/dist/server/routes/processes.d.ts +6 -6
- package/dist/server/routes/processes.js +17 -28
- package/dist/server/routes/project-briefs.d.ts +7 -7
- package/dist/server/routes/project-briefs.js +11 -20
- package/dist/server/routes/recall.d.ts +5 -5
- package/dist/server/routes/recall.js +16 -45
- package/dist/server/routes/skills.d.ts +7 -7
- package/dist/server/routes/skills.js +10 -22
- package/dist/server/server-detect.d.ts +15 -53
- package/dist/server/server-detect.js +55 -96
- package/dist/server/sleep-child.js +26 -7
- package/dist/server/sleep-offload.d.ts +11 -5
- package/dist/server/sleep-offload.js +21 -12
- package/dist/server/types.d.ts +32 -18
- package/dist/server/validation.d.ts +3 -2
- package/dist/server/validation.js +15 -33
- package/dist/server.d.ts +7 -6
- package/dist/server.js +8 -6
- package/dist/sharing/global-store.d.ts +19 -0
- package/dist/sharing/global-store.js +75 -0
- package/dist/sharing/global-sync.d.ts +6 -0
- package/dist/sharing/global-sync.js +73 -0
- package/dist/sharing/project-merge.d.ts +11 -19
- package/dist/sharing/project-merge.js +63 -125
- package/dist/sharing/search-both.d.ts +60 -0
- package/dist/sharing/search-both.js +138 -0
- package/dist/sharing/share.d.ts +40 -0
- package/dist/sharing/share.js +229 -0
- package/dist/store/ambient.js +9 -15
- package/dist/store/audit-event.d.ts +5 -13
- package/dist/store/audit-event.js +4 -12
- package/dist/store/audit.d.ts +2 -21
- package/dist/store/audit.js +8 -67
- package/dist/store/auth.d.ts +10 -8
- package/dist/store/auth.js +17 -12
- package/dist/store/candidates.d.ts +23 -5
- package/dist/store/candidates.js +119 -71
- package/dist/store/capture-write.d.ts +17 -0
- package/dist/store/capture-write.js +35 -0
- package/dist/store/card-detail.d.ts +2 -1
- package/dist/store/card-detail.js +2 -1
- package/dist/store/cards.d.ts +14 -9
- package/dist/store/cards.js +72 -126
- 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 +417 -0
- package/dist/store/compactions.js +6 -4
- package/dist/store/conflicts.d.ts +4 -21
- package/dist/store/conflicts.js +76 -152
- package/dist/store/connectors/dlq.d.ts +10 -0
- package/dist/store/connectors/dlq.js +32 -0
- package/dist/store/connectors/github.d.ts +14 -16
- package/dist/store/connectors/github.js +34 -57
- package/dist/store/connectors/slack.d.ts +2 -11
- package/dist/store/connectors/slack.js +18 -47
- package/dist/store/dashboard-reads.js +11 -14
- package/dist/store/delete-and-batch.d.ts +17 -31
- package/dist/store/delete-and-batch.js +84 -67
- package/dist/store/delivery-recorder.d.ts +15 -4
- package/dist/store/delivery-recorder.js +34 -17
- package/dist/store/descendant-page.js +6 -3
- package/dist/store/diagnostics.js +6 -13
- package/dist/store/dormant.d.ts +8 -30
- package/dist/store/dormant.js +18 -57
- package/dist/store/embeddings/index.d.ts +11 -90
- package/dist/store/embeddings/index.js +18 -523
- package/dist/store/entry-reads.d.ts +34 -61
- package/dist/store/entry-reads.js +111 -136
- package/dist/store/entry-row.d.ts +6 -35
- package/dist/store/entry-row.js +9 -37
- package/dist/store/entry-writes.d.ts +12 -18
- package/dist/store/entry-writes.js +46 -44
- 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.d.ts +3 -40
- package/dist/store/goals.js +41 -178
- package/dist/store/graph-queue.d.ts +6 -22
- package/dist/store/graph-queue.js +14 -45
- package/dist/store/graph-reads.d.ts +11 -35
- package/dist/store/graph-reads.js +24 -60
- package/dist/store/graph-rows.d.ts +3 -6
- package/dist/store/graph-rows.js +6 -9
- package/dist/store/graph-view-rows.d.ts +2 -1
- package/dist/store/graph-view-rows.js +2 -1
- package/dist/store/graph-writes.d.ts +10 -35
- package/dist/store/graph-writes.js +59 -106
- package/dist/store/half-life.d.ts +2 -1
- package/dist/store/half-life.js +14 -16
- package/dist/store/handoffs.d.ts +6 -12
- package/dist/store/handoffs.js +22 -40
- package/dist/store/index-and-stats.d.ts +6 -19
- package/dist/store/index-and-stats.js +36 -84
- 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.d.ts +2 -6
- package/dist/store/mirrors.js +24 -29
- package/dist/store/open.d.ts +0 -4
- package/dist/store/open.js +42 -62
- package/dist/store/pilot-arm.d.ts +12 -0
- package/dist/store/pilot-arm.js +42 -0
- package/dist/store/planning-fallacy-evidence.d.ts +2 -30
- package/dist/store/planning-fallacy-evidence.js +8 -37
- package/dist/store/port.d.ts +91 -82
- package/dist/store/port.js +8 -0
- package/dist/store/predictions.d.ts +12 -53
- package/dist/store/predictions.js +41 -125
- package/dist/store/project-tags.d.ts +62 -0
- package/dist/store/project-tags.js +67 -0
- package/dist/{cli → store}/quality-repair.js +15 -31
- package/dist/store/quarantine.js +2 -1
- package/dist/store/raw-archive.d.ts +4 -16
- package/dist/store/raw-archive.js +14 -29
- package/dist/store/recall-trace.d.ts +12 -77
- package/dist/store/recall-trace.js +37 -97
- package/dist/store/rejected-values.js +9 -20
- package/dist/store/rejection-probe.d.ts +4 -0
- package/dist/store/rejection-probe.js +19 -0
- package/dist/store/rejection.d.ts +10 -73
- package/dist/store/rejection.js +12 -84
- package/dist/store/report-reads.d.ts +6 -0
- package/dist/store/report-reads.js +29 -0
- package/dist/store/rows.d.ts +9 -19
- package/dist/store/rows.js +36 -34
- package/dist/store/rule-sql.d.ts +14 -0
- package/dist/store/rule-sql.js +56 -0
- package/dist/store/search-rows.d.ts +7 -38
- package/dist/store/search-rows.js +23 -54
- package/dist/store/sessions.d.ts +10 -47
- package/dist/store/sessions.js +21 -75
- 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 +5 -8
- package/dist/store/sqlite/connector-writes-group.js +3 -3
- package/dist/store/sqlite/entry-writes-group.js +4 -4
- package/dist/store/sqlite/error-codec.js +8 -5
- package/dist/store/sqlite/executor.d.ts +2 -1
- package/dist/store/sqlite/executor.js +12 -5
- package/dist/store/sqlite/graph-reads-group.js +1 -1
- package/dist/store/sqlite/held-connection.d.ts +9 -0
- package/dist/store/sqlite/held-connection.js +41 -0
- package/dist/store/sqlite/local.d.ts +3 -3
- package/dist/store/sqlite/local.js +1 -0
- package/dist/store/sqlite/object-rows.d.ts +1 -1
- package/dist/store/sqlite/object-rows.js +6 -3
- package/dist/store/sqlite/objects-group.d.ts +1 -1
- package/dist/store/sqlite/objects-group.js +5 -3
- package/dist/store/sqlite/quarantine-group.js +2 -2
- package/dist/store/sqlite/store.d.ts +1 -4
- package/dist/store/sqlite/store.js +16 -15
- package/dist/store/sqlite/vector-reads-group.js +2 -2
- package/dist/store/sqlite/worker-jobs.js +1 -1
- package/dist/store/sqlite/worker-ops.d.ts +13 -2
- package/dist/store/sqlite/worker-ops.js +13 -2
- package/dist/store/sqlite/worker-store.js +5 -2
- package/dist/store/summaries.d.ts +11 -63
- package/dist/store/summaries.js +37 -148
- package/dist/store/summary-dirty.js +1 -1
- package/dist/store/tenant-lookup.d.ts +6 -1
- package/dist/store/tenant-lookup.js +7 -0
- package/dist/store/tenant.d.ts +2 -16
- package/dist/store/tenant.js +4 -19
- package/dist/store/token-ledger.d.ts +13 -50
- package/dist/store/token-ledger.js +19 -85
- package/dist/store/usage-reports.js +5 -13
- package/dist/store/vector-index.d.ts +46 -0
- package/dist/store/vector-index.js +171 -0
- package/dist/store/working-memory.d.ts +6 -25
- package/dist/store/working-memory.js +18 -52
- package/dist/support-bundle.js +9 -8
- package/dist/trust/reject-flow.js +3 -5
- package/dist/util/agent-homes.d.ts +15 -0
- package/dist/util/agent-homes.js +34 -0
- package/dist/util/anthropic-messages.d.ts +3 -0
- package/dist/util/anthropic-messages.js +35 -6
- package/dist/util/atomic-write.d.ts +2 -1
- package/dist/util/atomic-write.js +35 -4
- package/dist/util/capped-json.d.ts +6 -0
- package/dist/util/capped-json.js +46 -0
- package/dist/util/chunked.d.ts +3 -0
- package/dist/util/chunked.js +10 -0
- package/dist/util/crash-handlers.d.ts +8 -1
- package/dist/util/crash-handlers.js +52 -10
- package/dist/util/ellipsize.d.ts +3 -0
- package/dist/util/ellipsize.js +5 -0
- package/dist/util/env.d.ts +14 -6
- package/dist/util/env.js +15 -7
- package/dist/util/format.d.ts +3 -0
- package/dist/util/format.js +6 -0
- package/dist/util/home-path.d.ts +2 -1
- package/dist/util/home-path.js +4 -2
- package/dist/util/hook-payload.d.ts +8 -0
- package/dist/util/hook-payload.js +37 -0
- package/dist/util/http-retry.d.ts +9 -1
- package/dist/util/http-retry.js +67 -8
- 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 +7 -2
- package/dist/util/log.js +34 -9
- package/dist/util/request-scope.d.ts +5 -2
- package/dist/util/request-scope.js +13 -7
- package/dist/util/secret-detect.d.ts +5 -30
- package/dist/util/secret-detect.js +19 -40
- package/dist/util/sqlite-blocked.d.ts +2 -0
- package/dist/util/sqlite-blocked.js +5 -0
- package/dist/util/stored-json.d.ts +1 -1
- package/dist/util/stored-json.js +1 -1
- 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/token-text.d.ts +1 -4
- package/dist/util/token-text.js +1 -4
- package/dist/util/transcript-tail.d.ts +2 -0
- package/dist/util/transcript-tail.js +24 -23
- package/dist/util/version.d.ts +5 -20
- package/dist/util/version.js +5 -20
- package/dist/{store → util}/yaml.d.ts +1 -5
- package/dist/{store → util}/yaml.js +2 -6
- package/extensions/openclaw-plugin/index.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 +2 -2
- package/dist/cli/provenance-coverage.d.ts +0 -18
- package/dist/connectors/github/cli-impl.d.ts +0 -25
- package/dist/sharing/scope.d.ts +0 -14
- package/dist/sharing/shared.d.ts +0 -187
- package/dist/sharing/shared.js +0 -563
- package/dist/store/embeddings/local.d.ts +0 -15
- package/dist/store/embeddings/local.js +0 -192
- package/dist/store/embeddings/provider.d.ts +0 -77
- package/dist/store/markdown.d.ts +0 -10
- package/dist/store/recall-scope.d.ts +0 -138
- package/dist/store/recall-scope.js +0 -216
- package/dist/store/vector-writes.d.ts +0 -13
- package/dist/store/vector-writes.js +0 -89
- /package/dist/{store → core}/object-types.d.ts +0 -0
- /package/dist/{store → core}/object-types.js +0 -0
- /package/dist/{cli → store}/quality-repair.d.ts +0 -0
- /package/dist/{capture → util}/compaction-items.d.ts +0 -0
- /package/dist/{capture → util}/compaction-items.js +0 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// GitHub event ingest, once per idempotency key. The key comes from the event's own content, never from the unsigned
|
|
2
2
|
// X-GitHub-Delivery header, so a replay cannot get past it by rotating the delivery id. The pre-check is only the fast path:
|
|
3
3
|
// the store logs the key in the memory's own transaction, which is what holds when two workers race.
|
|
4
|
-
import { remember } from '../../api/index.js';
|
|
5
4
|
import { requireGroup, storeFor } from '../../store/index.js';
|
|
6
|
-
import {
|
|
5
|
+
import { rememberWithEventLog } from '../ingest.js';
|
|
7
6
|
import { computeIdempotencyKey } from './signature.js';
|
|
8
7
|
import { issueEventToRememberOpts, issueCommentEventToRememberOpts, pullRequestEventToRememberOpts, prReviewCommentEventToRememberOpts, } from './transform.js';
|
|
9
8
|
function transformEvent(event) {
|
|
@@ -18,12 +17,8 @@ function transformEvent(event) {
|
|
|
18
17
|
return prReviewCommentEventToRememberOpts(event.payload);
|
|
19
18
|
}
|
|
20
19
|
}
|
|
21
|
-
/**
|
|
22
|
-
*
|
|
23
|
-
* Backfill and webhook both produce IngestEvent objects describing the same
|
|
24
|
-
* source revision, so deriving the key from these fields collapses both paths
|
|
25
|
-
* onto the same dedupe row. Mirrors the artifactRef strings in transform.ts.
|
|
26
|
-
*/
|
|
20
|
+
/** Extract the source-normalized identifier the idempotency key needs, so backfill and webhook deliveries of the same
|
|
21
|
+
* source revision collapse onto one dedupe row. Mirrors the artifactRef strings in transform.ts. */
|
|
27
22
|
function eventArtifactRef(event) {
|
|
28
23
|
const repo = event.payload.repository?.full_name ?? 'unknown/unknown';
|
|
29
24
|
switch (event.eventName) {
|
|
@@ -58,33 +53,7 @@ export async function ingestEvent(ctx, input) {
|
|
|
58
53
|
const seen = await events.eventRecord(event);
|
|
59
54
|
if (seen.seen)
|
|
60
55
|
return { status: 'duplicate', memoryId: seen.memoryId };
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// Empty body: no memory to write, but mark seen so a retry of the same
|
|
64
|
-
// empty event returns 'duplicate' (not 'skipped' again — that would
|
|
65
|
-
// re-run the transform on every retry).
|
|
66
|
-
await events.markEventSeen(event);
|
|
67
|
-
return { status: 'skipped', memoryId: null };
|
|
68
|
-
}
|
|
69
|
-
try {
|
|
70
|
-
return await rememberWithEventLog(ctx, event, opts);
|
|
71
|
-
}
|
|
72
|
-
catch (e) {
|
|
73
|
-
if (e instanceof RejectedValueError) {
|
|
74
|
-
// A tombstone hit is a PERMANENT skip, never DLQ-retried: mark the key seen like the empty-body
|
|
75
|
-
// branch above so a GitHub retry of the same delivery acks as done, not error.
|
|
76
|
-
await events.markEventSeen(event);
|
|
77
|
-
return { status: 'skipped', memoryId: null };
|
|
78
|
-
}
|
|
79
|
-
throw e;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
async function rememberWithEventLog(ctx, event, opts) {
|
|
83
|
-
// No `|| 'connector:github'` fallback (see rememberWithEventLog in slack/ingest.ts for rationale).
|
|
84
|
-
const result = await remember(ctx, { ...opts, untrusted: true, event });
|
|
85
|
-
// Another worker logged this key between the pre-check and the write: its memory stands and ours was not stored.
|
|
86
|
-
if (result.duplicate)
|
|
87
|
-
return { status: 'skipped_duplicate', memoryId: result.duplicate.memoryId };
|
|
88
|
-
return { status: 'ingested', memoryId: result.id };
|
|
56
|
+
// An empty body is logged too, so a retry returns 'duplicate' instead of re-running the transform.
|
|
57
|
+
return rememberWithEventLog(ctx, event, transformEvent(input.event));
|
|
89
58
|
}
|
|
90
59
|
//# sourceMappingURL=ingest.js.map
|
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Production uses `realGitHubFetcher` against `https://api.github.com`.
|
|
5
|
-
* Tests inject a fake `GitHubFetcher` so they never hit the network.
|
|
6
|
-
*
|
|
7
|
-
* Any non-200 response that is NOT a recognized rate-limit pause MUST throw
|
|
8
|
-
* `GitHubFetchError`: an empty page would be an empty backfill with no operator signal.
|
|
9
|
-
*/
|
|
1
|
+
/** Octokit-shaped HTTP fetcher for the GitHub backfill; tests inject a fake `GitHubFetcher`.
|
|
2
|
+
* Any non-200 that is not a recognised rate-limit pause MUST throw `GitHubFetchError`, since an empty page would be a silent empty backfill. */
|
|
10
3
|
import { type RateLimitInfo } from './ratelimit.js';
|
|
11
4
|
import type { JsonValue } from '../../util/json.js';
|
|
12
5
|
export declare class GitHubFetchError extends Error {
|
|
13
6
|
readonly status: number;
|
|
14
7
|
readonly bodyExcerpt: string;
|
|
15
8
|
readonly url: string;
|
|
16
|
-
constructor(status: number, bodyExcerpt: string, url: string);
|
|
9
|
+
constructor(status: number, bodyExcerpt: string, url: string, options?: ErrorOptions);
|
|
17
10
|
}
|
|
18
11
|
export interface GitHubBackfillPage {
|
|
19
12
|
readonly items: ReadonlyArray<JsonValue>;
|
|
@@ -24,12 +17,7 @@ export type GitHubFetcher = (args: {
|
|
|
24
17
|
url: string;
|
|
25
18
|
token: string;
|
|
26
19
|
}) => Promise<GitHubBackfillPage>;
|
|
27
|
-
/**
|
|
28
|
-
* Parse the rel="next" URL from an RFC 5988 `Link` header.
|
|
29
|
-
*
|
|
30
|
-
* Header format: `<url1>; rel="next", <url2>; rel="last"`.
|
|
31
|
-
* Returns the URL whose rel parameter is exactly `"next"`, or null.
|
|
32
|
-
*/
|
|
20
|
+
/** Parse the rel="next" URL from an RFC 5988 `Link` header, or null. */
|
|
33
21
|
export declare function parseNextLink(linkHeader: string): string | null;
|
|
34
22
|
export declare const realGitHubFetcher: GitHubFetcher;
|
|
35
23
|
//# sourceMappingURL=octokit-client.d.ts.map
|
|
@@ -1,32 +1,22 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Production uses `realGitHubFetcher` against `https://api.github.com`.
|
|
5
|
-
* Tests inject a fake `GitHubFetcher` so they never hit the network.
|
|
6
|
-
*
|
|
7
|
-
* Any non-200 response that is NOT a recognized rate-limit pause MUST throw
|
|
8
|
-
* `GitHubFetchError`: an empty page would be an empty backfill with no operator signal.
|
|
9
|
-
*/
|
|
1
|
+
/** Octokit-shaped HTTP fetcher for the GitHub backfill; tests inject a fake `GitHubFetcher`.
|
|
2
|
+
* Any non-200 that is not a recognised rate-limit pause MUST throw `GitHubFetchError`, since an empty page would be a silent empty backfill. */
|
|
10
3
|
import { parseRateLimit } from './ratelimit.js';
|
|
11
4
|
import { fetchWithRetry } from '../../util/http-retry.js';
|
|
5
|
+
import { readCappedJson, readCappedText } from '../../util/capped-json.js';
|
|
6
|
+
import { errorMessage } from '../../util/log.js';
|
|
12
7
|
export class GitHubFetchError extends Error {
|
|
13
8
|
status;
|
|
14
9
|
bodyExcerpt;
|
|
15
10
|
url;
|
|
16
|
-
constructor(status, bodyExcerpt, url) {
|
|
17
|
-
super(`GitHub ${status} on ${url}: ${bodyExcerpt}
|
|
11
|
+
constructor(status, bodyExcerpt, url, options) {
|
|
12
|
+
super(`GitHub ${status} on ${url}: ${bodyExcerpt}`, options);
|
|
18
13
|
this.status = status;
|
|
19
14
|
this.bodyExcerpt = bodyExcerpt;
|
|
20
15
|
this.url = url;
|
|
21
16
|
this.name = 'GitHubFetchError';
|
|
22
17
|
}
|
|
23
18
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Parse the rel="next" URL from an RFC 5988 `Link` header.
|
|
26
|
-
*
|
|
27
|
-
* Header format: `<url1>; rel="next", <url2>; rel="last"`.
|
|
28
|
-
* Returns the URL whose rel parameter is exactly `"next"`, or null.
|
|
29
|
-
*/
|
|
19
|
+
/** Parse the rel="next" URL from an RFC 5988 `Link` header, or null. */
|
|
30
20
|
export function parseNextLink(linkHeader) {
|
|
31
21
|
if (!linkHeader)
|
|
32
22
|
return null;
|
|
@@ -43,6 +33,24 @@ function headersToRecord(h) {
|
|
|
43
33
|
}
|
|
44
34
|
const GITHUB_TIMEOUT_MS = 30_000;
|
|
45
35
|
const ERROR_BODY_SNIPPET_CHARS = 256;
|
|
36
|
+
const UTF8_MAX_BYTES_PER_CHAR = 4;
|
|
37
|
+
// A page is at most 100 items (per_page=100), each with a body of up to 65,536 characters at 4 bytes, plus its fields.
|
|
38
|
+
const GITHUB_MAX_REPLY_BYTES = 32 * 1024 * 1024;
|
|
39
|
+
/** The items of a 200 list reply. A body that is not JSON, is over the cap or is not an array throws, so it never reaches ingest as items. */
|
|
40
|
+
async function readItems(res, url) {
|
|
41
|
+
// The path only: a `next` link comes from the server, so its query string is not ours to print.
|
|
42
|
+
const path = new URL(url).pathname;
|
|
43
|
+
let body;
|
|
44
|
+
try {
|
|
45
|
+
body = await readCappedJson(res, GITHUB_MAX_REPLY_BYTES);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
throw new GitHubFetchError(res.status, errorMessage(err), path, { cause: err });
|
|
49
|
+
}
|
|
50
|
+
if (!Array.isArray(body))
|
|
51
|
+
throw new GitHubFetchError(res.status, 'the reply is not a JSON array', path);
|
|
52
|
+
return body;
|
|
53
|
+
}
|
|
46
54
|
export const realGitHubFetcher = async ({ url, token }) => {
|
|
47
55
|
const res = await fetchWithRetry(url, {
|
|
48
56
|
headers: {
|
|
@@ -56,15 +64,10 @@ export const realGitHubFetcher = async ({ url, token }) => {
|
|
|
56
64
|
// Don't silently turn 401/403/404/500 into empty pages.
|
|
57
65
|
if (res.status !== 200 && rateLimit.reason === 'none') {
|
|
58
66
|
// The status is the error reported; a body that cannot be read only costs its snippet.
|
|
59
|
-
const body = await res
|
|
67
|
+
const body = await readCappedText(res, ERROR_BODY_SNIPPET_CHARS * UTF8_MAX_BYTES_PER_CHAR).catch(() => '');
|
|
60
68
|
throw new GitHubFetchError(res.status, body.slice(0, ERROR_BODY_SNIPPET_CHARS), url);
|
|
61
69
|
}
|
|
62
|
-
|
|
63
|
-
// only endpoints this backfill fetcher targets) return a JSON array body
|
|
64
|
-
// on 200; per-item shape is intentionally left as `unknown` here since
|
|
65
|
-
// GitHubBackfillPage.items is opaque to this seam (callers parse the
|
|
66
|
-
// shape they expect downstream).
|
|
67
|
-
const items = res.status === 200 ? (await res.json()) : [];
|
|
70
|
+
const items = res.status === 200 ? await readItems(res, url) : [];
|
|
68
71
|
const link = res.headers.get('link') ?? '';
|
|
69
72
|
const next = parseNextLink(link);
|
|
70
73
|
return { items, next, rateLimit };
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* GitHub returns 403 for primary rate-limit (with `X-RateLimit-Remaining: 0`
|
|
5
|
-
* and `X-RateLimit-Reset: <epoch>`) and 429 + `Retry-After: <seconds>` for
|
|
6
|
-
* secondary rate-limit. Backfill must pause and resume rather than error.
|
|
7
|
-
*/
|
|
1
|
+
/** GitHub rate-limit header parser: 403 with `X-RateLimit-Remaining: 0` is primary, 429 with `Retry-After` is secondary.
|
|
2
|
+
* Backfill must pause and resume rather than error. */
|
|
8
3
|
export interface RateLimitInfo {
|
|
9
4
|
readonly sleepSeconds: number;
|
|
10
5
|
readonly reason: 'primary' | 'secondary' | 'none';
|
|
11
6
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Parse rate-limit signal from a GitHub HTTP response.
|
|
14
|
-
*
|
|
15
|
-
* @param headers Lower-cased HTTP response headers.
|
|
16
|
-
* @param status HTTP status code.
|
|
17
|
-
* @param now Optional current epoch seconds (for deterministic tests).
|
|
18
|
-
*/
|
|
7
|
+
/** Parse the rate-limit signal from a GitHub response; `headers` are lower-cased and `now` (epoch seconds) is for deterministic tests. */
|
|
19
8
|
export declare function parseRateLimit(headers: Record<string, string | undefined>, status: number, now?: number): RateLimitInfo;
|
|
20
9
|
//# sourceMappingURL=ratelimit.d.ts.map
|
|
@@ -1,17 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
|
|
4
|
-
* GitHub returns 403 for primary rate-limit (with `X-RateLimit-Remaining: 0`
|
|
5
|
-
* and `X-RateLimit-Reset: <epoch>`) and 429 + `Retry-After: <seconds>` for
|
|
6
|
-
* secondary rate-limit. Backfill must pause and resume rather than error.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Parse rate-limit signal from a GitHub HTTP response.
|
|
10
|
-
*
|
|
11
|
-
* @param headers Lower-cased HTTP response headers.
|
|
12
|
-
* @param status HTTP status code.
|
|
13
|
-
* @param now Optional current epoch seconds (for deterministic tests).
|
|
14
|
-
*/
|
|
1
|
+
/** GitHub rate-limit header parser: 403 with `X-RateLimit-Remaining: 0` is primary, 429 with `Retry-After` is secondary.
|
|
2
|
+
* Backfill must pause and resume rather than error. */
|
|
3
|
+
/** Parse the rate-limit signal from a GitHub response; `headers` are lower-cased and `now` (epoch seconds) is for deterministic tests. */
|
|
15
4
|
export function parseRateLimit(headers, status, now) {
|
|
16
5
|
const _now = now ?? Math.floor(Date.now() / 1000);
|
|
17
6
|
if (status === 429) {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { GitHubRepository } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* nothing) << cost of leaking private into public (data exposure).
|
|
6
|
-
*/
|
|
2
|
+
/** Map a GitHub repository to a hippo scope string. Default-private when
|
|
3
|
+
* privacy is undetermined: cost of leaking public into private (recall returns
|
|
4
|
+
* nothing) << cost of leaking private into public (data exposure). */
|
|
7
5
|
export declare function scopeFromRepository(repo: GitHubRepository | undefined): string;
|
|
8
6
|
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* nothing) << cost of leaking private into public (data exposure).
|
|
5
|
-
*/
|
|
1
|
+
/** Map a GitHub repository to a hippo scope string. Default-private when
|
|
2
|
+
* privacy is undetermined: cost of leaking public into private (recall returns
|
|
3
|
+
* nothing) << cost of leaking private into public (data exposure). */
|
|
6
4
|
export function scopeFromRepository(repo) {
|
|
7
5
|
if (!repo)
|
|
8
6
|
return 'github:private:unknown';
|
|
@@ -7,32 +7,10 @@ export interface VerifyOpts {
|
|
|
7
7
|
previousSecret?: string;
|
|
8
8
|
}
|
|
9
9
|
export declare function verifyGitHubSignature(opts: VerifyOpts): boolean;
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
12
|
-
* A raw-body key would hash a webhook envelope and a REST backfill item of the
|
|
13
|
-
* SAME source event differently and ingest it twice. Same artifact + same
|
|
14
|
-
* revision = same key, whichever path delivered it; an edit gets a new key,
|
|
15
|
-
* which is correct because each edit IS a new memory revision.
|
|
16
|
-
*
|
|
17
|
-
* Both inputs are upstream-derived from the parsed event, not from the
|
|
18
|
-
* unsigned delivery header — replay attacks still cannot bypass dedupe.
|
|
19
|
-
*
|
|
20
|
-
* Inputs:
|
|
21
|
-
* - artifactRef: e.g. 'github://acme/repo/issue/42' or
|
|
22
|
-
* 'github://acme/repo/issue/42/comment/123'.
|
|
23
|
-
* - updatedAt: source-side ISO timestamp (issue.updated_at,
|
|
24
|
-
* comment.updated_at, pull_request.updated_at). Empty string when the
|
|
25
|
-
* payload omits it (rare; older REST shapes).
|
|
26
|
-
*/
|
|
10
|
+
/** Source-aware idempotency key: artifact_ref plus the source-side updated_at, so a webhook and a REST backfill of the SAME event dedupe.
|
|
11
|
+
* An edit gets a new key (a new revision); both inputs come from the parsed event, not the unsigned delivery header, so replays cannot bypass dedupe. */
|
|
27
12
|
export declare function computeIdempotencyKey(artifactRef: string, updatedAt: string | null | undefined): string;
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
* updatedAt). Distinct namespace from computeIdempotencyKey so an ingest's row
|
|
31
|
-
* in github_event_log doesn't make a deletion return 'duplicate' before it
|
|
32
|
-
* gets a chance to archive; retries of the SAME deletion still dedupe.
|
|
33
|
-
*
|
|
34
|
-
* Kept as a separate exported function so the namespace prefix is explicit
|
|
35
|
-
* at every call site (server.ts deletion branches, deletion.ts, DLQ replay).
|
|
36
|
-
*/
|
|
13
|
+
/** Deletion idempotency key: sha256('deleted:' + artifactRef + ':' + updatedAt).
|
|
14
|
+
* A separate namespace so an ingest's event-log row cannot make a deletion return 'duplicate'; retries of the same deletion still dedupe. */
|
|
37
15
|
export declare function computeDeletionKey(artifactRef: string, updatedAt: string | null | undefined): string;
|
|
38
16
|
//# sourceMappingURL=signature.d.ts.map
|
|
@@ -16,35 +16,13 @@ export function verifyGitHubSignature(opts) {
|
|
|
16
16
|
return true;
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
-
/**
|
|
20
|
-
*
|
|
21
|
-
* A raw-body key would hash a webhook envelope and a REST backfill item of the
|
|
22
|
-
* SAME source event differently and ingest it twice. Same artifact + same
|
|
23
|
-
* revision = same key, whichever path delivered it; an edit gets a new key,
|
|
24
|
-
* which is correct because each edit IS a new memory revision.
|
|
25
|
-
*
|
|
26
|
-
* Both inputs are upstream-derived from the parsed event, not from the
|
|
27
|
-
* unsigned delivery header — replay attacks still cannot bypass dedupe.
|
|
28
|
-
*
|
|
29
|
-
* Inputs:
|
|
30
|
-
* - artifactRef: e.g. 'github://acme/repo/issue/42' or
|
|
31
|
-
* 'github://acme/repo/issue/42/comment/123'.
|
|
32
|
-
* - updatedAt: source-side ISO timestamp (issue.updated_at,
|
|
33
|
-
* comment.updated_at, pull_request.updated_at). Empty string when the
|
|
34
|
-
* payload omits it (rare; older REST shapes).
|
|
35
|
-
*/
|
|
19
|
+
/** Source-aware idempotency key: artifact_ref plus the source-side updated_at, so a webhook and a REST backfill of the SAME event dedupe.
|
|
20
|
+
* An edit gets a new key (a new revision); both inputs come from the parsed event, not the unsigned delivery header, so replays cannot bypass dedupe. */
|
|
36
21
|
export function computeIdempotencyKey(artifactRef, updatedAt) {
|
|
37
22
|
return createHash('sha256').update(`${artifactRef}:${updatedAt ?? ''}`).digest('hex');
|
|
38
23
|
}
|
|
39
|
-
/**
|
|
40
|
-
*
|
|
41
|
-
* updatedAt). Distinct namespace from computeIdempotencyKey so an ingest's row
|
|
42
|
-
* in github_event_log doesn't make a deletion return 'duplicate' before it
|
|
43
|
-
* gets a chance to archive; retries of the SAME deletion still dedupe.
|
|
44
|
-
*
|
|
45
|
-
* Kept as a separate exported function so the namespace prefix is explicit
|
|
46
|
-
* at every call site (server.ts deletion branches, deletion.ts, DLQ replay).
|
|
47
|
-
*/
|
|
24
|
+
/** Deletion idempotency key: sha256('deleted:' + artifactRef + ':' + updatedAt).
|
|
25
|
+
* A separate namespace so an ingest's event-log row cannot make a deletion return 'duplicate'; retries of the same deletion still dedupe. */
|
|
48
26
|
export function computeDeletionKey(artifactRef, updatedAt) {
|
|
49
27
|
return createHash('sha256').update(`deleted:${artifactRef}:${updatedAt ?? ''}`).digest('hex');
|
|
50
28
|
}
|
|
@@ -5,29 +5,7 @@ export interface ResolveArgs {
|
|
|
5
5
|
/** `repository.full_name` from the webhook envelope, used for PAT-mode multi-tenant routing. */
|
|
6
6
|
repoFullName?: string | null;
|
|
7
7
|
}
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Returns:
|
|
12
|
-
* - mapped tenant_id when `github_installations` has a row for `installationId`
|
|
13
|
-
* (App-mode multi-tenant — primary path)
|
|
14
|
-
* - mapped tenant_id when `installation` is absent, `repository.full_name`
|
|
15
|
-
* matches a `github_repositories` row (PAT-mode multi-tenant)
|
|
16
|
-
* - the deployment's HIPPO_TENANT fallback (or 'default') when BOTH routing
|
|
17
|
-
* tables are empty (single-tenant deployment — env fallback is safe)
|
|
18
|
-
* - null when:
|
|
19
|
-
* - `installationId` is present but unknown AND `github_installations`
|
|
20
|
-
* is non-empty (multi-tenant install with foreign installation)
|
|
21
|
-
* - `installationId` is missing AND either routing table is non-empty
|
|
22
|
-
* AND no `repository.full_name` match (PAT-mode webhook from a foreign
|
|
23
|
-
* account)
|
|
24
|
-
*
|
|
25
|
-
* Escape hatch: `GITHUB_ALLOW_UNKNOWN_INSTALLATION_FALLBACK=1` restores the
|
|
26
|
-
* env fallback for emergency rollback only. Mirrors the Slack equivalent
|
|
27
|
-
* (`SLACK_ALLOW_UNKNOWN_TEAM_FALLBACK`).
|
|
28
|
-
*
|
|
29
|
-
* The fail-closed contract lives here so every caller (route handler, CLI
|
|
30
|
-
* replay, future MCP) gets identical protection.
|
|
31
|
-
*/
|
|
8
|
+
/** Resolve a GitHub envelope's tenant_id by installation id, then repository.full_name; the HIPPO_TENANT fallback applies only if both tables are empty.
|
|
9
|
+
* An unknown installation or repo on a multi-tenant deployment returns null (fail closed); GITHUB_ALLOW_UNKNOWN_INSTALLATION_FALLBACK=1 escapes. */
|
|
32
10
|
export declare function resolveTenantForGitHub(hippoRoot: string, args: ResolveArgs, store?: HippoStore): Promise<string | null>;
|
|
33
11
|
//# sourceMappingURL=tenant-routing.d.ts.map
|
|
@@ -1,32 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { envGitHubAllowUnknownInstallationFallback, envTenant } from '../../util/env.js';
|
|
2
2
|
import { requireGroup, storeFor } from '../../store/index.js';
|
|
3
|
-
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Returns:
|
|
7
|
-
* - mapped tenant_id when `github_installations` has a row for `installationId`
|
|
8
|
-
* (App-mode multi-tenant — primary path)
|
|
9
|
-
* - mapped tenant_id when `installation` is absent, `repository.full_name`
|
|
10
|
-
* matches a `github_repositories` row (PAT-mode multi-tenant)
|
|
11
|
-
* - the deployment's HIPPO_TENANT fallback (or 'default') when BOTH routing
|
|
12
|
-
* tables are empty (single-tenant deployment — env fallback is safe)
|
|
13
|
-
* - null when:
|
|
14
|
-
* - `installationId` is present but unknown AND `github_installations`
|
|
15
|
-
* is non-empty (multi-tenant install with foreign installation)
|
|
16
|
-
* - `installationId` is missing AND either routing table is non-empty
|
|
17
|
-
* AND no `repository.full_name` match (PAT-mode webhook from a foreign
|
|
18
|
-
* account)
|
|
19
|
-
*
|
|
20
|
-
* Escape hatch: `GITHUB_ALLOW_UNKNOWN_INSTALLATION_FALLBACK=1` restores the
|
|
21
|
-
* env fallback for emergency rollback only. Mirrors the Slack equivalent
|
|
22
|
-
* (`SLACK_ALLOW_UNKNOWN_TEAM_FALLBACK`).
|
|
23
|
-
*
|
|
24
|
-
* The fail-closed contract lives here so every caller (route handler, CLI
|
|
25
|
-
* replay, future MCP) gets identical protection.
|
|
26
|
-
*/
|
|
3
|
+
/** Resolve a GitHub envelope's tenant_id by installation id, then repository.full_name; the HIPPO_TENANT fallback applies only if both tables are empty.
|
|
4
|
+
* An unknown installation or repo on a multi-tenant deployment returns null (fail closed); GITHUB_ALLOW_UNKNOWN_INSTALLATION_FALLBACK=1 escapes. */
|
|
27
5
|
export async function resolveTenantForGitHub(hippoRoot, args, store) {
|
|
28
6
|
const envFallback = () => envTenant();
|
|
29
|
-
const escapeHatch =
|
|
7
|
+
const escapeHatch = envGitHubAllowUnknownInstallationFallback();
|
|
30
8
|
const routing = await requireGroup(storeFor({ hippoRoot, store }), 'connectorEvents').githubRouting(args);
|
|
31
9
|
if (routing.tenant)
|
|
32
10
|
return routing.tenant;
|
|
@@ -1,20 +1,6 @@
|
|
|
1
1
|
import { scopeFromRepository } from './scope.js';
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* function returns null when the event has no usable body so the webhook
|
|
5
|
-
* caller can mark the delivery seen for idempotency and skip the insert.
|
|
6
|
-
*
|
|
7
|
-
* Contract (mirrors src/connectors/slack/transform.ts):
|
|
8
|
-
* - kind is the literal 'raw' (connector boundary, see src/importers.ts).
|
|
9
|
-
* - artifact_ref formats are stable; deletion paths look up by these strings.
|
|
10
|
-
* - issue: github://<owner/repo>/issue/<number>
|
|
11
|
-
* - issue_comment: github://<owner/repo>/issue/<number>/comment/<id>
|
|
12
|
-
* - pull_request: github://<owner/repo>/pull/<number>
|
|
13
|
-
* - pr_review_comment: github://<owner/repo>/pull/<number>/review_comment/<id>
|
|
14
|
-
* - owner is `user:github:<login>`. Required by the provenance gate.
|
|
15
|
-
* - scope is derived from repository.private via scopeFromRepository (default
|
|
16
|
-
* private when undetermined).
|
|
17
|
-
*/
|
|
2
|
+
/** Convert GitHub webhook events into RememberOpts; each returns null when the event has no usable body so the caller marks it seen and skips the insert.
|
|
3
|
+
* artifact_ref formats (github://<owner/repo>/issue|pull/<n>[/comment|review_comment/<id>]) are stable because deletion looks rows up by them. */
|
|
18
4
|
const UNKNOWN_REPO = 'unknown/unknown';
|
|
19
5
|
export function issueEventToRememberOpts(evt) {
|
|
20
6
|
const body = evt.issue.body?.trim();
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub
|
|
3
|
-
* Spec: https://docs.github.com/en/webhooks/webhook-events-and-payloads
|
|
4
|
-
*
|
|
5
|
-
* V1 cares about four event types: issues, issue_comment, pull_request,
|
|
6
|
-
* pull_request_review_comment. Each guard is gated on the X-GitHub-Event
|
|
7
|
-
* header value so a malicious or misrouted payload cannot satisfy a guard
|
|
8
|
-
* for the wrong event type.
|
|
9
|
-
*/
|
|
1
|
+
/** GitHub webhook event shapes for the ingestion connector (https://docs.github.com/en/webhooks/webhook-events-and-payloads).
|
|
2
|
+
* Each guard is gated on the X-GitHub-Event header so a misrouted payload cannot satisfy a guard for the wrong event type. */
|
|
10
3
|
import { type JsonValue } from '../../util/json.js';
|
|
11
|
-
/**
|
|
12
|
-
* `private` MUST be optional, not required. The Slack-style
|
|
13
|
-
* fail-safe in scope.ts requires an envelope with `private: undefined` to
|
|
14
|
-
* map to private; a strict boolean type would reject the payload before
|
|
15
|
-
* scope can fail closed.
|
|
16
|
-
*/
|
|
4
|
+
/** `private` MUST stay optional: scope.ts maps `private: undefined` to private, and a strict boolean would reject the payload before scope can fail closed. */
|
|
17
5
|
export interface GitHubRepository {
|
|
18
6
|
full_name: string;
|
|
19
7
|
private?: boolean;
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub
|
|
3
|
-
* Spec: https://docs.github.com/en/webhooks/webhook-events-and-payloads
|
|
4
|
-
*
|
|
5
|
-
* V1 cares about four event types: issues, issue_comment, pull_request,
|
|
6
|
-
* pull_request_review_comment. Each guard is gated on the X-GitHub-Event
|
|
7
|
-
* header value so a malicious or misrouted payload cannot satisfy a guard
|
|
8
|
-
* for the wrong event type.
|
|
9
|
-
*/
|
|
1
|
+
/** GitHub webhook event shapes for the ingestion connector (https://docs.github.com/en/webhooks/webhook-events-and-payloads).
|
|
2
|
+
* Each guard is gated on the X-GitHub-Event header so a misrouted payload cannot satisfy a guard for the wrong event type. */
|
|
10
3
|
import { isJsonString, isJsonNumber } from '../../util/json.js';
|
|
11
4
|
function isObjectOrArray(x) {
|
|
12
5
|
return x !== null && typeof x === 'object';
|
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
import type { HippoStore } from '../../store/index.js';
|
|
2
2
|
import { type WebhookRequest } from '../../util/http-util.js';
|
|
3
|
-
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* 1. HMAC SHA-256 over the raw body (X-Hub-Signature-256), no timestamp.
|
|
7
|
-
* 2. Event type discriminated by the X-GitHub-Event header (not body.type).
|
|
8
|
-
* 3. X-GitHub-Delivery is required audit metadata (NOT the dedupe seam - see
|
|
9
|
-
* computeIdempotencyKey, which folds the signed body into the key so a
|
|
10
|
-
* replayed body with a fresh delivery UUID still dedupes).
|
|
11
|
-
* 4. Tenant resolved by installation.id → github_installations, then by
|
|
12
|
-
* repository.full_name → github_repositories (PAT-mode multi-tenant).
|
|
13
|
-
* 5. ALWAYS ACK 200 on signed envelopes (DLQ included). 401 only on bad
|
|
14
|
-
* signature; 404 only when GITHUB_WEBHOOK_SECRET is unset (don't expose
|
|
15
|
-
* the route's existence on builds where it's gated off).
|
|
16
|
-
*
|
|
17
|
-
* Bearer auth is skipped on purpose: server.ts checks isPublicRoute before calling this.
|
|
18
|
-
*/
|
|
3
|
+
/** GitHub webhook receiver: HMAC SHA-256 over the raw body, event type from the X-GitHub-Event header, tenant by installation.id then repository.full_name.
|
|
4
|
+
* ACKs 200 on signed envelopes (DLQ too); 401 only on a bad signature; 409 on a delivery id seen in the replay window;
|
|
5
|
+
* 404 when GITHUB_WEBHOOK_SECRET is unset. No Bearer: its route row declares webhook-signature. */
|
|
19
6
|
export declare function handleGitHubEventsWebhook(request: WebhookRequest, store?: HippoStore): Promise<void>;
|
|
20
7
|
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { envGitHubWebhookSecret, envGitHubWebhookSecretPrevious } from '../../util/env.js';
|
|
2
2
|
import { verifyGitHubSignature } from './signature.js';
|
|
3
3
|
import { isGitHubWebhookEnvelope, isGitHubIssueEvent, isGitHubIssueCommentEvent, isGitHubPullRequestEvent, isGitHubPullRequestReviewCommentEvent, } from './types.js';
|
|
4
4
|
import { ingestEvent as ingestGitHubEvent } from './ingest.js';
|
|
@@ -9,33 +9,20 @@ import { resolveTenantForGitHub } from './tenant-routing.js';
|
|
|
9
9
|
import { computeDeletionKey as computeGitHubDeletionKey } from './signature.js';
|
|
10
10
|
import { resolveTenantId } from '../../store/tenant.js';
|
|
11
11
|
import { HttpError, JSON_HEADERS, isHeaderString, closeIfBodyUnread, readWebhookBody, sendJson, } from '../../util/http-util.js';
|
|
12
|
-
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* 1. HMAC SHA-256 over the raw body (X-Hub-Signature-256), no timestamp.
|
|
16
|
-
* 2. Event type discriminated by the X-GitHub-Event header (not body.type).
|
|
17
|
-
* 3. X-GitHub-Delivery is required audit metadata (NOT the dedupe seam - see
|
|
18
|
-
* computeIdempotencyKey, which folds the signed body into the key so a
|
|
19
|
-
* replayed body with a fresh delivery UUID still dedupes).
|
|
20
|
-
* 4. Tenant resolved by installation.id → github_installations, then by
|
|
21
|
-
* repository.full_name → github_repositories (PAT-mode multi-tenant).
|
|
22
|
-
* 5. ALWAYS ACK 200 on signed envelopes (DLQ included). 401 only on bad
|
|
23
|
-
* signature; 404 only when GITHUB_WEBHOOK_SECRET is unset (don't expose
|
|
24
|
-
* the route's existence on builds where it's gated off).
|
|
25
|
-
*
|
|
26
|
-
* Bearer auth is skipped on purpose: server.ts checks isPublicRoute before calling this.
|
|
27
|
-
*/
|
|
12
|
+
/** GitHub webhook receiver: HMAC SHA-256 over the raw body, event type from the X-GitHub-Event header, tenant by installation.id then repository.full_name.
|
|
13
|
+
* ACKs 200 on signed envelopes (DLQ too); 401 only on a bad signature; 409 on a delivery id seen in the replay window;
|
|
14
|
+
* 404 when GITHUB_WEBHOOK_SECRET is unset. No Bearer: its route row declares webhook-signature. */
|
|
28
15
|
export async function handleGitHubEventsWebhook(request, store) {
|
|
29
16
|
const { req, res, opts } = request;
|
|
30
17
|
// Secret and signature header before the body, so a caller with neither cannot make the server buffer one.
|
|
31
|
-
const secret =
|
|
18
|
+
const secret = envGitHubWebhookSecret();
|
|
32
19
|
if (!secret) {
|
|
33
20
|
closeIfBodyUnread(request);
|
|
34
21
|
res.writeHead(404, JSON_HEADERS);
|
|
35
22
|
res.end(JSON.stringify({ error: 'not found' }));
|
|
36
23
|
return;
|
|
37
24
|
}
|
|
38
|
-
const previousSecret =
|
|
25
|
+
const previousSecret = envGitHubWebhookSecretPrevious();
|
|
39
26
|
const sigHdr = req.headers['x-hub-signature-256'];
|
|
40
27
|
const eventHdr = req.headers['x-github-event'];
|
|
41
28
|
const deliveryHdr = req.headers['x-github-delivery'];
|
|
@@ -57,7 +44,37 @@ export async function handleGitHubEventsWebhook(request, store) {
|
|
|
57
44
|
}
|
|
58
45
|
// Signature OK from here on. Everything else is ACK-200; bad envelopes go
|
|
59
46
|
// to the DLQ and a human can replay later.
|
|
60
|
-
|
|
47
|
+
const replayKey = deliveryId === null ? null : `${opts.hippoRoot}\n${deliveryId}`;
|
|
48
|
+
if (replayKey !== null && !claimDelivery(replayKey, Date.now()))
|
|
49
|
+
throw new HttpError(409, 'duplicate X-GitHub-Delivery');
|
|
50
|
+
try {
|
|
51
|
+
await routeSignedDelivery({ hippoRoot: opts.hippoRoot, store, res, rawBody, eventName, deliveryId, signature: sigStr });
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
// A delivery that failed left nothing stored, so GitHub's redelivery of the same id must get through.
|
|
55
|
+
if (replayKey !== null)
|
|
56
|
+
seenDeliveries.delete(replayKey);
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// GitHub signs no timestamp, so a captured delivery verifies forever; this window is what refuses its replay.
|
|
61
|
+
const DELIVERY_REPLAY_TTL_MS = 24 * 60 * 60 * 1000;
|
|
62
|
+
const DELIVERY_REPLAY_MAX_IDS = 10_000;
|
|
63
|
+
// SHORTCUT: seen ids live in this process and reset on restart or eviction; move them to the store if serve ever runs as several processes.
|
|
64
|
+
const seenDeliveries = new Map();
|
|
65
|
+
/** Claims a delivery id for the window; false when it was claimed within the window already. The oldest claim goes first at the cap. */
|
|
66
|
+
function claimDelivery(key, now) {
|
|
67
|
+
const seenAt = seenDeliveries.get(key);
|
|
68
|
+
if (seenAt !== undefined && now - seenAt < DELIVERY_REPLAY_TTL_MS)
|
|
69
|
+
return false;
|
|
70
|
+
seenDeliveries.delete(key);
|
|
71
|
+
if (seenDeliveries.size >= DELIVERY_REPLAY_MAX_IDS) {
|
|
72
|
+
const oldest = seenDeliveries.keys().next();
|
|
73
|
+
if (!oldest.done)
|
|
74
|
+
seenDeliveries.delete(oldest.value);
|
|
75
|
+
}
|
|
76
|
+
seenDeliveries.set(key, now);
|
|
77
|
+
return true;
|
|
61
78
|
}
|
|
62
79
|
const ALLOWED_EVENTS = new Set([
|
|
63
80
|
'issues',
|
|
@@ -167,9 +184,7 @@ async function dispatchGitHubEvent(d, ctx, body, deliveryId, routing) {
|
|
|
167
184
|
if (action === null)
|
|
168
185
|
return false;
|
|
169
186
|
if (action.kind === 'manual-review') {
|
|
170
|
-
//
|
|
171
|
-
// policy is to log and let an operator decide. Archive could lose the
|
|
172
|
-
// memory if the issue is being moved between accounts.
|
|
187
|
+
// issues.deleted (admin-initiated) is logged, not archived: archiving could lose the memory if the issue moves between accounts.
|
|
173
188
|
await parkAndAck(d, {
|
|
174
189
|
...routing,
|
|
175
190
|
tenantId: ctx.tenantId,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Context, type RememberOpts } from '../api/index.js';
|
|
2
|
+
import type { ConnectorEvent } from '../store/port.js';
|
|
3
|
+
export type IngestStatus = 'ingested' | 'duplicate' | 'skipped' | 'skipped_duplicate';
|
|
4
|
+
export interface IngestResult {
|
|
5
|
+
status: IngestStatus;
|
|
6
|
+
memoryId: string | null;
|
|
7
|
+
}
|
|
8
|
+
/** Stores `opts` once per event key; null `opts` (an empty body) and a tombstoned value are logged with no memory, so a redelivery acks instead of retrying. */
|
|
9
|
+
export declare function rememberWithEventLog(ctx: Context, event: ConnectorEvent, opts: RememberOpts | null): Promise<IngestResult>;
|
|
10
|
+
//# sourceMappingURL=ingest.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// The write half every connector's ingest shares, after its own pre-check of the event log.
|
|
2
|
+
import { remember } from '../api/index.js';
|
|
3
|
+
import { requireGroup, storeFor } from '../store/index.js';
|
|
4
|
+
import { RejectedValueError } from '../core/api-errors.js';
|
|
5
|
+
/** Stores `opts` once per event key; null `opts` (an empty body) and a tombstoned value are logged with no memory, so a redelivery acks instead of retrying. */
|
|
6
|
+
export async function rememberWithEventLog(ctx, event, opts) {
|
|
7
|
+
if (!opts)
|
|
8
|
+
return markSkipped(ctx, event);
|
|
9
|
+
try {
|
|
10
|
+
// No actor fallback: every caller builds ctx with its connector subject.
|
|
11
|
+
const result = await remember(ctx, { ...opts, untrusted: true, event });
|
|
12
|
+
// Another worker logged this key between the pre-check and the write: its memory stands and ours was not stored.
|
|
13
|
+
if (result.duplicate)
|
|
14
|
+
return { status: 'skipped_duplicate', memoryId: result.duplicate.memoryId };
|
|
15
|
+
return { status: 'ingested', memoryId: result.id };
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
// A tombstone refusal is permanent, so a DLQ retry would hit it forever.
|
|
19
|
+
if (e instanceof RejectedValueError)
|
|
20
|
+
return markSkipped(ctx, event);
|
|
21
|
+
throw e;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function markSkipped(ctx, event) {
|
|
25
|
+
await requireGroup(storeFor(ctx), 'connectorEvents').markEventSeen(event);
|
|
26
|
+
return { status: 'skipped', memoryId: null };
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=ingest.js.map
|