hippo-memory 0.34.0 → 0.36.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 +17 -0
- package/dist/api.d.ts +163 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +323 -0
- package/dist/api.js.map +1 -0
- package/dist/audit.d.ts +26 -0
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +45 -0
- package/dist/audit.js.map +1 -1
- package/dist/auth.d.ts +28 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +65 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.js +457 -19
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +54 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +181 -0
- package/dist/client.js.map +1 -0
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/dashboard.js +5 -1
- package/dist/dashboard.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +60 -1
- package/dist/db.js.map +1 -1
- package/dist/mcp/server.d.ts +46 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +81 -29
- package/dist/mcp/server.js.map +1 -1
- package/dist/memory.d.ts +2 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +1 -0
- package/dist/memory.js.map +1 -1
- package/dist/raw-archive.d.ts.map +1 -1
- package/dist/raw-archive.js +19 -0
- package/dist/raw-archive.js.map +1 -1
- package/dist/server-detect.d.ts +26 -0
- package/dist/server-detect.d.ts.map +1 -0
- package/dist/server-detect.js +70 -0
- package/dist/server-detect.js.map +1 -0
- package/dist/server.d.ts +29 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +612 -0
- package/dist/server.js.map +1 -0
- package/dist/shared.d.ts +5 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +8 -8
- package/dist/shared.js.map +1 -1
- package/dist/sso.d.ts +13 -0
- package/dist/sso.d.ts.map +1 -0
- package/dist/sso.js +22 -0
- package/dist/sso.js.map +1 -0
- package/dist/store.d.ts +29 -5
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +98 -22
- package/dist/store.js.map +1 -1
- package/dist/tenant.d.ts +7 -0
- package/dist/tenant.d.ts.map +1 -0
- package/dist/tenant.js +17 -0
- package/dist/tenant.js.map +1 -0
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,6 +60,23 @@ hippo recall "data pipeline issues" --budget 2000
|
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
63
|
+
### What's new in v0.36.0
|
|
64
|
+
|
|
65
|
+
- **`hippo serve` daemon.** Persistent HTTP server on 127.0.0.1:6789. CLI auto-detects and becomes a thin client; one process owns the SQLite DB.
|
|
66
|
+
- **MCP-over-HTTP.** MCP clients can now connect over HTTP/SSE in addition to stdio. Same tool surface.
|
|
67
|
+
- **Bearer-token auth + loopback trust.** Set HIPPO_API_KEY for remote calls; loopback connections work without a key. Server refuses to bind to non-loopback host without auth.
|
|
68
|
+
- **Audit log fix.** Mutations on non-default tenants are now correctly attributed in the audit log (was using HIPPO_TENANT env, now uses the row's tenant_id).
|
|
69
|
+
- **Tenant deny on archive/forget.** A valid Bearer for tenant A can no longer affect tenant B's memories, cross-tenant requests return "memory not found".
|
|
70
|
+
- **Known issue:** p99 recall latency is 58.4ms on a 10k store, target is 50ms. Architecture ships; latency hardening in v0.37.0.
|
|
71
|
+
|
|
72
|
+
### What's new in v0.35.0
|
|
73
|
+
|
|
74
|
+
- **Stub auth landed.** API keys + audit log + per-tenant data isolation. `hippo auth create` mints a scrypt-hashed key shown plaintext exactly once. `hippo audit list` exposes the mutation trail.
|
|
75
|
+
- **Cross-tenant safety.** Set `HIPPO_TENANT=acme` (or pass an API key) and recall, explain, context, MCP, and dashboard all filter by that tenant. Tenant A cannot see tenant B's memories, proven by negative test.
|
|
76
|
+
- **Audit trail.** Every mutation writes to `audit_log`: remember, recall, promote, supersede, forget, archive, auth_revoke. Query with `hippo audit list --op recall --since 2026-04-01 --json`.
|
|
77
|
+
- **Schema v16.** `tenant_id` columns added to memories and four other tables, default 'default'. Existing data is unaffected.
|
|
78
|
+
- **SSO/SCIM stubs.** Hook points exist (throw `NotImplementedError`); full multi-tenant + OAuth deferred to v2.
|
|
79
|
+
|
|
63
80
|
### What's new in v0.34.0
|
|
64
81
|
|
|
65
82
|
- **Provenance envelope on every memory.** `kind` (raw / distilled / superseded), `scope`, `owner`, `artifact_ref` columns now ride alongside content. `hippo recall --why` shows them; `hippo remember --kind --scope --owner --artifact-ref` sets them. Foundation for ingestion connectors and right-to-be-forgotten.
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain API layer for Hippo.
|
|
3
|
+
*
|
|
4
|
+
* Pure functions taking a Context (hippoRoot + tenantId + actor) plus
|
|
5
|
+
* operation options. Both the CLI (direct mode) and the HTTP server
|
|
6
|
+
* (`hippo serve`, A1) call into this module so the business logic lives
|
|
7
|
+
* in exactly one place.
|
|
8
|
+
*/
|
|
9
|
+
import { type MemoryKind } from './memory.js';
|
|
10
|
+
import { type AuditEvent, type AuditOp } from './audit.js';
|
|
11
|
+
import { type ApiKeyListItem } from './auth.js';
|
|
12
|
+
export interface Context {
|
|
13
|
+
hippoRoot: string;
|
|
14
|
+
tenantId: string;
|
|
15
|
+
/** 'cli' | 'localhost:cli' | 'api_key:<key_id>' | 'mcp' */
|
|
16
|
+
actor: string;
|
|
17
|
+
}
|
|
18
|
+
export interface RememberOpts {
|
|
19
|
+
content: string;
|
|
20
|
+
kind?: MemoryKind;
|
|
21
|
+
scope?: string;
|
|
22
|
+
owner?: string;
|
|
23
|
+
artifactRef?: string;
|
|
24
|
+
tags?: string[];
|
|
25
|
+
}
|
|
26
|
+
export interface RememberResult {
|
|
27
|
+
id: string;
|
|
28
|
+
kind: MemoryKind;
|
|
29
|
+
tenantId: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function remember(ctx: Context, opts: RememberOpts): RememberResult;
|
|
32
|
+
export interface RecallOpts {
|
|
33
|
+
query: string;
|
|
34
|
+
limit?: number;
|
|
35
|
+
mode?: 'bm25' | 'hybrid' | 'physics';
|
|
36
|
+
}
|
|
37
|
+
export interface RecallResultItem {
|
|
38
|
+
id: string;
|
|
39
|
+
content: string;
|
|
40
|
+
score: number;
|
|
41
|
+
layer: string;
|
|
42
|
+
strength: number;
|
|
43
|
+
}
|
|
44
|
+
export interface RecallResult {
|
|
45
|
+
results: RecallResultItem[];
|
|
46
|
+
total: number;
|
|
47
|
+
tokens: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Domain-level recall. Loads BM25-ranked candidates from SQLite scoped to
|
|
51
|
+
* `ctx.tenantId`. The `mode` flag is accepted for forward compatibility (the
|
|
52
|
+
* CLI exposes hybrid/physics paths) but Task 2 wires only the BM25 candidate
|
|
53
|
+
* loader; later tasks can extend this to call the physics/hybrid scorer.
|
|
54
|
+
*/
|
|
55
|
+
export declare function recall(ctx: Context, opts: RecallOpts): RecallResult;
|
|
56
|
+
/**
|
|
57
|
+
* Delete a memory by id. `deleteEntry` threads ctx.actor into its internal
|
|
58
|
+
* audit hook, so exactly one 'forget' event lands with the supplied actor.
|
|
59
|
+
*
|
|
60
|
+
* Tenant scope: deleteEntry looks up the row by id alone, so without an
|
|
61
|
+
* explicit tenant guard a Bearer for tenant A could delete tenant B's row
|
|
62
|
+
* by guessing or leaking the id. Pre-check the row's tenant_id and deny
|
|
63
|
+
* cross-tenant access with a not-found error (no info leak about whether
|
|
64
|
+
* the id exists in another tenant).
|
|
65
|
+
*/
|
|
66
|
+
export declare function forget(ctx: Context, id: string): {
|
|
67
|
+
ok: true;
|
|
68
|
+
id: string;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Copy a local memory into the global store. Mirrors `cmdPromote` in cli.ts:
|
|
72
|
+
* the `writeEntry` inside `promoteToGlobal` emits a 'remember' on the global
|
|
73
|
+
* db; we add a 'promote' audit event on the global db so the user-facing
|
|
74
|
+
* intent stays distinct from the underlying upsert.
|
|
75
|
+
*
|
|
76
|
+
* Note: `promoteToGlobal` does not currently take a tenantId override — it
|
|
77
|
+
* reads the entry from the local root via `readEntry` (no tenant filter) and
|
|
78
|
+
* preserves the entry's existing tenantId on the global side. Task 4 may
|
|
79
|
+
* tighten this once writeEntry/readEntry thread tenant context.
|
|
80
|
+
*/
|
|
81
|
+
export declare function promote(ctx: Context, id: string): {
|
|
82
|
+
ok: true;
|
|
83
|
+
sourceId: string;
|
|
84
|
+
globalId: string;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Replace an old memory with new content, chaining old.superseded_by = new.id.
|
|
88
|
+
* Mirrors `cmdSupersede` in cli.ts (without flag-driven layer/tag/pin overrides
|
|
89
|
+
* — A1 keeps the API minimal; the CLI handler will continue to handle those
|
|
90
|
+
* flags and pass the resolved values once Task 4 lands).
|
|
91
|
+
*/
|
|
92
|
+
export declare function supersede(ctx: Context, oldId: string, newContent: string): {
|
|
93
|
+
ok: true;
|
|
94
|
+
oldId: string;
|
|
95
|
+
newId: string;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Archive a kind='raw' memory: snapshot into raw_archive, mark archived, delete.
|
|
99
|
+
*
|
|
100
|
+
* `archiveRawMemory` audits the operation internally (op='archive_raw') using the
|
|
101
|
+
* row's own tenant_id. We DO NOT emit a second audit event here to avoid double-
|
|
102
|
+
* emitting the archive_raw op (unlike Task 1 remember/forget where the underlying
|
|
103
|
+
* helpers hardcode actor='cli'). Instead we pass `ctx.actor` through as `who`,
|
|
104
|
+
* and raw-archive.ts uses that for the audit row.
|
|
105
|
+
*/
|
|
106
|
+
export declare function archiveRaw(ctx: Context, id: string, reason: string): {
|
|
107
|
+
ok: true;
|
|
108
|
+
archivedAt: string;
|
|
109
|
+
};
|
|
110
|
+
export interface AuthCreateOpts {
|
|
111
|
+
label?: string;
|
|
112
|
+
/** Override the calling tenant (e.g. admin minting a key for tenant B). */
|
|
113
|
+
tenantId?: string;
|
|
114
|
+
}
|
|
115
|
+
export interface AuthCreateResult {
|
|
116
|
+
keyId: string;
|
|
117
|
+
plaintext: string;
|
|
118
|
+
tenantId: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Mint a new API key. Per A5 v2 follow-ups (TODOS.md), `auth_create` is currently
|
|
122
|
+
* unaudited — we intentionally match that behavior here for consistency. When A5
|
|
123
|
+
* v2 lands and adds the audit op, this function should mirror the cli handler.
|
|
124
|
+
*/
|
|
125
|
+
export declare function authCreate(ctx: Context, opts: AuthCreateOpts): AuthCreateResult;
|
|
126
|
+
/**
|
|
127
|
+
* List API keys visible to the calling tenant.
|
|
128
|
+
*
|
|
129
|
+
* Divergence from `cmdAuthList` in src/cli.ts: the CLI today returns ALL keys
|
|
130
|
+
* regardless of tenant (single-tenant deployments). The API surface is tenant-
|
|
131
|
+
* scoped because future multi-tenant deployments will share a hippoRoot, and
|
|
132
|
+
* tenant A must not see tenant B's keys. Read-only — no audit emit (matches A5).
|
|
133
|
+
*/
|
|
134
|
+
export declare function authList(ctx: Context, opts: {
|
|
135
|
+
active: boolean;
|
|
136
|
+
}): ApiKeyListItem[];
|
|
137
|
+
/**
|
|
138
|
+
* Revoke an API key.
|
|
139
|
+
*
|
|
140
|
+
* Security: the key must belong to `ctx.tenantId`. Cross-tenant revoke is
|
|
141
|
+
* rejected with the same "not found" message used for missing keys, so that a
|
|
142
|
+
* caller cannot probe which key_ids exist on other tenants.
|
|
143
|
+
*
|
|
144
|
+
* Audit: emits 'auth_revoke' with `tenantId` set to the KEY ROW's tenant_id
|
|
145
|
+
* (M1 fix from A5 review, mirrors src/cli.ts:cmdAuthRevoke). Skipped on no-op
|
|
146
|
+
* revoke (already revoked) so re-running doesn't pad the audit log.
|
|
147
|
+
*/
|
|
148
|
+
export declare function authRevoke(ctx: Context, keyId: string): {
|
|
149
|
+
ok: true;
|
|
150
|
+
revokedAt: string;
|
|
151
|
+
};
|
|
152
|
+
export interface AuditListOpts {
|
|
153
|
+
op?: AuditOp;
|
|
154
|
+
/** ISO timestamp lower bound. */
|
|
155
|
+
since?: string;
|
|
156
|
+
limit?: number;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Read audit events scoped to `ctx.tenantId`. Read-only — no audit emit (matches
|
|
160
|
+
* A5: cmdAuditList does not record a 'recall'-style read event).
|
|
161
|
+
*/
|
|
162
|
+
export declare function auditList(ctx: Context, opts: AuditListOpts): AuditEvent[];
|
|
163
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain API layer for Hippo.
|
|
3
|
+
*
|
|
4
|
+
* Pure functions taking a Context (hippoRoot + tenantId + actor) plus
|
|
5
|
+
* operation options. Both the CLI (direct mode) and the HTTP server
|
|
6
|
+
* (`hippo serve`, A1) call into this module so the business logic lives
|
|
7
|
+
* in exactly one place.
|
|
8
|
+
*/
|
|
9
|
+
import { openHippoDb, closeHippoDb } from './db.js';
|
|
10
|
+
import { writeEntry, readEntry, deleteEntry, loadSearchEntries, } from './store.js';
|
|
11
|
+
import { createMemory, Layer, } from './memory.js';
|
|
12
|
+
import { appendAuditEvent, queryAuditEvents, } from './audit.js';
|
|
13
|
+
import { promoteToGlobal, getGlobalRoot } from './shared.js';
|
|
14
|
+
import { archiveRawMemory } from './raw-archive.js';
|
|
15
|
+
import { createApiKey, listApiKeys, revokeApiKey, } from './auth.js';
|
|
16
|
+
export function remember(ctx, opts) {
|
|
17
|
+
const entry = createMemory(opts.content, {
|
|
18
|
+
kind: opts.kind ?? 'distilled',
|
|
19
|
+
scope: opts.scope ?? null,
|
|
20
|
+
owner: opts.owner ?? null,
|
|
21
|
+
artifact_ref: opts.artifactRef ?? null,
|
|
22
|
+
tags: opts.tags,
|
|
23
|
+
tenantId: ctx.tenantId,
|
|
24
|
+
});
|
|
25
|
+
// writeEntry threads ctx.actor into its internal audit hook, so exactly
|
|
26
|
+
// one 'remember' event lands in the log with the supplied actor.
|
|
27
|
+
writeEntry(ctx.hippoRoot, entry, { actor: ctx.actor });
|
|
28
|
+
return { id: entry.id, kind: entry.kind, tenantId: ctx.tenantId };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Domain-level recall. Loads BM25-ranked candidates from SQLite scoped to
|
|
32
|
+
* `ctx.tenantId`. The `mode` flag is accepted for forward compatibility (the
|
|
33
|
+
* CLI exposes hybrid/physics paths) but Task 2 wires only the BM25 candidate
|
|
34
|
+
* loader; later tasks can extend this to call the physics/hybrid scorer.
|
|
35
|
+
*/
|
|
36
|
+
export function recall(ctx, opts) {
|
|
37
|
+
const limit = opts.limit ?? 10;
|
|
38
|
+
const entries = loadSearchEntries(ctx.hippoRoot, opts.query, undefined, ctx.tenantId);
|
|
39
|
+
// BM25 ordering already comes from loadSearchEntries; cap to `limit`.
|
|
40
|
+
// Score is a placeholder — the physics/hybrid scorers in src/search.ts
|
|
41
|
+
// produce richer breakdowns and will replace this when wired up.
|
|
42
|
+
const ranked = entries.slice(0, limit).map((entry, idx) => ({
|
|
43
|
+
id: entry.id,
|
|
44
|
+
content: entry.content,
|
|
45
|
+
score: Math.max(0, 1 - idx / Math.max(1, limit)),
|
|
46
|
+
layer: entry.layer,
|
|
47
|
+
strength: entry.strength,
|
|
48
|
+
}));
|
|
49
|
+
const tokens = ranked.reduce((acc, r) => acc + Math.ceil(r.content.length / 4), 0);
|
|
50
|
+
// TODO(a1-task-4): emit via the shared audit hook in store.ts so we don't
|
|
51
|
+
// double-emit. Recall does not currently write through writeEntry, so no
|
|
52
|
+
// duplicate exists today, but we keep the same shape for symmetry.
|
|
53
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
54
|
+
try {
|
|
55
|
+
appendAuditEvent(db, {
|
|
56
|
+
tenantId: ctx.tenantId,
|
|
57
|
+
actor: ctx.actor,
|
|
58
|
+
op: 'recall',
|
|
59
|
+
metadata: { query: opts.query.slice(0, 200), results: ranked.length },
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
closeHippoDb(db);
|
|
64
|
+
}
|
|
65
|
+
return { results: ranked, total: entries.length, tokens };
|
|
66
|
+
}
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// forget
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
/**
|
|
71
|
+
* Delete a memory by id. `deleteEntry` threads ctx.actor into its internal
|
|
72
|
+
* audit hook, so exactly one 'forget' event lands with the supplied actor.
|
|
73
|
+
*
|
|
74
|
+
* Tenant scope: deleteEntry looks up the row by id alone, so without an
|
|
75
|
+
* explicit tenant guard a Bearer for tenant A could delete tenant B's row
|
|
76
|
+
* by guessing or leaking the id. Pre-check the row's tenant_id and deny
|
|
77
|
+
* cross-tenant access with a not-found error (no info leak about whether
|
|
78
|
+
* the id exists in another tenant).
|
|
79
|
+
*/
|
|
80
|
+
export function forget(ctx, id) {
|
|
81
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
82
|
+
try {
|
|
83
|
+
const row = db
|
|
84
|
+
.prepare(`SELECT tenant_id FROM memories WHERE id = ?`)
|
|
85
|
+
.get(id);
|
|
86
|
+
if (!row || row.tenant_id !== ctx.tenantId) {
|
|
87
|
+
throw new Error(`memory not found: ${id}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
closeHippoDb(db);
|
|
92
|
+
}
|
|
93
|
+
const removed = deleteEntry(ctx.hippoRoot, id, { actor: ctx.actor });
|
|
94
|
+
if (!removed) {
|
|
95
|
+
throw new Error(`memory not found: ${id}`);
|
|
96
|
+
}
|
|
97
|
+
return { ok: true, id };
|
|
98
|
+
}
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// promote
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
/**
|
|
103
|
+
* Copy a local memory into the global store. Mirrors `cmdPromote` in cli.ts:
|
|
104
|
+
* the `writeEntry` inside `promoteToGlobal` emits a 'remember' on the global
|
|
105
|
+
* db; we add a 'promote' audit event on the global db so the user-facing
|
|
106
|
+
* intent stays distinct from the underlying upsert.
|
|
107
|
+
*
|
|
108
|
+
* Note: `promoteToGlobal` does not currently take a tenantId override — it
|
|
109
|
+
* reads the entry from the local root via `readEntry` (no tenant filter) and
|
|
110
|
+
* preserves the entry's existing tenantId on the global side. Task 4 may
|
|
111
|
+
* tighten this once writeEntry/readEntry thread tenant context.
|
|
112
|
+
*/
|
|
113
|
+
export function promote(ctx, id) {
|
|
114
|
+
// promoteToGlobal threads ctx.actor into the writeEntry call on the global
|
|
115
|
+
// db, which emits a 'remember' audit row. We then add the user-facing
|
|
116
|
+
// 'promote' event on the global db so the audit trail keeps the intent
|
|
117
|
+
// distinct from the underlying upsert.
|
|
118
|
+
const globalEntry = promoteToGlobal(ctx.hippoRoot, id, { actor: ctx.actor });
|
|
119
|
+
const db = openHippoDb(getGlobalRoot());
|
|
120
|
+
try {
|
|
121
|
+
appendAuditEvent(db, {
|
|
122
|
+
tenantId: ctx.tenantId,
|
|
123
|
+
actor: ctx.actor,
|
|
124
|
+
op: 'promote',
|
|
125
|
+
targetId: globalEntry.id,
|
|
126
|
+
metadata: { sourceId: id },
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
closeHippoDb(db);
|
|
131
|
+
}
|
|
132
|
+
return { ok: true, sourceId: id, globalId: globalEntry.id };
|
|
133
|
+
}
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// supersede
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
/**
|
|
138
|
+
* Replace an old memory with new content, chaining old.superseded_by = new.id.
|
|
139
|
+
* Mirrors `cmdSupersede` in cli.ts (without flag-driven layer/tag/pin overrides
|
|
140
|
+
* — A1 keeps the API minimal; the CLI handler will continue to handle those
|
|
141
|
+
* flags and pass the resolved values once Task 4 lands).
|
|
142
|
+
*/
|
|
143
|
+
export function supersede(ctx, oldId, newContent) {
|
|
144
|
+
const old = readEntry(ctx.hippoRoot, oldId, ctx.tenantId);
|
|
145
|
+
if (!old) {
|
|
146
|
+
throw new Error(`Memory not found: ${oldId}`);
|
|
147
|
+
}
|
|
148
|
+
if (old.superseded_by) {
|
|
149
|
+
throw new Error(`Memory ${oldId} is already superseded by ${old.superseded_by}. Supersede that one instead.`);
|
|
150
|
+
}
|
|
151
|
+
const newEntry = createMemory(newContent, {
|
|
152
|
+
layer: old.layer ?? Layer.Episodic,
|
|
153
|
+
tags: [...old.tags],
|
|
154
|
+
pinned: old.pinned,
|
|
155
|
+
source: old.source,
|
|
156
|
+
confidence: 'verified',
|
|
157
|
+
tenantId: ctx.tenantId,
|
|
158
|
+
});
|
|
159
|
+
old.superseded_by = newEntry.id;
|
|
160
|
+
writeEntry(ctx.hippoRoot, old, { actor: ctx.actor });
|
|
161
|
+
writeEntry(ctx.hippoRoot, newEntry, { actor: ctx.actor });
|
|
162
|
+
// The two writeEntry calls above emit 'remember' audit rows; the 'supersede'
|
|
163
|
+
// event below carries the user-facing intent and the chained newId.
|
|
164
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
165
|
+
try {
|
|
166
|
+
appendAuditEvent(db, {
|
|
167
|
+
tenantId: ctx.tenantId,
|
|
168
|
+
actor: ctx.actor,
|
|
169
|
+
op: 'supersede',
|
|
170
|
+
targetId: oldId,
|
|
171
|
+
metadata: { newId: newEntry.id },
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
closeHippoDb(db);
|
|
176
|
+
}
|
|
177
|
+
return { ok: true, oldId, newId: newEntry.id };
|
|
178
|
+
}
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// archive_raw
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
/**
|
|
183
|
+
* Archive a kind='raw' memory: snapshot into raw_archive, mark archived, delete.
|
|
184
|
+
*
|
|
185
|
+
* `archiveRawMemory` audits the operation internally (op='archive_raw') using the
|
|
186
|
+
* row's own tenant_id. We DO NOT emit a second audit event here to avoid double-
|
|
187
|
+
* emitting the archive_raw op (unlike Task 1 remember/forget where the underlying
|
|
188
|
+
* helpers hardcode actor='cli'). Instead we pass `ctx.actor` through as `who`,
|
|
189
|
+
* and raw-archive.ts uses that for the audit row.
|
|
190
|
+
*/
|
|
191
|
+
export function archiveRaw(ctx, id, reason) {
|
|
192
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
193
|
+
try {
|
|
194
|
+
// Tenant scope: archiveRawMemory looks up the row by id alone, so a
|
|
195
|
+
// Bearer for tenant A could archive tenant B's raw row without this
|
|
196
|
+
// pre-check. Deny cross-tenant access with the same not-found message
|
|
197
|
+
// archiveRawMemory itself would throw on a missing row, so we don't
|
|
198
|
+
// leak whether the id exists in another tenant.
|
|
199
|
+
const row = db
|
|
200
|
+
.prepare(`SELECT tenant_id FROM memories WHERE id = ?`)
|
|
201
|
+
.get(id);
|
|
202
|
+
if (!row || row.tenant_id !== ctx.tenantId) {
|
|
203
|
+
throw new Error(`memory not found: ${id}`);
|
|
204
|
+
}
|
|
205
|
+
archiveRawMemory(db, id, { reason, who: ctx.actor });
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
closeHippoDb(db);
|
|
209
|
+
}
|
|
210
|
+
// archiveRawMemory does not return the archive_at timestamp it wrote. We
|
|
211
|
+
// emit a fresh ISO timestamp here for the API response. Within a millisecond
|
|
212
|
+
// of the actual write, fine for a server response shape.
|
|
213
|
+
return { ok: true, archivedAt: new Date().toISOString() };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Mint a new API key. Per A5 v2 follow-ups (TODOS.md), `auth_create` is currently
|
|
217
|
+
* unaudited — we intentionally match that behavior here for consistency. When A5
|
|
218
|
+
* v2 lands and adds the audit op, this function should mirror the cli handler.
|
|
219
|
+
*/
|
|
220
|
+
export function authCreate(ctx, opts) {
|
|
221
|
+
const tenantId = opts.tenantId ?? ctx.tenantId;
|
|
222
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
223
|
+
try {
|
|
224
|
+
const result = createApiKey(db, { tenantId, label: opts.label });
|
|
225
|
+
return { keyId: result.keyId, plaintext: result.plaintext, tenantId };
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
closeHippoDb(db);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* List API keys visible to the calling tenant.
|
|
233
|
+
*
|
|
234
|
+
* Divergence from `cmdAuthList` in src/cli.ts: the CLI today returns ALL keys
|
|
235
|
+
* regardless of tenant (single-tenant deployments). The API surface is tenant-
|
|
236
|
+
* scoped because future multi-tenant deployments will share a hippoRoot, and
|
|
237
|
+
* tenant A must not see tenant B's keys. Read-only — no audit emit (matches A5).
|
|
238
|
+
*/
|
|
239
|
+
export function authList(ctx, opts) {
|
|
240
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
241
|
+
try {
|
|
242
|
+
const all = listApiKeys(db, opts);
|
|
243
|
+
return all.filter((k) => k.tenantId === ctx.tenantId);
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
closeHippoDb(db);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Revoke an API key.
|
|
251
|
+
*
|
|
252
|
+
* Security: the key must belong to `ctx.tenantId`. Cross-tenant revoke is
|
|
253
|
+
* rejected with the same "not found" message used for missing keys, so that a
|
|
254
|
+
* caller cannot probe which key_ids exist on other tenants.
|
|
255
|
+
*
|
|
256
|
+
* Audit: emits 'auth_revoke' with `tenantId` set to the KEY ROW's tenant_id
|
|
257
|
+
* (M1 fix from A5 review, mirrors src/cli.ts:cmdAuthRevoke). Skipped on no-op
|
|
258
|
+
* revoke (already revoked) so re-running doesn't pad the audit log.
|
|
259
|
+
*/
|
|
260
|
+
export function authRevoke(ctx, keyId) {
|
|
261
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
262
|
+
try {
|
|
263
|
+
const row = db
|
|
264
|
+
.prepare(`SELECT key_id, tenant_id, revoked_at FROM api_keys WHERE key_id = ?`)
|
|
265
|
+
.get(keyId);
|
|
266
|
+
if (!row) {
|
|
267
|
+
throw new Error(`Unknown key_id: ${keyId}`);
|
|
268
|
+
}
|
|
269
|
+
// Cross-tenant access denied: same message as missing key, no info leak.
|
|
270
|
+
if (row.tenant_id !== ctx.tenantId) {
|
|
271
|
+
throw new Error(`Unknown key_id: ${keyId}`);
|
|
272
|
+
}
|
|
273
|
+
let revokedAt;
|
|
274
|
+
let alreadyRevoked = false;
|
|
275
|
+
if (row.revoked_at) {
|
|
276
|
+
alreadyRevoked = true;
|
|
277
|
+
revokedAt = row.revoked_at;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
revokeApiKey(db, keyId);
|
|
281
|
+
const updated = db
|
|
282
|
+
.prepare(`SELECT revoked_at FROM api_keys WHERE key_id = ?`)
|
|
283
|
+
.get(keyId);
|
|
284
|
+
revokedAt = updated?.revoked_at ?? new Date().toISOString();
|
|
285
|
+
}
|
|
286
|
+
if (!alreadyRevoked) {
|
|
287
|
+
try {
|
|
288
|
+
appendAuditEvent(db, {
|
|
289
|
+
tenantId: row.tenant_id, // M1: KEY's tenant, not ctx.tenantId.
|
|
290
|
+
actor: ctx.actor,
|
|
291
|
+
op: 'auth_revoke',
|
|
292
|
+
targetId: keyId,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
// Audit must not crash a successful revoke.
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return { ok: true, revokedAt };
|
|
300
|
+
}
|
|
301
|
+
finally {
|
|
302
|
+
closeHippoDb(db);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Read audit events scoped to `ctx.tenantId`. Read-only — no audit emit (matches
|
|
307
|
+
* A5: cmdAuditList does not record a 'recall'-style read event).
|
|
308
|
+
*/
|
|
309
|
+
export function auditList(ctx, opts) {
|
|
310
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
311
|
+
try {
|
|
312
|
+
return queryAuditEvents(db, {
|
|
313
|
+
tenantId: ctx.tenantId,
|
|
314
|
+
op: opts.op,
|
|
315
|
+
since: opts.since,
|
|
316
|
+
limit: opts.limit,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
finally {
|
|
320
|
+
closeHippoDb(db);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/audit.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { MemoryEntry } from './memory.js';
|
|
2
|
+
import type { DatabaseSyncLike } from './db.js';
|
|
2
3
|
export type AuditSeverity = 'warning' | 'error';
|
|
3
4
|
export interface AuditIssue {
|
|
4
5
|
memoryId: string;
|
|
@@ -14,4 +15,29 @@ export interface AuditResult {
|
|
|
14
15
|
export declare function auditMemory(entry: MemoryEntry): AuditIssue | null;
|
|
15
16
|
export declare function auditMemories(entries: MemoryEntry[]): AuditResult;
|
|
16
17
|
export declare function isContentWorthStoring(content: string): boolean;
|
|
18
|
+
export type AuditOp = 'remember' | 'recall' | 'promote' | 'supersede' | 'forget' | 'archive_raw' | 'auth_revoke';
|
|
19
|
+
export interface AppendAuditOpts {
|
|
20
|
+
tenantId: string;
|
|
21
|
+
actor: string;
|
|
22
|
+
op: AuditOp;
|
|
23
|
+
targetId?: string;
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export declare function appendAuditEvent(db: DatabaseSyncLike, opts: AppendAuditOpts): void;
|
|
27
|
+
export interface QueryAuditOpts {
|
|
28
|
+
tenantId: string;
|
|
29
|
+
op?: AuditOp;
|
|
30
|
+
since?: string;
|
|
31
|
+
limit?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface AuditEvent {
|
|
34
|
+
id: number;
|
|
35
|
+
ts: string;
|
|
36
|
+
tenantId: string;
|
|
37
|
+
actor: string;
|
|
38
|
+
op: AuditOp;
|
|
39
|
+
targetId: string | null;
|
|
40
|
+
metadata: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
export declare function queryAuditEvents(db: DatabaseSyncLike, opts: QueryAuditOpts): AuditEvent[];
|
|
17
43
|
//# sourceMappingURL=audit.d.ts.map
|
package/dist/audit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAuDD,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI,CA6BjE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,CAWjE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAQ9D;AAMD,MAAM,MAAM,OAAO,GACf,UAAU,GACV,QAAQ,GACR,SAAS,GACT,WAAW,GACX,QAAQ,GACR,aAAa,GACb,aAAa,CAAC;AAElB,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAUD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI,CAWlF;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,GAAG,UAAU,EAAE,CAmCzF"}
|
package/dist/audit.js
CHANGED
|
@@ -104,4 +104,49 @@ export function isContentWorthStoring(content) {
|
|
|
104
104
|
return false;
|
|
105
105
|
return true;
|
|
106
106
|
}
|
|
107
|
+
// node:sqlite returns INTEGER columns as bigint when the value exceeds
|
|
108
|
+
// Number.MAX_SAFE_INTEGER. Audit metadata can carry such values (row ids,
|
|
109
|
+
// counts), and JSON.stringify cannot serialize bigint without a replacer.
|
|
110
|
+
// Mirrors the bigintSafeReplacer in src/raw-archive.ts.
|
|
111
|
+
function bigintSafeReplacer(_key, value) {
|
|
112
|
+
return typeof value === 'bigint' ? value.toString() : value;
|
|
113
|
+
}
|
|
114
|
+
export function appendAuditEvent(db, opts) {
|
|
115
|
+
db.prepare(`INSERT INTO audit_log (ts, tenant_id, actor, op, target_id, metadata_json) VALUES (?, ?, ?, ?, ?, ?)`).run(new Date().toISOString(), opts.tenantId, opts.actor, opts.op, opts.targetId ?? null, JSON.stringify(opts.metadata ?? {}, bigintSafeReplacer));
|
|
116
|
+
}
|
|
117
|
+
export function queryAuditEvents(db, opts) {
|
|
118
|
+
const where = ['tenant_id = ?'];
|
|
119
|
+
const params = [opts.tenantId];
|
|
120
|
+
if (opts.op) {
|
|
121
|
+
where.push('op = ?');
|
|
122
|
+
params.push(opts.op);
|
|
123
|
+
}
|
|
124
|
+
if (opts.since) {
|
|
125
|
+
where.push('ts >= ?');
|
|
126
|
+
params.push(opts.since);
|
|
127
|
+
}
|
|
128
|
+
const limit = Math.max(1, Math.min(opts.limit ?? 100, 10000));
|
|
129
|
+
const rows = db
|
|
130
|
+
.prepare(`SELECT id, ts, tenant_id, actor, op, target_id, metadata_json
|
|
131
|
+
FROM audit_log WHERE ${where.join(' AND ')} ORDER BY ts DESC, id DESC LIMIT ?`)
|
|
132
|
+
.all(...params, limit);
|
|
133
|
+
return rows.map((r) => ({
|
|
134
|
+
id: r.id,
|
|
135
|
+
ts: r.ts,
|
|
136
|
+
tenantId: r.tenant_id,
|
|
137
|
+
actor: r.actor,
|
|
138
|
+
op: r.op,
|
|
139
|
+
targetId: r.target_id,
|
|
140
|
+
metadata: safeJsonParse(r.metadata_json),
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
function safeJsonParse(raw) {
|
|
144
|
+
try {
|
|
145
|
+
const v = JSON.parse(raw);
|
|
146
|
+
return typeof v === 'object' && v !== null ? v : {};
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return {};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
107
152
|
//# sourceMappingURL=audit.js.map
|
package/dist/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|