@hilbras/remembra 3.6.0 → 3.8.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/README.md +9 -1
  3. package/dist/backend.d.ts +17 -0
  4. package/dist/crypto.d.ts +10 -0
  5. package/dist/crypto.js +77 -0
  6. package/dist/crypto.js.map +1 -0
  7. package/dist/diff.d.ts +15 -0
  8. package/dist/diff.js +135 -0
  9. package/dist/diff.js.map +1 -0
  10. package/dist/errors.d.ts +3 -8
  11. package/dist/errors.js +11 -0
  12. package/dist/errors.js.map +1 -1
  13. package/dist/http.d.ts +5 -1
  14. package/dist/http.js +84 -4
  15. package/dist/http.js.map +1 -1
  16. package/dist/index.js +64 -4
  17. package/dist/index.js.map +1 -1
  18. package/dist/llm.d.ts +2 -0
  19. package/dist/llm.js +3 -0
  20. package/dist/llm.js.map +1 -1
  21. package/dist/log.d.ts +19 -0
  22. package/dist/log.js +28 -0
  23. package/dist/log.js.map +1 -0
  24. package/dist/metrics.d.ts +22 -0
  25. package/dist/metrics.js +121 -0
  26. package/dist/metrics.js.map +1 -0
  27. package/dist/redact.d.ts +33 -0
  28. package/dist/redact.js +104 -0
  29. package/dist/redact.js.map +1 -0
  30. package/dist/service.d.ts +75 -0
  31. package/dist/service.js +230 -10
  32. package/dist/service.js.map +1 -1
  33. package/dist/store.d.ts +17 -1
  34. package/dist/store.js +134 -6
  35. package/dist/store.js.map +1 -1
  36. package/dist/types.d.ts +74 -0
  37. package/dist/types.js +30 -0
  38. package/dist/types.js.map +1 -1
  39. package/dist/version.d.ts +6 -0
  40. package/dist/version.js +7 -0
  41. package/dist/version.js.map +1 -0
  42. package/docs/architecture.md +52 -3
  43. package/docs/chatgpt.md +25 -0
  44. package/docs/clients.md +4 -0
  45. package/docs/lifecycle.md +10 -3
  46. package/docs/memory-model.md +42 -3
  47. package/docs/observability.md +125 -0
  48. package/docs/security.md +63 -3
  49. package/docs/tools.md +48 -1
  50. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,127 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
7
7
  > (3.0.0 = v3). Earlier releases used independent semver: 0.1.0 = v1,
8
8
  > 0.2.0 = v1.5, 0.3.0 = v2, 0.4.0 = v3.
9
9
 
10
+ ## [3.8.0] — 2026-09-23
11
+
12
+ **Phase 8 of the deep audit — Advanced Capabilities.** All five roadmap
13
+ items covered; both storage-altering features are **opt-in** (scope review:
14
+ plain markdown and byte-faithful storage remain the defaults).
15
+
16
+ ### Added
17
+ - **Relationship graph** — `related: [ids]` frontmatter (directed, single
18
+ write; backlinks derived at read time), `memory_relate` MCP tool
19
+ (add/remove, targets validated, self-links rejected, idempotent), plus the
20
+ missing read surfaces: **`memory_get`** / `GET /memories/:id` return a
21
+ memory with resolved `related` + `backlinks`. Retrieval ranking untouched —
22
+ graph is structure for the consumer, not a score.
23
+ - **Confidence scores** — `confidence: 0–1` frontmatter: explicit stores
24
+ default `1.0`, digest extractions `0.7` (the extraction LLM may supply its
25
+ own via the extended prompt/schema). Surfaced everywhere and carried through
26
+ merge/export/import; **deliberately not ranked** — importance answers
27
+ "relevant?", confidence answers "true?" (Phase 4 weight decisions stay
28
+ closed).
29
+ - **PII redaction filter** (opt-in `REMEMBRA_REDACT=1`) — pattern filter at
30
+ the *ingest layer* (`memory_store`, digest items, merge output): emails,
31
+ Luhn-valid cards, SSNs, phone numbers, provider tokens / ≥40-char entropy
32
+ blobs → typed placeholders (`<EMAIL>` …). Cards must pass Luhn; phone
33
+ matching requires separators + 10–15 digits, so dates/versions never match.
34
+ Irreversible by design; `remembra_redactions_total{kind}` + `redacted`
35
+ log event (counts only, never matched text). Reverses the former "no PII
36
+ filter" non-goal — documented with its limits in `docs/security.md`.
37
+ - **Encrypted storage mode** (opt-in `REMEMBRA_ENCRYPT_KEY`) — AES-256-GCM
38
+ per file via `node:crypto` (zero deps): magic-header detection, transparent
39
+ decrypt-on-read, encrypt-on-write, mixed plain/cipher trees supported;
40
+ `remembra encrypt` / `remembra decrypt` migrate the whole tree (incl.
41
+ history) idempotently under the advisory lock. Missing/wrong key fails
42
+ **loudly**: `ENCRYPTED_NO_KEY` (HTTP 503, `/health` `storage` field) —
43
+ never warn-skipped into silent partial results. GCM makes wrong-key ≡
44
+ tampered. Reverses the former "no encryption at rest" non-goal with an
45
+ explicit threat-model section (protects stolen backups / copied dirs, not
46
+ a runtime attacker with your env).
47
+ - **Diff/history view** — content-changing updates snapshot the raw
48
+ on-disk pre-image into `.history/<id>/<epochMs>-<seq>.md` first (content-
49
+ equality gate: embedding backfills and linking never snapshot);
50
+ `memory_history` MCP tool + `GET /memories/:id/history?limit=` return
51
+ versions newest-first, each with a **unified line diff** against its
52
+ predecessor (own ~60-line LCS, zero deps, cell-budget fallback for huge
53
+ contents). Pruned to `REMEMBRA_HISTORY_LIMIT` (default 20, `0` disables);
54
+ `.history` is never walked by `all()`/search.
55
+
56
+ ### Changed
57
+ - Error classification gains `ENCRYPTED_NO_KEY` (503) and documents why it
58
+ breaks the skip-malformed-file rule; `metrics` route enum gains
59
+ `memory_sub` (the relate/history sub-routes).
60
+ - Extraction system prompt optionally returns `confidence` (0–1).
61
+
62
+ ### Docs
63
+ `tools` (+3 tools, 9 total, encrypt/decrypt CLI), `memory-model`
64
+ (relationships, version history, metadata rows, layout incl. `.history`),
65
+ `security` (encryption + redaction sections replace the two reversed
66
+ non-goals, checklist items), `architecture` (encryption format, history
67
+ snapshot design, error table), `clients` (+3 env vars), `observability`
68
+ (+4 counters, `memory_sub`, `redacted` event), `chatgpt` (+3 routes),
69
+ `lifecycle` (merge → history cross-ref), README (9 tools, 11 routes).
70
+
71
+ ### Tests
72
+ - **148 tests** (+16: redaction patterns + false-positive guards + service
73
+ on/off, digest redaction & confidence pass-through, confidence round-trip,
74
+ relations incl. backlinks/validation/idempotence/persistence, diff unit,
75
+ merge → snapshot → diff view, embedding-gate + limit pruning, encryption
76
+ round-trip / missing-key loud failure / wrong-key / mixed trees /
77
+ idempotent both-way migration incl. history, HTTP GET/relate/history
78
+ routes + `memory_sub` metric label). Suite verified stable across 3
79
+ consecutive runs.
80
+
81
+ ## [3.7.0] — 2026-09-23
82
+
83
+ **Phase 7 of the deep audit** — observability. All five roadmap items
84
+ covered (error-rate alerting taken as the *pragmatic substrate*: counters +
85
+ documented rules, no built-in notifier — decided in scope review).
86
+
87
+ ### Added
88
+ - **Structured JSON logging** (`src/log.ts`) — every server-side event goes
89
+ through one logger on **stderr** (stdout stays reserved for MCP stdio/CLI).
90
+ Format: `REMEMBRA_LOG=json|text` forces it; unset → auto — JSON when stderr
91
+ is piped (containers, CI, shippers), text on a TTY. Text mode prints the
92
+ exact legacy strings, so existing greps and the Phase 2/3 tests still hold.
93
+ JSON lines carry `{"ts","level","event","msg",...fields}`.
94
+ - **`GET /metrics`** (`src/metrics.ts`) — zero-dependency Prometheus text
95
+ endpoint: request/digest/search/cache counters, latency histograms,
96
+ `errors_total{code,transport}`, cache-entry gauge, `remembra_info`. Route
97
+ labels are a fixed low-cardinality enum (never raw paths). Sits **after**
98
+ the API-key check — keyed deployments must not leak counters; `/health`
99
+ stays exempt.
100
+ - **Search query logging** — one structured `search` event per call (scope,
101
+ term count, results, limit, `duration_ms`). Raw query text only under
102
+ `REMEMBRA_DEBUG` (Phase 2 log-hygiene rule unchanged).
103
+ - **`/health` readiness probe** — now runs a real storage read: `200 ok`
104
+ with `version`/`uptime_s`/`storage`/`cache` fields, **`503 unready`** with
105
+ the failing error code when storage cannot be read — the probe fails
106
+ instead of lying. Field `status:"ok"` kept for existing consumers.
107
+ - **Alerting infrastructure** — `docs/observability.md`: metric reference,
108
+ scrape config (incl. `x-api-key`), and ready-to-paste Prometheus rules
109
+ (down, internal error rate with 4xx excluded, readiness, lock contention,
110
+ search p95, cache thrash). No built-in notifier by design: a local tool
111
+ alerts through the operator's existing stack.
112
+ - `src/version.ts` single-sources `VERSION` (MCP server id, `/health`,
113
+ `remembra_info`); a test pins it to `package.json`.
114
+
115
+ ### Fixed
116
+ - **Prometheus bucket labels** — histogram series emitted `{le="…"route="…"}`
117
+ (missing comma), caught by the exposition-format test.
118
+
119
+ ### Changed
120
+ - Conversion to `logEvent` at 8 sites (listening banners, shutdown, parse
121
+ skip, crash recovery, embedding/touch/merge/decay failures) — messages
122
+ unchanged in text mode.
123
+
124
+ ### Tests
125
+ - **132 tests** (+13: log formats + auto-detection, `/metrics` content,
126
+ label enum + exposition grammar, auth on `/metrics`, counter movement for
127
+ store/search/cache, MCP + HTTP error counters, hygiene-first query logging
128
+ (and `REMEMBRA_DEBUG` opt-in), healthy + broken-storage `/health`,
129
+ version pin). Suite verified stable across 3 consecutive runs.
130
+
10
131
  ## [3.6.0] — 2026-09-23
11
132
 
12
133
  **Phase 6 of the deep audit** — testing depth. All six roadmap items now
package/README.md CHANGED
@@ -85,10 +85,14 @@ Then wire a Custom GPT to the API — full walkthrough in **[docs/chatgpt.md](do
85
85
 
86
86
  | Method | Route | Purpose |
87
87
  |--------|-------|---------|
88
- | GET | `/health` | Liveness (no auth) |
88
+ | GET | `/health` | Liveness + readiness (no auth) |
89
+ | GET | `/metrics` | Prometheus metrics (auth when keyed) |
89
90
  | POST | `/memories` | Store a memory |
90
91
  | GET | `/memories/search?query=&scope=` | Search |
91
92
  | GET | `/memories?scope=&type=` | List |
93
+ | GET | `/memories/:id` | One memory + related links + backlinks |
94
+ | POST | `/memories/:id/relate` | Link / unlink memories |
95
+ | GET | `/memories/:id/history` | Version history with line diffs |
92
96
  | POST | `/memories/digest` | LLM extract + store from a transcript |
93
97
  | POST | `/maintain` | Decay sweep + vector backfill |
94
98
  | DELETE | `/memories/:id` | Forget |
@@ -123,6 +127,9 @@ tampered snapshot is rejected atomically, never half-imported. Of course,
123
127
  | `memory_digest` | Extract + store memories from a transcript (LLM) |
124
128
  | `memory_search` | Retrieve relevant memories (pass `scope` = current project) |
125
129
  | `memory_list` | Browse stored memories |
130
+ | `memory_get` | Fetch one memory with its links and backlinks |
131
+ | `memory_relate` | Link / unlink memories (relationship graph) |
132
+ | `memory_history` | Version history of a memory with line diffs |
126
133
  | `memory_maintain` | Archive decayed / delete expired / backfill vectors |
127
134
  | `memory_forget` | Delete by id |
128
135
 
@@ -139,6 +146,7 @@ Full reference: **[docs/tools.md](docs/tools.md)**
139
146
  | [AI providers](docs/providers.md) | Digest LLM + embeddings configuration |
140
147
  | [Lifecycle](docs/lifecycle.md) | Decay, archiving, auto-delete, contradiction merging |
141
148
  | [Security](docs/security.md) | Trust model, enforced protections, deployment checklist |
149
+ | [Observability](docs/observability.md) | Structured logs, Prometheus metrics, health/readiness, alert rules |
142
150
  | [Architecture](docs/architecture.md) | Backend interface, locking, crash recovery, error codes |
143
151
  | [Contributing](CONTRIBUTING.md) | Dev workflow and guidelines |
144
152
  | [Changelog](CHANGELOG.md) | Release history |
package/dist/backend.d.ts CHANGED
@@ -1,4 +1,14 @@
1
1
  import type { Memory, StoreInput } from "./types.js";
2
+ /** One superseded pre-image from `.history/<id>/` (audit Phase 8). */
3
+ export interface HistoryEntry {
4
+ /** Snapshot file name (`${epochMs}-${seq}.md`). */
5
+ file: string;
6
+ /** The pre-image's own `updatedAt` — when this version was current. */
7
+ at?: string;
8
+ /** When the snapshot was taken (from the file name's epoch prefix). */
9
+ snapshotAt?: string;
10
+ content: string;
11
+ }
2
12
  /**
3
13
  * Storage abstraction (audit: Phase 3 — separate MemoryStore abstraction to
4
14
  * enable a future DB swap).
@@ -18,6 +28,11 @@ export interface MemoryBackend {
18
28
  store(input: StoreInput, embedding?: number[], opts?: {
19
29
  provenance?: Memory["provenance"];
20
30
  }): Promise<Memory>;
31
+ /** Optional observability hook — the file backend exposes parse-cache stats. */
32
+ cacheStats?(): {
33
+ size: number;
34
+ capacity: number;
35
+ };
21
36
  get(id: string): Promise<Memory | null>;
22
37
  all(includeArchived?: boolean): Promise<Memory[]>;
23
38
  update(memory: Memory): Promise<Memory>;
@@ -26,4 +41,6 @@ export interface MemoryBackend {
26
41
  touch(id: string): Promise<void>;
27
42
  forget(id: string): Promise<boolean>;
28
43
  importMemory(m: Memory): Promise<boolean>;
44
+ /** Optional (audit Phase 8): superseded pre-images, newest first. */
45
+ history?(id: string): Promise<HistoryEntry[]>;
29
46
  }
@@ -0,0 +1,10 @@
1
+ export declare function encryptionEnabled(): boolean;
2
+ /** Cheap detection: does this file already hold ciphertext? */
3
+ export declare function isEncrypted(buf: Buffer): boolean;
4
+ export declare function encryptBuffer(plain: Buffer): Buffer;
5
+ /**
6
+ * Decrypt a file buffer. Throws `ENCRYPTED_NO_KEY` when the key is missing
7
+ * or wrong (GCM authentication failure covers both — a tampered file must
8
+ * fail identically).
9
+ */
10
+ export declare function decryptBuffer(buf: Buffer): Buffer;
package/dist/crypto.js ADDED
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Encrypted storage mode (audit Phase 8).
3
+ *
4
+ * Opt-in: `REMEMBRA_ENCRYPT_KEY` set → memory files are written as
5
+ * AES-256-GCM ciphertext (node:crypto — zero dependencies) and decrypted
6
+ * transparently on read. Unset → plain markdown, exactly as before.
7
+ *
8
+ * Key material: a 64-hex-char (32-byte) key, used directly — no KDF, no
9
+ * salt (a high-entropy symmetric key needs neither; per-file random nonces
10
+ * provide uniqueness). Generate one with:
11
+ * node -p 'require("node:crypto").randomBytes(32).toString("hex")'
12
+ *
13
+ * On-disk format (files keep their .md names; detection is by magic bytes):
14
+ * MAGIC(7) "RMBENC1" | nonce(12) | tag(16) | ciphertext
15
+ * The AAD is empty — files move between trees (archive/revive) freely.
16
+ *
17
+ * Failure mode without the key: reading an encrypted file throws
18
+ * `ENCRYPTED_NO_KEY` (HTTP 503, health `storage: ENCRYPTED_NO_KEY`) instead
19
+ * of warn-skipping — a store you cannot read must fail loudly, never
20
+ * silently serve partial data.
21
+ *
22
+ * Migration: `remembra encrypt` / `remembra decrypt` rewrite the tree under
23
+ * the storage lock (idempotent; already-converted files are skipped).
24
+ */
25
+ import { randomBytes, createCipheriv, createDecipheriv } from "node:crypto";
26
+ import { RemembraError } from "./errors.js";
27
+ const MAGIC = Buffer.from("RMBENC1", "ascii");
28
+ const NONCE_LEN = 12;
29
+ const TAG_LEN = 16;
30
+ export function encryptionEnabled() {
31
+ return (process.env.REMEMBRA_ENCRYPT_KEY ?? "").length > 0;
32
+ }
33
+ function rawKey() {
34
+ const hex = process.env.REMEMBRA_ENCRYPT_KEY ?? "";
35
+ if (!/^[0-9a-fA-F]{64}$/.test(hex)) {
36
+ throw new RemembraError("INVALID_INPUT", "REMEMBRA_ENCRYPT_KEY must be 64 hex chars (32 bytes). Generate one: " +
37
+ `node -p 'require("node:crypto").randomBytes(32).toString("hex")'`);
38
+ }
39
+ return Buffer.from(hex, "hex");
40
+ }
41
+ /** Cheap detection: does this file already hold ciphertext? */
42
+ export function isEncrypted(buf) {
43
+ return buf.length > MAGIC.length && buf.subarray(0, MAGIC.length).equals(MAGIC);
44
+ }
45
+ export function encryptBuffer(plain) {
46
+ const nonce = randomBytes(NONCE_LEN);
47
+ const cipher = createCipheriv("aes-256-gcm", rawKey(), nonce);
48
+ const ct = Buffer.concat([cipher.update(plain), cipher.final()]);
49
+ return Buffer.concat([MAGIC, nonce, cipher.getAuthTag(), ct]);
50
+ }
51
+ /**
52
+ * Decrypt a file buffer. Throws `ENCRYPTED_NO_KEY` when the key is missing
53
+ * or wrong (GCM authentication failure covers both — a tampered file must
54
+ * fail identically).
55
+ */
56
+ export function decryptBuffer(buf) {
57
+ if (!isEncrypted(buf))
58
+ return buf; // plain file first: plain mode must never throw
59
+ if (!encryptionEnabled()) {
60
+ throw new RemembraError("ENCRYPTED_NO_KEY", "storage contains encrypted memories but REMEMBRA_ENCRYPT_KEY is not set");
61
+ }
62
+ if (buf.length < MAGIC.length + NONCE_LEN + TAG_LEN + 1) {
63
+ throw new RemembraError("ENCRYPTED_NO_KEY", "encrypted file is truncated");
64
+ }
65
+ const nonce = buf.subarray(MAGIC.length, MAGIC.length + NONCE_LEN);
66
+ const tag = buf.subarray(MAGIC.length + NONCE_LEN, MAGIC.length + NONCE_LEN + TAG_LEN);
67
+ const ct = buf.subarray(MAGIC.length + NONCE_LEN + TAG_LEN);
68
+ try {
69
+ const decipher = createDecipheriv("aes-256-gcm", rawKey(), nonce);
70
+ decipher.setAuthTag(tag);
71
+ return Buffer.concat([decipher.update(ct), decipher.final()]);
72
+ }
73
+ catch {
74
+ throw new RemembraError("ENCRYPTED_NO_KEY", "cannot decrypt: wrong REMEMBRA_ENCRYPT_KEY or corrupted file");
75
+ }
76
+ }
77
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
package/dist/diff.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Line-based unified diff (audit Phase 8 — diff/history view).
3
+ *
4
+ * Zero-dependency LCS over lines producing standard unified format with 2
5
+ * lines of context, so any client that renders `diff -u` output renders our
6
+ * history view for free.
7
+ *
8
+ * Guard: the LCS table is O(n·m) — contents above the cell budget fall back
9
+ * to a coarse whole-block diff instead of allocating hundreds of megabytes.
10
+ */
11
+ /**
12
+ * Unified diff of `prev` → `next`. Empty string when identical.
13
+ * `fromLabel`/`toLabel` name the sides (defaults: previous/current).
14
+ */
15
+ export declare function unifiedDiff(prev: string, next: string, fromLabel?: string, toLabel?: string): string;
package/dist/diff.js ADDED
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Line-based unified diff (audit Phase 8 — diff/history view).
3
+ *
4
+ * Zero-dependency LCS over lines producing standard unified format with 2
5
+ * lines of context, so any client that renders `diff -u` output renders our
6
+ * history view for free.
7
+ *
8
+ * Guard: the LCS table is O(n·m) — contents above the cell budget fall back
9
+ * to a coarse whole-block diff instead of allocating hundreds of megabytes.
10
+ */
11
+ const MAX_CELLS = 4_000_000;
12
+ const CONTEXT = 2;
13
+ function lcsOps(a, b) {
14
+ const n = a.length;
15
+ const m = b.length;
16
+ // dp[i][j] = LCS length of a[i:], b[j:]
17
+ const dp = new Uint32Array((n + 1) * (m + 1));
18
+ for (let i = n - 1; i >= 0; i--) {
19
+ for (let j = m - 1; j >= 0; j--) {
20
+ dp[i * (m + 1) + j] =
21
+ a[i] === b[j] ? dp[(i + 1) * (m + 1) + j + 1] + 1 : Math.max(dp[(i + 1) * (m + 1) + j], dp[i * (m + 1) + j + 1]);
22
+ }
23
+ }
24
+ const ops = [];
25
+ let i = 0;
26
+ let j = 0;
27
+ while (i < n && j < m) {
28
+ if (a[i] === b[j]) {
29
+ ops.push({ kind: "keep", line: a[i] });
30
+ i++;
31
+ j++;
32
+ }
33
+ else if (dp[(i + 1) * (m + 1) + j] >= dp[i * (m + 1) + j + 1]) {
34
+ ops.push({ kind: "remove", line: a[i] });
35
+ i++;
36
+ }
37
+ else {
38
+ ops.push({ kind: "add", line: b[j] });
39
+ j++;
40
+ }
41
+ }
42
+ while (i < n)
43
+ ops.push({ kind: "remove", line: a[i++] });
44
+ while (j < m)
45
+ ops.push({ kind: "add", line: b[j++] });
46
+ return ops;
47
+ }
48
+ /**
49
+ * Unified diff of `prev` → `next`. Empty string when identical.
50
+ * `fromLabel`/`toLabel` name the sides (defaults: previous/current).
51
+ */
52
+ export function unifiedDiff(prev, next, fromLabel = "previous", toLabel = "current") {
53
+ if (prev === next)
54
+ return "";
55
+ const a = prev.split("\n");
56
+ const b = next.split("\n");
57
+ if ((a.length + 1) * (b.length + 1) > MAX_CELLS) {
58
+ // Coarse fallback: claim a full rewrite rather than allocating the table.
59
+ return [
60
+ `--- ${fromLabel}`,
61
+ `+++ ${toLabel}`,
62
+ `@@ -1,${a.length} +1,${b.length} @@ (diff omitted: content too large for line diff)`,
63
+ ...a.map((l) => `-${l}`),
64
+ ...b.map((l) => `+${l}`),
65
+ ].join("\n");
66
+ }
67
+ const ops = lcsOps(a, b);
68
+ const header = [`--- ${fromLabel}`, `+++ ${toLabel}`];
69
+ let out = header.join("\n");
70
+ // Group changed regions (with context) into hunks.
71
+ let idx = 0;
72
+ while (idx < ops.length) {
73
+ if (ops[idx].kind === "keep") {
74
+ idx++;
75
+ continue;
76
+ }
77
+ // Expand over the changed run.
78
+ let end = idx;
79
+ while (end < ops.length) {
80
+ if (ops[end].kind !== "keep") {
81
+ end++;
82
+ continue;
83
+ }
84
+ // Peek: a keep run shorter than 2·context followed by more changes
85
+ // belongs to the same hunk.
86
+ let run = 0;
87
+ let probe = end;
88
+ while (probe < ops.length && ops[probe].kind === "keep") {
89
+ run++;
90
+ probe++;
91
+ }
92
+ if (probe < ops.length && run <= CONTEXT * 2) {
93
+ end = probe; // small keep-gap: bridge it and keep consuming changes
94
+ continue;
95
+ }
96
+ break;
97
+ }
98
+ const start = Math.max(0, idx - CONTEXT);
99
+ const stop = Math.min(ops.length, end + CONTEXT);
100
+ // Line numbers (1-based) for the hunk header.
101
+ let aLine = 0;
102
+ let bLine = 0;
103
+ for (let k = 0; k < start; k++) {
104
+ if (ops[k].kind !== "add")
105
+ aLine++;
106
+ if (ops[k].kind !== "remove")
107
+ bLine++;
108
+ }
109
+ const aStart = aLine + 1;
110
+ const bStart = bLine + 1;
111
+ let aCount = 0;
112
+ let bCount = 0;
113
+ const hunk = [];
114
+ for (let k = start; k < stop; k++) {
115
+ const op = ops[k];
116
+ if (op.kind === "keep") {
117
+ hunk.push(` ${op.line}`);
118
+ aCount++;
119
+ bCount++;
120
+ }
121
+ else if (op.kind === "remove") {
122
+ hunk.push(`-${op.line}`);
123
+ aCount++;
124
+ }
125
+ else {
126
+ hunk.push(`+${op.line}`);
127
+ bCount++;
128
+ }
129
+ }
130
+ out += `\n@@ -${aStart},${aCount} +${bStart},${bCount} @@\n${hunk.join("\n")}`;
131
+ idx = stop;
132
+ }
133
+ return out + "\n";
134
+ }
135
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
package/dist/errors.d.ts CHANGED
@@ -1,11 +1,4 @@
1
- /**
2
- * Structured error classification (audit: Phase 2 — structured error
3
- * classification for store operations).
4
- *
5
- * Every failure that callers should react to carries a stable `code`.
6
- * HTTP maps codes to statuses; MCP tools surface them as `[CODE] message`.
7
- */
8
- export type ErrorCode = "INVALID_INPUT" | "SNAPSHOT_INVALID" | "SCOPE_ESCAPES_ROOT" | "NOT_FOUND" | "CONFLICT" | "LOCK_TIMEOUT" | "IO_ERROR" | "LLM_ERROR";
1
+ export type ErrorCode = "INVALID_INPUT" | "SNAPSHOT_INVALID" | "SCOPE_ESCAPES_ROOT" | "NOT_FOUND" | "CONFLICT" | "LOCK_TIMEOUT" | "IO_ERROR" | "LLM_ERROR" | "ENCRYPTED_NO_KEY";
9
2
  export declare class RemembraError extends Error {
10
3
  readonly code: ErrorCode;
11
4
  constructor(code: ErrorCode, message: string, options?: {
@@ -18,6 +11,8 @@ export declare function statusFor(err: RemembraError): number;
18
11
  export declare function inputError(err: unknown, code: "INVALID_INPUT" | "SNAPSHOT_INVALID"): unknown;
19
12
  /** Uniform single-line rendering for MCP tool failures. */
20
13
  export declare function formatToolError(err: unknown): string;
14
+ /** Stable low-cardinality label for metrics (`remembra_errors_total{code}`). */
15
+ export declare function errorLabel(err: unknown): ErrorCode | "INVALID_INPUT" | "INTERNAL";
21
16
  /** MCP tool error result shape (structural — no SDK import needed). */
22
17
  export declare function toolFail(err: unknown): {
23
18
  content: {
package/dist/errors.js CHANGED
@@ -5,6 +5,7 @@
5
5
  * Every failure that callers should react to carries a stable `code`.
6
6
  * HTTP maps codes to statuses; MCP tools surface them as `[CODE] message`.
7
7
  */
8
+ import { metrics } from "./metrics.js";
8
9
  export class RemembraError extends Error {
9
10
  code;
10
11
  constructor(code, message, options) {
@@ -25,6 +26,7 @@ const HTTP_STATUS = {
25
26
  LOCK_TIMEOUT: 423, // Locked
26
27
  IO_ERROR: 500,
27
28
  LLM_ERROR: 502,
29
+ ENCRYPTED_NO_KEY: 503, // Service Unavailable — storage unreadable without the key
28
30
  };
29
31
  export function statusFor(err) {
30
32
  return HTTP_STATUS[err.code] ?? 500;
@@ -53,8 +55,17 @@ export function formatToolError(err) {
53
55
  return `[INVALID_INPUT] ${zodSummary(err)}`;
54
56
  return `[INTERNAL] ${err instanceof Error ? err.message : String(err)}`;
55
57
  }
58
+ /** Stable low-cardinality label for metrics (`remembra_errors_total{code}`). */
59
+ export function errorLabel(err) {
60
+ if (isRemembraError(err))
61
+ return err.code;
62
+ if (isZodLike(err))
63
+ return "INVALID_INPUT";
64
+ return "INTERNAL";
65
+ }
56
66
  /** MCP tool error result shape (structural — no SDK import needed). */
57
67
  export function toolFail(err) {
68
+ metrics.inc("remembra_errors_total", { code: errorLabel(err), transport: "mcp" });
58
69
  return { content: [{ type: "text", text: formatToolError(err) }], isError: true };
59
70
  }
60
71
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAE3B;IADX,YACW,IAAe,EACxB,OAAe,EACf,OAA6B;QAE7B,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAJf,SAAI,GAAJ,IAAI,CAAW;QAKxB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,OAAO,GAAG,YAAY,aAAa,CAAC;AACtC,CAAC;AAED,MAAM,WAAW,GAA8B;IAC7C,aAAa,EAAE,GAAG;IAClB,gBAAgB,EAAE,GAAG;IACrB,kBAAkB,EAAE,GAAG;IACvB,SAAS,EAAE,GAAG;IACd,QAAQ,EAAE,GAAG;IACb,YAAY,EAAE,GAAG,EAAE,SAAS;IAC5B,QAAQ,EAAE,GAAG;IACb,SAAS,EAAE,GAAG;CACf,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,GAAkB;IAC1C,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;AACtC,CAAC;AAED,SAAS,UAAU,CAAC,GAAkE;IACpF,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IACjE,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;IACrD,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,MAAM,MAAM,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,EAAE,CAAC;AACpG,CAAC;AAED,SAAS,SAAS,CAAC,GAAY;IAC7B,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAK,GAA0B,CAAC,IAAI,KAAK,UAAU,CAAC;AACpG,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,UAAU,CAAC,GAAY,EAAE,IAA0C;IACjF,IAAI,SAAS,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACpF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,IAAI,eAAe,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;IAChE,IAAI,SAAS,CAAC,GAAG,CAAC;QAAE,OAAO,mBAAmB,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;IAChE,OAAO,cAAc,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AAC1E,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,QAAQ,CAAC,GAAY;IAInC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACpF,CAAC"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts CHANGED
@@ -23,12 +23,16 @@ export declare function resolveListen(host: string | undefined, hasKey: boolean)
23
23
  * Minimal HTTP API over the same handlers the MCP tools use.
24
24
  *
25
25
  * Routes:
26
- * GET /health → liveness (no auth)
26
+ * GET /health → liveness + readiness (no auth): 200 ok / 503 unready
27
+ * GET /metrics → Prometheus text format (auth when keyed)
27
28
  * POST /memories → store a memory
28
29
  * GET /memories/search → ?query=&scope=&type=&limit=
29
30
  * GET /memories → ?scope=&type=&includeArchived=&offset=&limit=
30
31
  * POST /memories/digest → LLM extraction
31
32
  * POST /maintain → decay sweep + vector backfill
33
+ * GET /memories/:id → one memory + related + backlinks (Phase 8)
34
+ * POST /memories/:id/relate → link/unlink memories (Phase 8)
35
+ * GET /memories/:id/history→ version history + line diffs (Phase 8)
32
36
  * DELETE /memories/:id → forget
33
37
  */
34
38
  export declare function createHttpServer(service: MemoryService, opts?: HttpOptions): http.Server;