@justfortytwo/memory 0.1.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/LICENSE +21 -0
- package/README.md +183 -0
- package/dist/contract.d.ts +19 -0
- package/dist/contract.js +41 -0
- package/dist/contract.js.map +1 -0
- package/dist/db.d.ts +11 -0
- package/dist/db.js +33 -0
- package/dist/db.js.map +1 -0
- package/dist/dispatch.d.ts +3 -0
- package/dist/dispatch.js +43 -0
- package/dist/dispatch.js.map +1 -0
- package/dist/embedder.d.ts +18 -0
- package/dist/embedder.js +44 -0
- package/dist/embedder.js.map +1 -0
- package/dist/enrichment.d.ts +58 -0
- package/dist/enrichment.js +109 -0
- package/dist/enrichment.js.map +1 -0
- package/dist/gate-approval-store.d.ts +17 -0
- package/dist/gate-approval-store.js +114 -0
- package/dist/gate-approval-store.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/memory.d.ts +74 -0
- package/dist/memory.js +179 -0
- package/dist/memory.js.map +1 -0
- package/dist/migrate.d.ts +2 -0
- package/dist/migrate.js +40 -0
- package/dist/migrate.js.map +1 -0
- package/dist/migrations/001_init.d.ts +3 -0
- package/dist/migrations/001_init.js +40 -0
- package/dist/migrations/001_init.js.map +1 -0
- package/dist/migrations/002_fts.d.ts +3 -0
- package/dist/migrations/002_fts.js +26 -0
- package/dist/migrations/002_fts.js.map +1 -0
- package/dist/migrations/003_approvals.d.ts +3 -0
- package/dist/migrations/003_approvals.js +37 -0
- package/dist/migrations/003_approvals.js.map +1 -0
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +66 -0
- package/dist/tools.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// memory's implementation of gate's host-integration seam.
|
|
2
|
+
//
|
|
3
|
+
// @justfortytwo/gate (the safety gate) defines the ApprovalStore + AuditLogger
|
|
4
|
+
// interfaces but ships only standalone in-memory / JSONL stores. This is the
|
|
5
|
+
// RICHER, durable backing the gate's `decide()` accepts via opts.store / opts.audit:
|
|
6
|
+
// a transactional store + audit trail on memory's own SQLite db (tables created by
|
|
7
|
+
// migration 003_approvals).
|
|
8
|
+
//
|
|
9
|
+
// Dependency direction is ONE-WAY: memory -> gate (we import gate's TYPES; gate
|
|
10
|
+
// never imports memory). No cycle. gate is a peerDependency of memory.
|
|
11
|
+
import { randomUUID } from 'node:crypto';
|
|
12
|
+
function nowIso() {
|
|
13
|
+
return new Date().toISOString();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Fail-closed transition guard (same invariant as gate's stock stores): only a
|
|
17
|
+
* pending call may be approved/denied, and an approval may be revoked (-> denied)
|
|
18
|
+
* before it is consumed. Terminal states (executed/denied/expired) are immutable,
|
|
19
|
+
* so a decision can never resurrect a spent or denied one-shot.
|
|
20
|
+
*/
|
|
21
|
+
function canDecide(current, next) {
|
|
22
|
+
if (current === 'pending')
|
|
23
|
+
return true;
|
|
24
|
+
if (current === 'approved' && next === 'denied')
|
|
25
|
+
return true;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
function toApproval(r) {
|
|
29
|
+
return {
|
|
30
|
+
id: r.id,
|
|
31
|
+
tool: r.tool,
|
|
32
|
+
target: r.target,
|
|
33
|
+
payload: JSON.parse(r.payload),
|
|
34
|
+
tier: r.tier,
|
|
35
|
+
tool_use_id: r.tool_use_id,
|
|
36
|
+
session_id: r.session_id,
|
|
37
|
+
status: r.status,
|
|
38
|
+
created_at: r.created_at,
|
|
39
|
+
updated_at: r.updated_at,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* SQLite-backed ApprovalStore + AuditLogger for the gate. Pass an instance
|
|
44
|
+
* to gate's `decide(manifest, ctx, { store, audit })` so staged one-shots and the
|
|
45
|
+
* audit trail live in memory's durable db instead of the gate's JSONL default.
|
|
46
|
+
*/
|
|
47
|
+
export class GateApprovalStore {
|
|
48
|
+
h;
|
|
49
|
+
constructor(h) {
|
|
50
|
+
this.h = h;
|
|
51
|
+
}
|
|
52
|
+
async addPending(input) {
|
|
53
|
+
const id = `pa_${randomUUID()}`;
|
|
54
|
+
const ts = nowIso();
|
|
55
|
+
// Upsert keyed on tool_use_id: a re-request replaces the prior (terminal) row
|
|
56
|
+
// with a fresh pending one, so there is exactly one staged row per tool_use_id
|
|
57
|
+
// and "most recent wins" is deterministic (no fragile timestamp/uuid tie-break).
|
|
58
|
+
this.h.raw
|
|
59
|
+
.prepare(`INSERT INTO approvals
|
|
60
|
+
(id, tool, target, payload, tier, tool_use_id, session_id, status, decided_by, created_at, updated_at)
|
|
61
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', NULL, ?, ?)
|
|
62
|
+
ON CONFLICT(tool_use_id) DO UPDATE SET
|
|
63
|
+
id = excluded.id, tool = excluded.tool, target = excluded.target,
|
|
64
|
+
payload = excluded.payload, tier = excluded.tier, session_id = excluded.session_id,
|
|
65
|
+
status = 'pending', decided_by = NULL,
|
|
66
|
+
created_at = excluded.created_at, updated_at = excluded.updated_at`)
|
|
67
|
+
.run(id, input.tool, input.target, JSON.stringify(input.payload ?? {}), input.tier, input.tool_use_id, input.session_id ?? null, ts, ts);
|
|
68
|
+
return id;
|
|
69
|
+
}
|
|
70
|
+
async getByToolUseId(toolUseId) {
|
|
71
|
+
// tool_use_id is UNIQUE (one staged row each), so this is unambiguous.
|
|
72
|
+
const row = this.h.raw
|
|
73
|
+
.prepare(`SELECT * FROM approvals WHERE tool_use_id = ? LIMIT 1`)
|
|
74
|
+
.get(toolUseId);
|
|
75
|
+
return row ? toApproval(row) : undefined;
|
|
76
|
+
}
|
|
77
|
+
async markExecutedByToolUseId(toolUseId) {
|
|
78
|
+
// Atomic compare-and-set approved -> executed: succeeds exactly once.
|
|
79
|
+
const txn = this.h.raw.transaction(() => {
|
|
80
|
+
const info = this.h.raw
|
|
81
|
+
.prepare(`UPDATE approvals SET status = 'executed', updated_at = ?
|
|
82
|
+
WHERE tool_use_id = ? AND status = 'approved'`)
|
|
83
|
+
.run(nowIso(), toolUseId);
|
|
84
|
+
return info.changes > 0;
|
|
85
|
+
});
|
|
86
|
+
return txn();
|
|
87
|
+
}
|
|
88
|
+
async setDecisionByToolUseId(toolUseId, status, by) {
|
|
89
|
+
const txn = this.h.raw.transaction(() => {
|
|
90
|
+
const row = this.h.raw
|
|
91
|
+
.prepare(`SELECT id, status FROM approvals WHERE tool_use_id = ? LIMIT 1`)
|
|
92
|
+
.get(toolUseId);
|
|
93
|
+
if (!row || !canDecide(row.status, status))
|
|
94
|
+
return false;
|
|
95
|
+
this.h.raw
|
|
96
|
+
.prepare(`UPDATE approvals SET status = ?, decided_by = ?, updated_at = ? WHERE id = ?`)
|
|
97
|
+
.run(status, by ?? null, nowIso(), row.id);
|
|
98
|
+
return true;
|
|
99
|
+
});
|
|
100
|
+
return txn();
|
|
101
|
+
}
|
|
102
|
+
async list() {
|
|
103
|
+
const rows = this.h.raw
|
|
104
|
+
.prepare(`SELECT * FROM approvals ORDER BY created_at ASC, id ASC`)
|
|
105
|
+
.all();
|
|
106
|
+
return rows.map(toApproval);
|
|
107
|
+
}
|
|
108
|
+
async log(entry) {
|
|
109
|
+
this.h.raw
|
|
110
|
+
.prepare(`INSERT INTO audit_log (actor, kind, content, approval_status, meta) VALUES (?, ?, ?, ?, ?)`)
|
|
111
|
+
.run(entry.actor, entry.kind, entry.content, entry.approval_status ?? null, JSON.stringify(entry.meta ?? {}));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=gate-approval-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-approval-store.js","sourceRoot":"","sources":["../src/gate-approval-store.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,qFAAqF;AACrF,mFAAmF;AACnF,4BAA4B;AAC5B,EAAE;AACF,gFAAgF;AAChF,uEAAuE;AAEvE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAWzC,SAAS,MAAM;IACb,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AACH,SAAS,SAAS,CAAC,OAAe,EAAE,IAA2B;IAC7D,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,OAAO,KAAK,UAAU,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC7D,OAAO,KAAK,CAAC;AACf,CAAC;AAeD,SAAS,UAAU,CAAC,CAAgB;IAClC,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAA4B;QACzD,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,MAAM,EAAE,CAAC,CAAC,MAAwB;QAClC,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,UAAU,EAAE,CAAC,CAAC,UAAU;KACzB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IACC;IAA7B,YAA6B,CAAY;QAAZ,MAAC,GAAD,CAAC,CAAW;IAAG,CAAC;IAE7C,KAAK,CAAC,UAAU,CAAC,KAAsB;QACrC,MAAM,EAAE,GAAG,MAAM,UAAU,EAAE,EAAE,CAAC;QAChC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,8EAA8E;QAC9E,+EAA+E;QAC/E,iFAAiF;QACjF,IAAI,CAAC,CAAC,CAAC,GAAG;aACP,OAAO,CACN;;;;;;;8EAOsE,CACvE;aACA,GAAG,CACF,EAAE,EACF,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,MAAM,EACZ,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,EACnC,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,WAAW,EACjB,KAAK,CAAC,UAAU,IAAI,IAAI,EACxB,EAAE,EACF,EAAE,CACH,CAAC;QACJ,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,SAAiB;QACpC,uEAAuE;QACvE,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG;aACnB,OAAO,CAAC,uDAAuD,CAAC;aAChE,GAAG,CAAC,SAAS,CAA8B,CAAC;QAC/C,OAAO,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,uBAAuB,CAAC,SAAiB;QAC7C,sEAAsE;QACtE,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG;iBACpB,OAAO,CACN;0DACgD,CACjD;iBACA,GAAG,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC;YAC5B,OAAO,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,EAAE,CAAC;IACf,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,SAAiB,EAAE,MAA6B,EAAE,EAAW;QACxF,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG;iBACnB,OAAO,CAAC,gEAAgE,CAAC;iBACzE,GAAG,CAAC,SAAS,CAA+C,CAAC;YAChE,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;gBAAE,OAAO,KAAK,CAAC;YACzD,IAAI,CAAC,CAAC,CAAC,GAAG;iBACP,OAAO,CAAC,8EAA8E,CAAC;iBACvF,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,EAAE,CAAC;IACf,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG;aACpB,OAAO,CAAC,yDAAyD,CAAC;aAClE,GAAG,EAAqB,CAAC;QAC5B,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAiB;QACzB,IAAI,CAAC,CAAC,CAAC,GAAG;aACP,OAAO,CACN,4FAA4F,CAC7F;aACA,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,eAAe,IAAI,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IAClH,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export * from './contract.js';
|
|
3
|
+
export * from './embedder.js';
|
|
4
|
+
export { openDb, type DbHandles, EMBED_DIM } from './db.js';
|
|
5
|
+
export { runMigrations } from './migrate.js';
|
|
6
|
+
export { store, query, recall, recallDocs, lexical, reindex, exportRange, reembed, type MemoryInput, type MemoryRow, type RecallRow, type QueryOpts, type DocRecallRow, type ReindexResult, } from './memory.js';
|
|
7
|
+
export { enrich, enrichFromTurn, type EnrichmentCandidate, type EnrichmentResult } from './enrichment.js';
|
|
8
|
+
export { toolDefinitions } from './tools.js';
|
|
9
|
+
export { GateApprovalStore } from './gate-approval-store.js';
|
|
10
|
+
/**
|
|
11
|
+
* Boot the MCP server over stdio. Kept behind an entrypoint guard so that
|
|
12
|
+
* IMPORTING this package as a library (e.g. the installer calling
|
|
13
|
+
* `runMigrations`/`openDb`) does NOT open a DB, run migrations, or connect a
|
|
14
|
+
* transport. Only running the `fortytwo-memory` bin directly starts the server.
|
|
15
|
+
*/
|
|
16
|
+
export declare function startServer(): Promise<void>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { ListToolsRequestSchema, CallToolRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { resolve, dirname } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { mkdirSync, realpathSync } from 'node:fs';
|
|
8
|
+
import { openDb } from './db.js';
|
|
9
|
+
import { runMigrations } from './migrate.js';
|
|
10
|
+
import { FakeEmbedder, OllamaEmbedder } from './embedder.js';
|
|
11
|
+
import { toolDefinitions } from './tools.js';
|
|
12
|
+
import { callTool } from './dispatch.js';
|
|
13
|
+
import { MEMORY_SERVER_ID } from './contract.js';
|
|
14
|
+
// Public surface re-exports so consumers can `import { ... } from '@justfortytwo/memory'`.
|
|
15
|
+
export * from './contract.js';
|
|
16
|
+
export * from './embedder.js';
|
|
17
|
+
export { openDb, EMBED_DIM } from './db.js';
|
|
18
|
+
export { runMigrations } from './migrate.js';
|
|
19
|
+
export { store, query, recall, recallDocs, lexical, reindex, exportRange, reembed, } from './memory.js';
|
|
20
|
+
export { enrich, enrichFromTurn } from './enrichment.js';
|
|
21
|
+
export { toolDefinitions } from './tools.js';
|
|
22
|
+
// memory's implementation of gate's ApprovalStore + AuditLogger seam (memory -> gate).
|
|
23
|
+
export { GateApprovalStore } from './gate-approval-store.js';
|
|
24
|
+
/**
|
|
25
|
+
* Boot the MCP server over stdio. Kept behind an entrypoint guard so that
|
|
26
|
+
* IMPORTING this package as a library (e.g. the installer calling
|
|
27
|
+
* `runMigrations`/`openDb`) does NOT open a DB, run migrations, or connect a
|
|
28
|
+
* transport. Only running the `fortytwo-memory` bin directly starts the server.
|
|
29
|
+
*/
|
|
30
|
+
export async function startServer() {
|
|
31
|
+
// Standalone, persona-agnostic: DB_PATH (env) or ./memory.db. No repo-root coupling.
|
|
32
|
+
const DB_PATH = process.env.DB_PATH ? resolve(process.env.DB_PATH) : resolve('memory.db');
|
|
33
|
+
// EMBED_MODEL present → real Ollama embedder; absent → deterministic FakeEmbedder
|
|
34
|
+
// (lets the server boot with zero infra for tests / first-run smoke checks).
|
|
35
|
+
const embedder = process.env.EMBED_MODEL
|
|
36
|
+
? new OllamaEmbedder(process.env.EMBED_MODEL, process.env.OLLAMA_BASE_URL)
|
|
37
|
+
: new FakeEmbedder();
|
|
38
|
+
mkdirSync(dirname(DB_PATH), { recursive: true });
|
|
39
|
+
const h = openDb(DB_PATH);
|
|
40
|
+
await runMigrations(h.k);
|
|
41
|
+
const server = new Server({ name: MEMORY_SERVER_ID, version: '0.1.0' }, { capabilities: { tools: {} } });
|
|
42
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
43
|
+
tools: toolDefinitions(),
|
|
44
|
+
}));
|
|
45
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
46
|
+
const { name, arguments: args = {} } = req.params;
|
|
47
|
+
const result = await callTool(h, embedder, name, args);
|
|
48
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
49
|
+
});
|
|
50
|
+
const transport = new StdioServerTransport();
|
|
51
|
+
await server.connect(transport);
|
|
52
|
+
}
|
|
53
|
+
// Run the server only when invoked directly as the `fortytwo-memory` bin.
|
|
54
|
+
// Realpath comparison so the npm bin symlink resolves to this module.
|
|
55
|
+
function invokedAsBin() {
|
|
56
|
+
const argv1 = process.argv[1];
|
|
57
|
+
if (!argv1)
|
|
58
|
+
return false;
|
|
59
|
+
try {
|
|
60
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(import.meta.url));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (invokedAsBin()) {
|
|
67
|
+
startServer().catch((err) => {
|
|
68
|
+
process.stderr.write(`fortytwo-memory: ${err?.stack ?? err}\n`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/memory.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { DbHandles } from './db.js';
|
|
2
|
+
import type { Embedder } from './embedder.js';
|
|
3
|
+
/** A memory to write. `content` is required; everything else is provenance. */
|
|
4
|
+
export interface MemoryInput {
|
|
5
|
+
content: string;
|
|
6
|
+
/** Where this came from, e.g. "owner", "web", "tool:foo". Free-form. */
|
|
7
|
+
source?: string;
|
|
8
|
+
/** How it was observed, e.g. "stated", "inferred", "imported". Free-form. */
|
|
9
|
+
observed?: string;
|
|
10
|
+
/** ISO date the memory pertains to. Defaults to today (UTC) at write time. */
|
|
11
|
+
date?: string;
|
|
12
|
+
/** Free-form tags for filtering. */
|
|
13
|
+
tags?: string[];
|
|
14
|
+
/** Arbitrary structured provenance. Stored as JSON. */
|
|
15
|
+
meta?: Record<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* If set, this memory SUPERSEDES the referenced memory id. The prior row is
|
|
18
|
+
* kept (history is never silently destroyed) but flagged superseded.
|
|
19
|
+
* See enrichment.ts for the dedupe/supersede design.
|
|
20
|
+
*/
|
|
21
|
+
supersedes?: number | null;
|
|
22
|
+
}
|
|
23
|
+
export interface MemoryRow {
|
|
24
|
+
id: number;
|
|
25
|
+
ts: string;
|
|
26
|
+
content: string;
|
|
27
|
+
source: string | null;
|
|
28
|
+
observed: string | null;
|
|
29
|
+
date: string | null;
|
|
30
|
+
tags: string;
|
|
31
|
+
meta: string;
|
|
32
|
+
superseded_by: number | null;
|
|
33
|
+
}
|
|
34
|
+
/** Atomic insert of the relational row + its embedding (raw transaction). */
|
|
35
|
+
export declare function store(h: DbHandles, embedder: Embedder, m: MemoryInput): Promise<number>;
|
|
36
|
+
export interface QueryOpts {
|
|
37
|
+
source?: string;
|
|
38
|
+
observed?: string;
|
|
39
|
+
tag?: string;
|
|
40
|
+
since?: string;
|
|
41
|
+
until?: string;
|
|
42
|
+
/** When false, superseded rows are excluded (default: true — only live rows). */
|
|
43
|
+
liveOnly?: boolean;
|
|
44
|
+
limit?: number;
|
|
45
|
+
}
|
|
46
|
+
export declare function query(h: DbHandles, opts?: QueryOpts): Promise<MemoryRow[]>;
|
|
47
|
+
export interface RecallRow extends MemoryRow {
|
|
48
|
+
distance: number;
|
|
49
|
+
}
|
|
50
|
+
/** Semantic top-k recall over the memory store by meaning. */
|
|
51
|
+
export declare function recall(h: DbHandles, embedder: Embedder, text: string, k?: number): Promise<RecallRow[]>;
|
|
52
|
+
/** Full-text keyword search over the memory store (FTS5). */
|
|
53
|
+
export declare function lexical(h: DbHandles, text: string, k?: number): MemoryRow[];
|
|
54
|
+
export interface ReindexResult {
|
|
55
|
+
indexed: number;
|
|
56
|
+
removed: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Self-heal the doc recall index from a directory of markdown files. Hashes
|
|
60
|
+
* content to skip unchanged files; removes index rows for files that vanished.
|
|
61
|
+
* Generic version of the original assistant's curated-doc reindex (no curated-corpus assumptions).
|
|
62
|
+
*/
|
|
63
|
+
export declare function reindex(h: DbHandles, embedder: Embedder, root: string): Promise<ReindexResult>;
|
|
64
|
+
export interface DocRecallRow {
|
|
65
|
+
file_path: string;
|
|
66
|
+
distance: number;
|
|
67
|
+
preview: string;
|
|
68
|
+
}
|
|
69
|
+
/** Semantic top-k recall over reindexed markdown (the doc_vec index). */
|
|
70
|
+
export declare function recallDocs(h: DbHandles, embedder: Embedder, text: string, k?: number): Promise<DocRecallRow[]>;
|
|
71
|
+
/** Render a date range of memories to markdown (for debugging/export). */
|
|
72
|
+
export declare function exportRange(h: DbHandles, since: string, until: string): Promise<string>;
|
|
73
|
+
/** Re-embed a stored memory's content (e.g. after an embedder/model change). */
|
|
74
|
+
export declare function reembed(h: DbHandles, embedder: Embedder, id: number): Promise<boolean>;
|
package/dist/memory.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readdirSync, readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import { vecToBuffer } from './embedder.js';
|
|
4
|
+
function todayUtc() {
|
|
5
|
+
return new Date().toISOString().slice(0, 10);
|
|
6
|
+
}
|
|
7
|
+
/** Atomic insert of the relational row + its embedding (raw transaction). */
|
|
8
|
+
export async function store(h, embedder, m) {
|
|
9
|
+
const vec = vecToBuffer(await embedder.embed(m.content));
|
|
10
|
+
const ins = h.raw.prepare(`INSERT INTO memories (content, source, observed, date, tags, meta)
|
|
11
|
+
VALUES (?, ?, ?, ?, ?, ?)`);
|
|
12
|
+
const insVec = h.raw.prepare('INSERT INTO memory_vec (rowid, embedding) VALUES (?, ?)');
|
|
13
|
+
const markSuperseded = h.raw.prepare('UPDATE memories SET superseded_by = ? WHERE id = ?');
|
|
14
|
+
const txn = h.raw.transaction(() => {
|
|
15
|
+
const info = ins.run(m.content, m.source ?? null, m.observed ?? null, m.date ?? todayUtc(), JSON.stringify(m.tags ?? []), JSON.stringify(m.meta ?? {}));
|
|
16
|
+
// vec0's xUpdate only accepts a 64-bit INTEGER binding; better-sqlite3
|
|
17
|
+
// promotes BigInt to SQLITE_INTEGER, while a plain Number fails vec0's
|
|
18
|
+
// "only integers allowed" check. Bind as BigInt; return as Number.
|
|
19
|
+
const id = Number(info.lastInsertRowid);
|
|
20
|
+
insVec.run(BigInt(id), vec);
|
|
21
|
+
// SUPERSEDE: keep history, link the old row forward (never a silent overwrite).
|
|
22
|
+
if (m.supersedes != null)
|
|
23
|
+
markSuperseded.run(id, m.supersedes);
|
|
24
|
+
return id;
|
|
25
|
+
});
|
|
26
|
+
return txn();
|
|
27
|
+
}
|
|
28
|
+
export async function query(h, opts = {}) {
|
|
29
|
+
let q = h.k('memories').select('*');
|
|
30
|
+
if (opts.source)
|
|
31
|
+
q = q.where('source', opts.source);
|
|
32
|
+
if (opts.observed)
|
|
33
|
+
q = q.where('observed', opts.observed);
|
|
34
|
+
if (opts.tag)
|
|
35
|
+
q = q.where('tags', 'like', `%"${opts.tag}"%`);
|
|
36
|
+
if (opts.since)
|
|
37
|
+
q = q.where('ts', '>=', opts.since);
|
|
38
|
+
if (opts.until)
|
|
39
|
+
q = q.where('ts', '<=', opts.until);
|
|
40
|
+
if (opts.liveOnly !== false)
|
|
41
|
+
q = q.whereNull('superseded_by');
|
|
42
|
+
return q.orderBy('ts', 'desc').limit(opts.limit ?? 50);
|
|
43
|
+
}
|
|
44
|
+
/** Semantic top-k recall over the memory store by meaning. */
|
|
45
|
+
export async function recall(h, embedder, text, k = 5) {
|
|
46
|
+
const qv = vecToBuffer(await embedder.embed(text));
|
|
47
|
+
// sqlite-vec's vec0 module needs the KNN size constraint at prepare time.
|
|
48
|
+
// `LIMIT ?` is only visible to vec0's xBestIndex on SQLite >= 3.41, so we
|
|
49
|
+
// use the portable `k = ?` form in the WHERE clause instead.
|
|
50
|
+
const stmt = h.raw.prepare(`SELECT m.*, v.distance
|
|
51
|
+
FROM memory_vec v
|
|
52
|
+
JOIN memories m ON m.id = v.rowid
|
|
53
|
+
WHERE v.embedding MATCH ? AND k = ?
|
|
54
|
+
AND m.superseded_by IS NULL
|
|
55
|
+
ORDER BY v.distance`);
|
|
56
|
+
return stmt.all(qv, k);
|
|
57
|
+
}
|
|
58
|
+
/** Full-text keyword search over the memory store (FTS5). */
|
|
59
|
+
export function lexical(h, text, k = 50) {
|
|
60
|
+
const stmt = h.raw.prepare(`SELECT m.*
|
|
61
|
+
FROM memory_fts f
|
|
62
|
+
JOIN memories m ON m.id = f.rowid
|
|
63
|
+
WHERE memory_fts MATCH ?
|
|
64
|
+
AND m.superseded_by IS NULL
|
|
65
|
+
ORDER BY rank
|
|
66
|
+
LIMIT ?`);
|
|
67
|
+
// FTS5 MATCH treats spaces as AND; quote each token defensively.
|
|
68
|
+
const safe = text.split(/\s+/).filter(Boolean).map((t) => `"${t.replace(/"/g, '""')}"`).join(' ');
|
|
69
|
+
return stmt.all(safe, k);
|
|
70
|
+
}
|
|
71
|
+
function sha256(s) {
|
|
72
|
+
return createHash('sha256').update(s).digest('hex');
|
|
73
|
+
}
|
|
74
|
+
function listMarkdown(root) {
|
|
75
|
+
if (!existsSync(root))
|
|
76
|
+
return [];
|
|
77
|
+
return readdirSync(root)
|
|
78
|
+
.filter((f) => f.endsWith('.md'))
|
|
79
|
+
.map((f) => `${root}/${f}`);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Self-heal the doc recall index from a directory of markdown files. Hashes
|
|
83
|
+
* content to skip unchanged files; removes index rows for files that vanished.
|
|
84
|
+
* Generic version of the original assistant's curated-doc reindex (no curated-corpus assumptions).
|
|
85
|
+
*/
|
|
86
|
+
export async function reindex(h, embedder, root) {
|
|
87
|
+
const files = listMarkdown(root);
|
|
88
|
+
const currentPaths = new Set(files);
|
|
89
|
+
const selIndexed = h.raw.prepare('SELECT id, file_path FROM index_state');
|
|
90
|
+
const selState = h.raw.prepare('SELECT id, sha256 FROM index_state WHERE file_path = ?');
|
|
91
|
+
const insState = h.raw.prepare('INSERT INTO index_state (file_path, sha256) VALUES (?, ?)');
|
|
92
|
+
const updState = h.raw.prepare("UPDATE index_state SET sha256 = ?, embedded_at = datetime('now') WHERE id = ?");
|
|
93
|
+
const delState = h.raw.prepare('DELETE FROM index_state WHERE id = ?');
|
|
94
|
+
const delVec = h.raw.prepare('DELETE FROM doc_vec WHERE rowid = ?');
|
|
95
|
+
const insVec = h.raw.prepare('INSERT INTO doc_vec (rowid, embedding) VALUES (?, ?)');
|
|
96
|
+
let indexed = 0;
|
|
97
|
+
let removed = 0;
|
|
98
|
+
for (const row of selIndexed.all()) {
|
|
99
|
+
if (currentPaths.has(row.file_path))
|
|
100
|
+
continue;
|
|
101
|
+
const t = h.raw.transaction(() => {
|
|
102
|
+
delVec.run(BigInt(row.id));
|
|
103
|
+
delState.run(row.id);
|
|
104
|
+
});
|
|
105
|
+
t();
|
|
106
|
+
removed++;
|
|
107
|
+
}
|
|
108
|
+
for (const path of files) {
|
|
109
|
+
const content = readFileSync(path, 'utf8');
|
|
110
|
+
const hash = sha256(content);
|
|
111
|
+
const existing = selState.get(path);
|
|
112
|
+
if (existing && existing.sha256 === hash)
|
|
113
|
+
continue;
|
|
114
|
+
const vec = vecToBuffer(await embedder.embed(content));
|
|
115
|
+
const t = h.raw.transaction(() => {
|
|
116
|
+
let id;
|
|
117
|
+
if (existing) {
|
|
118
|
+
id = existing.id;
|
|
119
|
+
updState.run(hash, id);
|
|
120
|
+
delVec.run(BigInt(id));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const info = insState.run(path, hash);
|
|
124
|
+
id = Number(info.lastInsertRowid);
|
|
125
|
+
}
|
|
126
|
+
// vec0's xUpdate only accepts a 64-bit INTEGER binding. Bind as BigInt.
|
|
127
|
+
insVec.run(BigInt(id), vec);
|
|
128
|
+
});
|
|
129
|
+
t();
|
|
130
|
+
indexed++;
|
|
131
|
+
}
|
|
132
|
+
return { indexed, removed };
|
|
133
|
+
}
|
|
134
|
+
/** Semantic top-k recall over reindexed markdown (the doc_vec index). */
|
|
135
|
+
export async function recallDocs(h, embedder, text, k = 5) {
|
|
136
|
+
const qv = vecToBuffer(await embedder.embed(text));
|
|
137
|
+
const stmt = h.raw.prepare(`SELECT s.file_path, v.distance
|
|
138
|
+
FROM doc_vec v
|
|
139
|
+
JOIN index_state s ON s.id = v.rowid
|
|
140
|
+
WHERE v.embedding MATCH ? AND k = ?
|
|
141
|
+
ORDER BY v.distance`);
|
|
142
|
+
const rows = stmt.all(qv, k);
|
|
143
|
+
return rows.map((r) => {
|
|
144
|
+
let preview = '';
|
|
145
|
+
try {
|
|
146
|
+
preview = readFileSync(r.file_path, 'utf8').slice(0, 200);
|
|
147
|
+
}
|
|
148
|
+
catch { /* removed since indexing */ }
|
|
149
|
+
return { file_path: r.file_path, distance: r.distance, preview };
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/** Render a date range of memories to markdown (for debugging/export). */
|
|
153
|
+
export async function exportRange(h, since, until) {
|
|
154
|
+
const rows = await h.k('memories')
|
|
155
|
+
.whereBetween('ts', [`${since} 00:00:00`, `${until} 23:59:59`])
|
|
156
|
+
.orderBy('ts', 'asc');
|
|
157
|
+
if (rows.length === 0)
|
|
158
|
+
return `# Memories — ${since}..${until}\n\n_(no entries)_\n`;
|
|
159
|
+
const body = rows
|
|
160
|
+
.map((r) => `### ${r.ts}${r.source ? ` · ${r.source}` : ''}${r.observed ? `/${r.observed}` : ''}\n\n${r.content}\n`)
|
|
161
|
+
.join('\n');
|
|
162
|
+
return `# Memories — ${since}..${until}\n\n${body}`;
|
|
163
|
+
}
|
|
164
|
+
/** Re-embed a stored memory's content (e.g. after an embedder/model change). */
|
|
165
|
+
export async function reembed(h, embedder, id) {
|
|
166
|
+
const row = await h.k('memories').select('content').where({ id }).first();
|
|
167
|
+
if (!row)
|
|
168
|
+
return false;
|
|
169
|
+
const vec = vecToBuffer(await embedder.embed(row.content));
|
|
170
|
+
const delVec = h.raw.prepare('DELETE FROM memory_vec WHERE rowid = ?');
|
|
171
|
+
const insVec = h.raw.prepare('INSERT INTO memory_vec (rowid, embedding) VALUES (?, ?)');
|
|
172
|
+
const txn = h.raw.transaction(() => {
|
|
173
|
+
delVec.run(BigInt(id));
|
|
174
|
+
insVec.run(BigInt(id), vec);
|
|
175
|
+
});
|
|
176
|
+
txn();
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
|
package/dist/migrate.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { openDb } from './db.js';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { mkdirSync } from 'node:fs';
|
|
4
|
+
import { dirname } from 'node:path';
|
|
5
|
+
import * as m001 from './migrations/001_init.js';
|
|
6
|
+
import * as m002 from './migrations/002_fts.js';
|
|
7
|
+
import * as m003 from './migrations/003_approvals.js';
|
|
8
|
+
// Static import list — deterministic under both vitest (resolves .js → .ts) and
|
|
9
|
+
// the built server (dist/migrations/*.js). No knex CLI, no dynamic-import path
|
|
10
|
+
// fragility.
|
|
11
|
+
const MIGRATIONS = [
|
|
12
|
+
{ name: '001_init', up: m001.up, down: m001.down },
|
|
13
|
+
{ name: '002_fts', up: m002.up, down: m002.down },
|
|
14
|
+
{ name: '003_approvals', up: m003.up, down: m003.down },
|
|
15
|
+
];
|
|
16
|
+
export async function runMigrations(k) {
|
|
17
|
+
await k.raw(`CREATE TABLE IF NOT EXISTS _migration_state (
|
|
18
|
+
name text primary key,
|
|
19
|
+
applied_at text not null default (datetime('now'))
|
|
20
|
+
)`);
|
|
21
|
+
const rows = (await k.raw('SELECT name FROM _migration_state'));
|
|
22
|
+
const done = new Set((Array.isArray(rows) ? rows : []).map((r) => r.name));
|
|
23
|
+
for (const m of MIGRATIONS) {
|
|
24
|
+
if (done.has(m.name))
|
|
25
|
+
continue;
|
|
26
|
+
await m.up(k);
|
|
27
|
+
await k.raw('INSERT INTO _migration_state (name) VALUES (?)', [m.name]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// `npm run migrate` entry point: open the DB at DB_PATH and apply migrations.
|
|
31
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
32
|
+
const dbPath = process.env.DB_PATH ? resolve(process.env.DB_PATH) : resolve('memory.db');
|
|
33
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
34
|
+
const h = openDb(dbPath);
|
|
35
|
+
await runMigrations(h.k);
|
|
36
|
+
await h.k.destroy();
|
|
37
|
+
// eslint-disable-next-line no-console
|
|
38
|
+
console.error(`[memory] migrations applied to ${dbPath}`);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,0BAA0B,CAAC;AACjD,OAAO,KAAK,IAAI,MAAM,yBAAyB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,+BAA+B,CAAC;AAItD,gFAAgF;AAChF,+EAA+E;AAC/E,aAAa;AACb,MAAM,UAAU,GAAwC;IACtD,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;IAClD,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;IACjD,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;CACxD,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,CAAO;IACzC,MAAM,CAAC,CAAC,GAAG,CACT;;;OAGG,CACJ,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAA4B,CAAC;IAC3F,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,SAAS;QAC/B,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACd,MAAM,CAAC,CAAC,GAAG,CAAC,gDAAgD,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACpD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACzF,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACzB,MAAM,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IACpB,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,kCAAkC,MAAM,EAAE,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Generic memory store. Stripped from the original assistant's 001_init: the journal_entries
|
|
2
|
+
// channel/direction/actor/approval_status columns, the `entities` table, and
|
|
3
|
+
// the registry_pending / registry_reminders tables (all original-assistant orchestration).
|
|
4
|
+
//
|
|
5
|
+
// The vec0 tables (memory_vec, doc_vec) are created on the raw sqlite-vec
|
|
6
|
+
// handle in db.ts — NOT here — because Knex's connection does not load the
|
|
7
|
+
// sqlite-vec extension. FTS5 (compiled into SQLite) is a migration (002_fts).
|
|
8
|
+
export async function up(k) {
|
|
9
|
+
await k.schema
|
|
10
|
+
.createTable('memories', (t) => {
|
|
11
|
+
t.increments('id').primary();
|
|
12
|
+
t.datetime('ts', { useTz: false }).notNullable().defaultTo(k.fn.now());
|
|
13
|
+
t.text('content').notNullable();
|
|
14
|
+
t.string('source').nullable(); // free-form provenance: owner | web | tool:foo
|
|
15
|
+
t.string('observed').nullable(); // free-form: stated | inferred | imported
|
|
16
|
+
t.string('date').nullable(); // ISO date the memory pertains to
|
|
17
|
+
t.text('tags').notNullable().defaultTo('[]');
|
|
18
|
+
t.text('meta').notNullable().defaultTo('{}');
|
|
19
|
+
// SUPERSEDE: links a stale row forward to the row that replaced it.
|
|
20
|
+
// History is never destroyed — superseded rows remain queryable.
|
|
21
|
+
t.integer('superseded_by').nullable();
|
|
22
|
+
t.index(['ts']);
|
|
23
|
+
t.index(['source']);
|
|
24
|
+
t.index(['observed']);
|
|
25
|
+
t.index(['date']);
|
|
26
|
+
t.index(['superseded_by']);
|
|
27
|
+
})
|
|
28
|
+
.createTable('index_state', (t) => {
|
|
29
|
+
t.increments('id').primary();
|
|
30
|
+
t.string('file_path').notNullable().unique();
|
|
31
|
+
t.string('sha256').notNullable();
|
|
32
|
+
t.datetime('embedded_at', { useTz: false }).notNullable().defaultTo(k.fn.now());
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export async function down(k) {
|
|
36
|
+
await k.schema
|
|
37
|
+
.dropTableIfExists('index_state')
|
|
38
|
+
.dropTableIfExists('memories');
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=001_init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"001_init.js","sourceRoot":"","sources":["../../src/migrations/001_init.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,6EAA6E;AAC7E,2FAA2F;AAC3F,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC,CAAO;IAC9B,MAAM,CAAC,CAAC,MAAM;SACX,WAAW,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE;QAC7B,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QACvE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAChC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAG,+CAA+C;QAChF,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,0CAA0C;QAC3E,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAK,kCAAkC;QACnE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7C,oEAAoE;QACpE,iEAAiE;QACjE,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAChB,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QACpB,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QACtB,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7B,CAAC,CAAC;SACD,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE;QAChC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,CAAC;QAC7C,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QACjC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,CAAO;IAChC,MAAM,CAAC,CAAC,MAAM;SACX,iBAAiB,CAAC,aAAa,CAAC;SAChC,iBAAiB,CAAC,UAAU,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// SQLite-only (FTS5 is built in). The triggers keep memory_fts in sync with the
|
|
2
|
+
// `memories` content column. Generic rename of the original assistant's journal_fts (003_fts).
|
|
3
|
+
export async function up(k) {
|
|
4
|
+
if (k.client.config.client !== 'better-sqlite3')
|
|
5
|
+
return;
|
|
6
|
+
await k.raw(`CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(content, content='memories', content_rowid='id')`);
|
|
7
|
+
await k.raw(`CREATE TRIGGER IF NOT EXISTS memory_ai AFTER INSERT ON memories BEGIN
|
|
8
|
+
INSERT INTO memory_fts(rowid, content) VALUES (new.id, new.content);
|
|
9
|
+
END`);
|
|
10
|
+
await k.raw(`CREATE TRIGGER IF NOT EXISTS memory_ad AFTER DELETE ON memories BEGIN
|
|
11
|
+
INSERT INTO memory_fts(memory_fts, rowid, content) VALUES('delete', old.id, old.content);
|
|
12
|
+
END`);
|
|
13
|
+
await k.raw(`CREATE TRIGGER IF NOT EXISTS memory_au AFTER UPDATE ON memories BEGIN
|
|
14
|
+
INSERT INTO memory_fts(memory_fts, rowid, content) VALUES('delete', old.id, old.content);
|
|
15
|
+
INSERT INTO memory_fts(rowid, content) VALUES (new.id, new.content);
|
|
16
|
+
END`);
|
|
17
|
+
}
|
|
18
|
+
export async function down(k) {
|
|
19
|
+
if (k.client.config.client !== 'better-sqlite3')
|
|
20
|
+
return;
|
|
21
|
+
await k.raw('DROP TRIGGER IF EXISTS memory_au');
|
|
22
|
+
await k.raw('DROP TRIGGER IF EXISTS memory_ad');
|
|
23
|
+
await k.raw('DROP TRIGGER IF EXISTS memory_ai');
|
|
24
|
+
await k.raw('DROP TABLE IF EXISTS memory_fts');
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=002_fts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"002_fts.js","sourceRoot":"","sources":["../../src/migrations/002_fts.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,+FAA+F;AAC/F,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC,CAAO;IAC9B,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,gBAAgB;QAAE,OAAO;IACxD,MAAM,CAAC,CAAC,GAAG,CAAC,2GAA2G,CAAC,CAAC;IACzH,MAAM,CAAC,CAAC,GAAG,CAAC;;MAER,CAAC,CAAC;IACN,MAAM,CAAC,CAAC,GAAG,CAAC;;MAER,CAAC,CAAC;IACN,MAAM,CAAC,CAAC,GAAG,CAAC;;;MAGR,CAAC,CAAC;AACR,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,CAAO;IAChC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,gBAAgB;QAAE,OAAO;IACxD,MAAM,CAAC,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAChD,MAAM,CAAC,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAChD,MAAM,CAAC,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAChD,MAAM,CAAC,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AACjD,CAAC"}
|