@hilbras/remembra 3.1.0 → 3.3.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/CHANGELOG.md +79 -0
- package/README.md +15 -0
- package/dist/backend.d.ts +27 -0
- package/dist/backend.js +2 -0
- package/dist/backend.js.map +1 -0
- package/dist/errors.d.ts +28 -0
- package/dist/errors.js +60 -0
- package/dist/errors.js.map +1 -0
- package/dist/http.js +16 -7
- package/dist/http.js.map +1 -1
- package/dist/index.js +117 -62
- package/dist/index.js.map +1 -1
- package/dist/service.d.ts +28 -4
- package/dist/service.js +94 -11
- package/dist/service.js.map +1 -1
- package/dist/store.d.ts +39 -5
- package/dist/store.js +343 -85
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +183 -5
- package/dist/types.js +78 -14
- package/dist/types.js.map +1 -1
- package/docs/architecture.md +98 -0
- package/docs/clients.md +3 -0
- package/docs/security.md +12 -7
- package/docs/tools.md +11 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,85 @@ 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.3.0] — 2026-09-23
|
|
11
|
+
|
|
12
|
+
**Phase 3 of the deep audit** — architecture: swappable backend, cross-process
|
|
13
|
+
locking, crash recovery, structured errors.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **`MemoryBackend` interface** (`src/backend.ts`) — `MemoryService` now
|
|
17
|
+
depends on the storage contract, not the file store; a DB backend can be
|
|
18
|
+
dropped in without touching service/transport code. Tested against an
|
|
19
|
+
in-memory implementation. Fixes audit Phase 3 item.
|
|
20
|
+
- **Advisory file locking** — `<root>/.remembra.lock` (`O_EXCL` create) around
|
|
21
|
+
every mutation *including its read*, plus an in-process FIFO queue. Stale
|
|
22
|
+
locks (dead pid or older than `REMEMBRA_LOCK_STALE_MS`) are stolen;
|
|
23
|
+
waiters fail with typed `LOCK_TIMEOUT` after `REMEMBRA_LOCK_TIMEOUT_MS`.
|
|
24
|
+
Fixes audit Phase 2 item (concurrent writers) and closes the
|
|
25
|
+
touch-vs-archive resurrection window.
|
|
26
|
+
- **Crash-recovery pass** (the audit's "journal", recovery-pass flavor —
|
|
27
|
+
documented rationale in `docs/architecture.md`): on first access per
|
|
28
|
+
process, deletes orphaned `*.tmp` files and reconciles ids left in *both*
|
|
29
|
+
active and archived trees by an interrupted archive/revive (finding #19);
|
|
30
|
+
newest `updatedAt` wins. Logged when it does anything.
|
|
31
|
+
- **Structured error classification** — `RemembraError` with stable codes
|
|
32
|
+
(`INVALID_INPUT`, `SNAPSHOT_INVALID`, `SCOPE_ESCAPES_ROOT`, `NOT_FOUND`,
|
|
33
|
+
`CONFLICT`, `LOCK_TIMEOUT`, `IO_ERROR`, `LLM_ERROR`). HTTP maps codes →
|
|
34
|
+
statuses and includes `code` in error bodies (423 for locked, 502 for LLM
|
|
35
|
+
failures); MCP tools return `[CODE] message` with `isError: true`; raw fs
|
|
36
|
+
failures wrap as `IO_ERROR`. Fixes audit Phase 2 item.
|
|
37
|
+
- **`docs/architecture.md`** — backend seam, locking model, recovery pass,
|
|
38
|
+
error-code table, schema-versioning notes.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- `archive()` now bumps `updatedAt` (state change updates recency; also makes
|
|
42
|
+
crash-recovery tie-breaks deterministic).
|
|
43
|
+
- All six MCP tool handlers catch and classify failures instead of throwing
|
|
44
|
+
through the SDK.
|
|
45
|
+
|
|
46
|
+
### Added (tests)
|
|
47
|
+
15 Phase-3 tests: non-file backend swappability, lock release/steal/timeout,
|
|
48
|
+
HTTP 423, mixed-concurrency single-tree invariant, tmp + both recovery
|
|
49
|
+
directions, error codes on every boundary, `formatToolError`/`statusFor`
|
|
50
|
+
units. **86/86 total.**
|
|
51
|
+
|
|
52
|
+
## [3.2.0] — 2026-09-23
|
|
53
|
+
|
|
54
|
+
**Phase 2 of the deep audit** — data integrity, portability, and shared schemas.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
- **`remembra export <file>.json` / `remembra import <file>.json`** — full
|
|
58
|
+
snapshot backup incl. archived memories. Import validates the *whole* file
|
|
59
|
+
before writing (atomic rollback on any invalid entry) and is idempotent
|
|
60
|
+
(existing ids and exact duplicates are skipped). Fixes audit #8.
|
|
61
|
+
- **Schema version field** — every memory file now carries `version: 1` in
|
|
62
|
+
frontmatter; files without it (v1–v3.1) parse as v1. Fixes audit #10.
|
|
63
|
+
- `REMEMBRA_DEBUG=1` — opt-in storage-root path logging.
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
- **Log hygiene (audit #7)**: startup no longer prints the storage root path
|
|
67
|
+
(gated behind `REMEMBRA_DEBUG`); embedding errors truncated to 200 chars;
|
|
68
|
+
swallowed `touch()` errors now logged (audit #15); unparseable memory files
|
|
69
|
+
warn once instead of being silently skipped.
|
|
70
|
+
- **Simultaneous digests** — digest runs are serialized through a lock, so
|
|
71
|
+
parallel sessions can no longer double-store duplicates.
|
|
72
|
+
- **Merge LLM failure fails open** — a failed merge stores the new fact fresh
|
|
73
|
+
instead of aborting the digest mid-way (never lose data).
|
|
74
|
+
- **Shared input schemas (audit #13)** — MCP tools, HTTP routes and the
|
|
75
|
+
service all parse the same Zod shapes from `types.ts` (single source of
|
|
76
|
+
truth; the `type` enum is no longer declared twice).
|
|
77
|
+
- `?limit=abc` on `/memories/search` no longer yields empty results (NaN guard).
|
|
78
|
+
|
|
79
|
+
### Changed
|
|
80
|
+
- MCP `memory_store` now applies `.default()` for `tags`/`importance` at the
|
|
81
|
+
schema layer (behavior unchanged; validation moved to shared schemas).
|
|
82
|
+
|
|
83
|
+
### Added (tests)
|
|
84
|
+
12 Phase-2 tests: schema version + backward compat, malformed-file recovery,
|
|
85
|
+
empty transcript, extraction rollback, merge fail-open, parallel stores,
|
|
86
|
+
serialized digests, export/import round-trip, cross-id dedup, atomic import
|
|
87
|
+
rollback. **71/71 total.**
|
|
88
|
+
|
|
10
89
|
## [3.1.0] — 2026-09-23
|
|
11
90
|
|
|
12
91
|
**Security hardening** in response to the deep audit (`HILBRAS-MEMORY-DEEP-AUDIT.md`).
|
package/README.md
CHANGED
|
@@ -101,6 +101,20 @@ All routes except `/health` require `x-api-key` (or `Authorization: Bearer`) whe
|
|
|
101
101
|
> to start. Public deployments (ChatGPT) must set a key. See
|
|
102
102
|
> [security.md](docs/security.md).
|
|
103
103
|
|
|
104
|
+
## Backup & restore
|
|
105
|
+
|
|
106
|
+
Your memories are plain files under `~/.remembra` — plus a portable snapshot
|
|
107
|
+
format for moving between machines or disaster recovery:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
remembra export memories.json # full snapshot (incl. archived)
|
|
111
|
+
remembra import memories.json # idempotent: existing ids/dups skipped
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Import validates the **whole file before writing anything** — a corrupt or
|
|
115
|
+
tampered snapshot is rejected atomically, never half-imported. Of course,
|
|
116
|
+
`rsync`/`git` on `~/.remembra` works too.
|
|
117
|
+
|
|
104
118
|
## Tools
|
|
105
119
|
|
|
106
120
|
| Tool | Purpose |
|
|
@@ -125,6 +139,7 @@ Full reference: **[docs/tools.md](docs/tools.md)**
|
|
|
125
139
|
| [AI providers](docs/providers.md) | Digest LLM + embeddings configuration |
|
|
126
140
|
| [Lifecycle](docs/lifecycle.md) | Decay, archiving, auto-delete, contradiction merging |
|
|
127
141
|
| [Security](docs/security.md) | Trust model, enforced protections, deployment checklist |
|
|
142
|
+
| [Architecture](docs/architecture.md) | Backend interface, locking, crash recovery, error codes |
|
|
128
143
|
| [Contributing](CONTRIBUTING.md) | Dev workflow and guidelines |
|
|
129
144
|
| [Changelog](CHANGELOG.md) | Release history |
|
|
130
145
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Memory, StoreInput } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Storage abstraction (audit: Phase 3 — separate MemoryStore abstraction to
|
|
4
|
+
* enable a future DB swap).
|
|
5
|
+
*
|
|
6
|
+
* `MemoryService` only ever talks to this contract. `MemoryStore` is the
|
|
7
|
+
* file-backed implementation shipped today; a SQLite/vector-DB backend would
|
|
8
|
+
* only need to satisfy this interface (see docs/architecture.md).
|
|
9
|
+
*
|
|
10
|
+
* Concurrency contract for implementations:
|
|
11
|
+
* - mutating calls must be safe under same-process concurrency (queueing) and
|
|
12
|
+
* cross-process concurrency (advisory lock) — a caller may issue `touch()`
|
|
13
|
+
* while another process runs `archive()`;
|
|
14
|
+
* - a memory id must exist in exactly one tree at rest;
|
|
15
|
+
* - `importMemory` must refuse ids that already exist (return false).
|
|
16
|
+
*/
|
|
17
|
+
export interface MemoryBackend {
|
|
18
|
+
store(input: StoreInput, embedding?: number[]): Promise<Memory>;
|
|
19
|
+
get(id: string): Promise<Memory | null>;
|
|
20
|
+
all(includeArchived?: boolean): Promise<Memory[]>;
|
|
21
|
+
update(memory: Memory): Promise<Memory>;
|
|
22
|
+
archive(id: string): Promise<Memory | null>;
|
|
23
|
+
revive(id: string): Promise<Memory | null>;
|
|
24
|
+
touch(id: string): Promise<void>;
|
|
25
|
+
forget(id: string): Promise<boolean>;
|
|
26
|
+
importMemory(m: Memory): Promise<boolean>;
|
|
27
|
+
}
|
package/dist/backend.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":""}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
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";
|
|
9
|
+
export declare class RemembraError extends Error {
|
|
10
|
+
readonly code: ErrorCode;
|
|
11
|
+
constructor(code: ErrorCode, message: string, options?: {
|
|
12
|
+
cause?: unknown;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export declare function isRemembraError(err: unknown): err is RemembraError;
|
|
16
|
+
export declare function statusFor(err: RemembraError): number;
|
|
17
|
+
/** Re-throw Zod failures as a classified error; pass anything else through. */
|
|
18
|
+
export declare function inputError(err: unknown, code: "INVALID_INPUT" | "SNAPSHOT_INVALID"): unknown;
|
|
19
|
+
/** Uniform single-line rendering for MCP tool failures. */
|
|
20
|
+
export declare function formatToolError(err: unknown): string;
|
|
21
|
+
/** MCP tool error result shape (structural — no SDK import needed). */
|
|
22
|
+
export declare function toolFail(err: unknown): {
|
|
23
|
+
content: {
|
|
24
|
+
type: "text";
|
|
25
|
+
text: string;
|
|
26
|
+
}[];
|
|
27
|
+
isError: true;
|
|
28
|
+
};
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
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 class RemembraError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
constructor(code, message, options) {
|
|
11
|
+
super(message, options);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.name = "RemembraError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function isRemembraError(err) {
|
|
17
|
+
return err instanceof RemembraError;
|
|
18
|
+
}
|
|
19
|
+
const HTTP_STATUS = {
|
|
20
|
+
INVALID_INPUT: 400,
|
|
21
|
+
SNAPSHOT_INVALID: 400,
|
|
22
|
+
SCOPE_ESCAPES_ROOT: 400,
|
|
23
|
+
NOT_FOUND: 404,
|
|
24
|
+
CONFLICT: 409,
|
|
25
|
+
LOCK_TIMEOUT: 423, // Locked
|
|
26
|
+
IO_ERROR: 500,
|
|
27
|
+
LLM_ERROR: 502,
|
|
28
|
+
};
|
|
29
|
+
export function statusFor(err) {
|
|
30
|
+
return HTTP_STATUS[err.code] ?? 500;
|
|
31
|
+
}
|
|
32
|
+
function zodSummary(err) {
|
|
33
|
+
const issues = err.issues ?? [];
|
|
34
|
+
const first = issues[0];
|
|
35
|
+
const where = first ? first.path.join(".") || "(root)" : "input";
|
|
36
|
+
const what = first ? first.message : "invalid input";
|
|
37
|
+
return issues.length > 1 ? `${where}: ${what} (+${issues.length - 1} more)` : `${where}: ${what}`;
|
|
38
|
+
}
|
|
39
|
+
function isZodLike(err) {
|
|
40
|
+
return typeof err === "object" && err !== null && err.name === "ZodError";
|
|
41
|
+
}
|
|
42
|
+
/** Re-throw Zod failures as a classified error; pass anything else through. */
|
|
43
|
+
export function inputError(err, code) {
|
|
44
|
+
if (isZodLike(err))
|
|
45
|
+
return new RemembraError(code, zodSummary(err), { cause: err });
|
|
46
|
+
return err;
|
|
47
|
+
}
|
|
48
|
+
/** Uniform single-line rendering for MCP tool failures. */
|
|
49
|
+
export function formatToolError(err) {
|
|
50
|
+
if (isRemembraError(err))
|
|
51
|
+
return `[${err.code}] ${err.message}`;
|
|
52
|
+
if (isZodLike(err))
|
|
53
|
+
return `[INVALID_INPUT] ${zodSummary(err)}`;
|
|
54
|
+
return `[INTERNAL] ${err instanceof Error ? err.message : String(err)}`;
|
|
55
|
+
}
|
|
56
|
+
/** MCP tool error result shape (structural — no SDK import needed). */
|
|
57
|
+
export function toolFail(err) {
|
|
58
|
+
return { content: [{ type: "text", text: formatToolError(err) }], isError: true };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +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"}
|
package/dist/http.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import http from "node:http";
|
|
2
2
|
import { timingSafeEqual } from "node:crypto";
|
|
3
3
|
import { DigestInput } from "./types.js";
|
|
4
|
+
import { isRemembraError, statusFor } from "./errors.js";
|
|
4
5
|
const DEFAULT_MAX_BODY = 10 * 1024 * 1024; // transcripts can be large — 10 MiB
|
|
5
6
|
/**
|
|
6
7
|
* Listen policy (P1 audit: default-deny):
|
|
@@ -66,11 +67,13 @@ export function createHttpServer(service, opts = {}) {
|
|
|
66
67
|
}
|
|
67
68
|
// GET /memories/search
|
|
68
69
|
if (req.method === "GET" && path === "/memories/search") {
|
|
70
|
+
const rawLimit = url.searchParams.get("limit");
|
|
71
|
+
const limit = rawLimit && Number.isFinite(Number(rawLimit)) ? Number(rawLimit) : undefined;
|
|
69
72
|
const result = await service.search({
|
|
70
73
|
query: url.searchParams.get("query") ?? url.searchParams.get("q") ?? undefined,
|
|
71
74
|
scope: url.searchParams.get("scope") ?? undefined,
|
|
72
75
|
type: url.searchParams.get("type") ?? undefined,
|
|
73
|
-
limit
|
|
76
|
+
limit,
|
|
74
77
|
});
|
|
75
78
|
return send(res, 200, result);
|
|
76
79
|
}
|
|
@@ -93,12 +96,18 @@ export function createHttpServer(service, opts = {}) {
|
|
|
93
96
|
}
|
|
94
97
|
catch (err) {
|
|
95
98
|
const name = err.name;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
// Structured classification: typed errors carry a stable code → status.
|
|
100
|
+
const status = isRemembraError(err)
|
|
101
|
+
? statusFor(err)
|
|
102
|
+
: name === "ZodError" || name === "BadRequestError"
|
|
103
|
+
? 400
|
|
104
|
+
: name === "PayloadTooLarge"
|
|
105
|
+
? 413
|
|
106
|
+
: 500;
|
|
107
|
+
send(res, status, {
|
|
108
|
+
error: err instanceof Error ? err.message : String(err),
|
|
109
|
+
...(isRemembraError(err) ? { code: err.code } : {}),
|
|
110
|
+
});
|
|
102
111
|
}
|
|
103
112
|
});
|
|
104
113
|
const port = opts.port ?? Number(process.env.REMEMBRA_PORT ?? 8787);
|
package/dist/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAYzD,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,oCAAoC;AAE/E;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAwB,EACxB,MAAe;IAEf,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,QAAQ,GAAG,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK,KAAK,CAAC;QACnF,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YACzB,OAAO;gBACL,KAAK,EAAE,yBAAyB,IAAI,6DAA6D;aAClG,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAsB,EAAE,OAAoB,EAAE;IAC7E,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,gBAAgB,CAAC,CAAC;IAC/F,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACjG,IAAI,YAAY,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAE5D,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAClD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;YAErD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1C,CAAC;YAED,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACjD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,0CAA0C,EAAE,CAAC,CAAC;YAC/E,CAAC;YAED,iDAAiD;YACjD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gBAClD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YAChC,CAAC;YAED,+EAA+E;YAC/E,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBACzD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;gBAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC7D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YAChC,CAAC;YAED,iBAAiB;YACjB,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gBAClD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;gBAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACzC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YAChC,CAAC;YAED,uBAAuB;YACvB,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBACxD,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC/C,MAAM,KAAK,GAAG,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC3F,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC;oBAClC,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,SAAS;oBAC9E,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS;oBACjD,IAAI,EAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAW,IAAI,SAAS;oBAC1D,KAAK;iBACN,CAAC,CAAC;gBACH,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YAChC,CAAC;YAED,gBAAgB;YAChB,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gBACjD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;oBAChC,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS;oBACjD,IAAI,EAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAW,IAAI,SAAS;oBAC1D,eAAe,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,MAAM;iBACpE,CAAC,CAAC;gBACH,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YAChC,CAAC;YAED,uBAAuB;YACvB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAChD,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,EAAE,CAAC;gBACnC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChE,OAAO,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAClD,CAAC;YAED,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,GAAI,GAAyB,CAAC,IAAI,CAAC;YAC7C,wEAAwE;YACxE,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC;gBACjC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC;gBAChB,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,iBAAiB;oBACjD,CAAC,CAAC,GAAG;oBACL,CAAC,CAAC,IAAI,KAAK,iBAAiB;wBAC1B,CAAC,CAAC,GAAG;wBACL,CAAC,CAAC,GAAG,CAAC;YACZ,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE;gBAChB,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;gBACvD,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACpD,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC;IAClC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE;QAChC,MAAM,KAAK,GAAG,OAAO,IAAI,SAAS,CAAC;QACnC,OAAO,CAAC,KAAK,CACX,kCAAkC,KAAK,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,4BAA4B,EAAE,CACpH,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wEAAwE;AACxE,SAAS,UAAU,CAAC,GAAyB,EAAE,GAAW;IACxD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IACvC,MAAM,QAAQ,GACZ,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QACjD,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC5D,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACzC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QAC1B,uEAAuE;QACvE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,IAAI,CAAC,GAAwB,EAAE,MAAc,EAAE,IAAa;IACnE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACpB,cAAc,EAAE,iCAAiC;QACjD,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;KAC1C,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,QAAQ,CAAC,GAAyB,EAAE,QAAgB;IAC3D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5D,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,QAAQ,EAAE,CAAC;YACrD,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,iCAAiC,QAAQ,SAAS,CAAC,CAAC;YAC1E,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC;YAC7B,MAAM,CAAC,GAAG,CAAC,CAAC;YACZ,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE;YAC3B,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;YAClB,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;gBACrB,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,iCAAiC,QAAQ,SAAS,CAAC,CAAC;gBAC1E,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC;gBAC7B,MAAM,CAAC,GAAG,CAAC,CAAC;gBACZ,GAAG,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACnD,IAAI,CAAC,GAAG;gBAAE,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7B,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACzC,CAAC,CAAC,IAAI,GAAG,iBAAiB,CAAC;gBAC3B,MAAM,CAAC,CAAC,CAAC,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,58 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
2
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
-
import { z } from "zod";
|
|
5
5
|
import { MemoryStore } from "./store.js";
|
|
6
6
|
import { MemoryService } from "./service.js";
|
|
7
7
|
import { createHttpServer } from "./http.js";
|
|
8
|
-
import { DigestInput } from "./types.js";
|
|
8
|
+
import { DigestInput, storeInputShape, digestInputShape, searchInputShape, listInputShape, forgetInputShape, } from "./types.js";
|
|
9
|
+
import { toolFail } from "./errors.js";
|
|
9
10
|
const store = new MemoryStore(MemoryStore.defaultRoot());
|
|
10
11
|
const service = new MemoryService(store);
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
12
|
+
const argv = process.argv.slice(2);
|
|
13
|
+
const httpFlag = argv.includes("--http");
|
|
14
|
+
const maintainFlag = argv.includes("maintain");
|
|
15
|
+
const portArg = argv.indexOf("--port");
|
|
16
|
+
const port = portArg !== -1 ? Number(argv[portArg + 1]) : undefined;
|
|
17
|
+
if (argv[0] === "export") {
|
|
18
|
+
// CLI backup: `remembra export <file.json>` — full snapshot incl. archived.
|
|
19
|
+
const out = argv[1];
|
|
20
|
+
if (!out) {
|
|
21
|
+
console.error("Usage: remembra export <file.json>");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
const snapshot = await service.exportSnapshot();
|
|
25
|
+
await fs.writeFile(out, JSON.stringify(snapshot, null, 2), "utf8");
|
|
26
|
+
console.log(`Exported ${snapshot.memories.length} memories to ${out}`);
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
else if (argv[0] === "import") {
|
|
30
|
+
// CLI restore: `remembra import <file.json>` — validates whole file first,
|
|
31
|
+
// then skips existing ids/duplicates (idempotent re-import).
|
|
32
|
+
const input = argv[1];
|
|
33
|
+
if (!input) {
|
|
34
|
+
console.error("Usage: remembra import <file.json>");
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
let data;
|
|
38
|
+
try {
|
|
39
|
+
data = JSON.parse(await fs.readFile(input, "utf8"));
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
console.error(`Cannot read snapshot ${input}: ${err instanceof Error ? err.message : err}`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const result = await service.importSnapshot(data);
|
|
47
|
+
console.log(`Import: ${result.imported} imported, ${result.skipped} skipped`);
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.error(`Import rejected (nothing written): ${err instanceof Error ? err.message : err}`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (maintainFlag) {
|
|
16
56
|
// CLI maintenance: `remembra maintain` — one-shot, prints JSON, exits.
|
|
17
57
|
const result = await service.maintain();
|
|
18
58
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -20,55 +60,57 @@ if (maintainFlag) {
|
|
|
20
60
|
}
|
|
21
61
|
else if (httpFlag) {
|
|
22
62
|
// HTTP mode: long-running API for non-MCP clients (ChatGPT, scripts, ...).
|
|
23
|
-
createHttpServer(service, {
|
|
63
|
+
const httpServer = createHttpServer(service, {
|
|
24
64
|
port,
|
|
25
65
|
apiKey: process.env.REMEMBRA_API_KEY,
|
|
26
66
|
});
|
|
67
|
+
// Graceful shutdown: stop accepting, drain in-flight requests, then exit.
|
|
68
|
+
const shutdown = (sig) => {
|
|
69
|
+
console.error(`Remembra: received ${sig}, shutting down`);
|
|
70
|
+
httpServer.close(() => process.exit(0));
|
|
71
|
+
setTimeout(() => process.exit(0), 3000).unref();
|
|
72
|
+
};
|
|
73
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
74
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
27
75
|
}
|
|
28
76
|
else {
|
|
29
77
|
// MCP mode (default): stdio transport launched by an MCP client.
|
|
30
78
|
await startMcp();
|
|
31
79
|
}
|
|
32
80
|
async function startMcp() {
|
|
33
|
-
const server = new McpServer({ name: "remembra", version: "3.
|
|
81
|
+
const server = new McpServer({ name: "remembra", version: "3.3.0" });
|
|
34
82
|
server.registerTool("memory_store", {
|
|
35
83
|
title: "Store a memory",
|
|
36
84
|
description: "Persist a fact, decision, role or history entry so it survives context window resets. " +
|
|
37
85
|
"Use type 'fact' for stable knowledge, 'decision' for choices already made, " +
|
|
38
86
|
"'role' for standing instructions/roles, 'history' for condensed chronology of past work.",
|
|
39
|
-
inputSchema:
|
|
40
|
-
type: z.enum(["fact", "decision", "role", "history"]),
|
|
41
|
-
content: z.string().describe("The memory itself, written as a standalone statement"),
|
|
42
|
-
scope: z
|
|
43
|
-
.string()
|
|
44
|
-
.optional()
|
|
45
|
-
.describe("'global' for always-relevant memories, or a project path/id for project-scoped ones"),
|
|
46
|
-
tags: z.array(z.string()).optional(),
|
|
47
|
-
importance: z.number().int().min(1).max(5).optional().describe("1=minor, 5=critical (default 3)"),
|
|
48
|
-
source: z.string().optional().describe("Originating session or client"),
|
|
49
|
-
},
|
|
87
|
+
inputSchema: storeInputShape,
|
|
50
88
|
}, async (args) => {
|
|
51
|
-
|
|
52
|
-
|
|
89
|
+
try {
|
|
90
|
+
const result = await service.store(args);
|
|
91
|
+
return { content: [{ type: "text", text: result.message }] };
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
return toolFail(err);
|
|
95
|
+
}
|
|
53
96
|
});
|
|
54
97
|
server.registerTool("memory_digest", {
|
|
55
98
|
title: "Digest a session",
|
|
56
99
|
description: "Extract facts, decisions, roles and history from a conversation transcript and store " +
|
|
57
100
|
"them automatically (exact duplicates are skipped). Call at the end of a session with " +
|
|
58
101
|
"the transcript or a detailed summary of it. Requires REMEMBRA_LLM + an API key.",
|
|
59
|
-
inputSchema:
|
|
60
|
-
transcript: z
|
|
61
|
-
.string()
|
|
62
|
-
.describe("Conversation transcript or a detailed summary of the session"),
|
|
63
|
-
scope: z.string().optional().describe("Scope for extracted memories (default: global)"),
|
|
64
|
-
source: z.string().optional().describe("Originating session/client"),
|
|
65
|
-
},
|
|
102
|
+
inputSchema: digestInputShape,
|
|
66
103
|
}, async (args) => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
104
|
+
try {
|
|
105
|
+
const result = await service.digest(DigestInput.parse(args));
|
|
106
|
+
const text = `Digest complete: ${result.extracted} extracted, ${result.stored.length} stored, ` +
|
|
107
|
+
`${result.merged} merged/revived, ${result.skippedDuplicates} duplicates skipped.` +
|
|
108
|
+
(result.ids.length ? `\nStored ids: ${result.ids.join(", ")}` : "");
|
|
109
|
+
return { content: [{ type: "text", text }] };
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
return toolFail(err);
|
|
113
|
+
}
|
|
72
114
|
});
|
|
73
115
|
server.registerTool("memory_maintain", {
|
|
74
116
|
title: "Run maintenance",
|
|
@@ -77,52 +119,65 @@ async function startMcp() {
|
|
|
77
119
|
"missing embedding vectors. Roles never decay. Safe to call anytime.",
|
|
78
120
|
inputSchema: {},
|
|
79
121
|
}, async () => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
122
|
+
try {
|
|
123
|
+
const result = await service.maintain();
|
|
124
|
+
const text = `Maintenance complete: ${result.archived.length} archived, ` +
|
|
125
|
+
`${result.deleted.length} deleted, ${result.embedded} vectors backfilled.` +
|
|
126
|
+
(result.archived.length ? `\nArchived: ${result.archived.join(", ")}` : "") +
|
|
127
|
+
(result.deleted.length ? `\nDeleted: ${result.deleted.join(", ")}` : "");
|
|
128
|
+
return { content: [{ type: "text", text }] };
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
return toolFail(err);
|
|
132
|
+
}
|
|
86
133
|
});
|
|
87
134
|
server.registerTool("memory_search", {
|
|
88
135
|
title: "Search memories",
|
|
89
136
|
description: "Retrieve relevant memories from external storage. Call this at the start of a session " +
|
|
90
137
|
"(or whenever prior context might exist) to recover facts, decisions, roles and history.",
|
|
91
|
-
inputSchema:
|
|
92
|
-
query: z.string().optional().describe("Keywords to match (omit to get a scope/recency-ranked list)"),
|
|
93
|
-
scope: z.string().optional().describe("Current project path or workspace id to filter by"),
|
|
94
|
-
type: z.enum(["fact", "decision", "role", "history"]).optional(),
|
|
95
|
-
limit: z.number().int().min(1).max(50).optional(),
|
|
96
|
-
},
|
|
138
|
+
inputSchema: searchInputShape,
|
|
97
139
|
}, async (args) => {
|
|
98
|
-
|
|
99
|
-
|
|
140
|
+
try {
|
|
141
|
+
const result = await service.search(args);
|
|
142
|
+
return { content: [{ type: "text", text: result.text }] };
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
return toolFail(err);
|
|
146
|
+
}
|
|
100
147
|
});
|
|
101
148
|
server.registerTool("memory_list", {
|
|
102
149
|
title: "List memories",
|
|
103
150
|
description: "List stored memories, optionally filtered by scope or type.",
|
|
104
|
-
inputSchema:
|
|
105
|
-
scope: z.string().optional(),
|
|
106
|
-
type: z.enum(["fact", "decision", "role", "history"]).optional(),
|
|
107
|
-
includeArchived: z.boolean().optional().describe("Include archived memories (flagged)"),
|
|
108
|
-
},
|
|
151
|
+
inputSchema: listInputShape,
|
|
109
152
|
}, async (args) => {
|
|
110
|
-
|
|
111
|
-
|
|
153
|
+
try {
|
|
154
|
+
const result = await service.list(args);
|
|
155
|
+
return { content: [{ type: "text", text: result.text }] };
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
return toolFail(err);
|
|
159
|
+
}
|
|
112
160
|
});
|
|
113
161
|
server.registerTool("memory_forget", {
|
|
114
162
|
title: "Delete a memory",
|
|
115
163
|
description: "Permanently delete a memory by its id.",
|
|
116
|
-
inputSchema:
|
|
164
|
+
inputSchema: forgetInputShape,
|
|
117
165
|
}, async ({ id }) => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
166
|
+
try {
|
|
167
|
+
const result = await service.forget(id);
|
|
168
|
+
return {
|
|
169
|
+
content: [{ type: "text", text: result.text }],
|
|
170
|
+
isError: !result.ok,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
return toolFail(err);
|
|
175
|
+
}
|
|
123
176
|
});
|
|
124
177
|
const transport = new StdioServerTransport();
|
|
125
178
|
await server.connect(transport);
|
|
126
|
-
|
|
179
|
+
// Log hygiene (audit #7): filesystem paths only under REMEMBRA_DEBUG.
|
|
180
|
+
const rootNote = process.env.REMEMBRA_DEBUG ? ` (root: ${MemoryStore.defaultRoot()})` : "";
|
|
181
|
+
console.error(`Remembra MCP server running${rootNote}`);
|
|
127
182
|
}
|
|
128
183
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|