@persql/context 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.
@@ -0,0 +1,87 @@
1
+ import { PerSQLDatabase } from '@persql/sdk';
2
+ import { ExtractedContext, RememberInput, RecallOptions, MemoryRow, ListOptions, Entity, Edge } from './core.cjs';
3
+ export { EXTRACTION_JSON_SCHEMA, EXTRACTION_SYSTEM_PROMPT, EdgeInput, EntityInput, MemoryKind, SCHEMA_SQL, SCHEMA_VERSION, SqlStatement, TABLE_PREFIX, buildByTag, buildEdgesAmong, buildExtractionMessages, buildForget, buildGet, buildInit, buildNeighborEntities, buildRecall, buildRecent, buildRemember, buildStats, buildSupersede, buildUpsertEdge, buildUpsertEntity, entityId, normalizeTags, toFtsQuery } from './core.cjs';
4
+
5
+ /**
6
+ * @persql/context — shared, structured agent context on the PerSQL substrate.
7
+ *
8
+ * One store, readable and writable from every agent surface PerSQL speaks
9
+ * (SDK, MCP, published endpoints, CLI). Reads and structured writes are plain
10
+ * SQL over `@persql/sdk` — cheap, exact, lexical (FTS5). The raw-dump extract
11
+ * path puts the LLM on the *write* side: file once, recall by keyword forever.
12
+ */
13
+
14
+ /** Bring-your-own-LLM extractor, or use the hosted PerSQL Context worker. */
15
+ type Extractor = (raw: string, ctx: {
16
+ hint?: string;
17
+ }) => Promise<ExtractedContext>;
18
+ interface ContextStoreOptions {
19
+ /** Default extractor for `rememberRaw` (model-agnostic; you supply it). */
20
+ extract?: Extractor;
21
+ /** Default provenance label stamped on writes (e.g. "claude-code"). */
22
+ source?: string;
23
+ }
24
+ interface WriteResult {
25
+ memoryIds: string[];
26
+ entityIds: string[];
27
+ edgeCount: number;
28
+ }
29
+ interface ContextStats {
30
+ facts: number;
31
+ factsTotal: number;
32
+ entities: number;
33
+ edges: number;
34
+ }
35
+ declare class ContextStore {
36
+ private readonly db;
37
+ private readonly opts;
38
+ constructor(db: PerSQLDatabase, opts?: ContextStoreOptions);
39
+ /** Create the schema (idempotent). Run once before first use. */
40
+ init(): Promise<void>;
41
+ /** Store one structured fact/episode/artifact. Returns its id. */
42
+ remember(input: RememberInput): Promise<string>;
43
+ /**
44
+ * Extract durable context from raw text and store it. The LLM runs on the
45
+ * write path; pass `extract` here or to the constructor (or use the hosted
46
+ * Context MCP, which runs extraction server-side and meters it).
47
+ */
48
+ rememberRaw(raw: string, opts?: {
49
+ extract?: Extractor;
50
+ hint?: string;
51
+ source?: string;
52
+ }): Promise<WriteResult>;
53
+ /** Persist an already-extracted bundle of facts, entities, and edges. */
54
+ write(extracted: ExtractedContext, opts?: {
55
+ source?: string;
56
+ }): Promise<WriteResult>;
57
+ /** Mark older memory rows as replaced by `newId` (filtered out of recall). */
58
+ supersede(oldIds: string | string[], newId: string): Promise<void>;
59
+ /** Hard-delete a memory row. */
60
+ forget(id: string): Promise<void>;
61
+ /** Add a relationship between two entities (created if absent). */
62
+ link(src: string, rel: string, dst: string, opts?: {
63
+ source?: string;
64
+ }): Promise<void>;
65
+ /** Keyword recall, BM25-ranked, most relevant first. */
66
+ recall(query: string, opts?: RecallOptions): Promise<MemoryRow[]>;
67
+ /** Most recent memory rows. */
68
+ recent(opts?: ListOptions): Promise<MemoryRow[]>;
69
+ /** Memory rows carrying a given tag. */
70
+ byTag(tag: string, opts?: ListOptions): Promise<MemoryRow[]>;
71
+ /** Fetch one memory row by id, or null. */
72
+ get(id: string): Promise<MemoryRow | null>;
73
+ /** The subgraph around an entity: reachable entities + the edges among them. */
74
+ neighbors(name: string, opts?: {
75
+ depth?: number;
76
+ limit?: number;
77
+ }): Promise<{
78
+ entities: Entity[];
79
+ edges: Edge[];
80
+ }>;
81
+ /** Counts: current facts, total facts, entities, edges. */
82
+ stats(): Promise<ContextStats>;
83
+ }
84
+ /** Wrap a PerSQL database handle as a shared context store. */
85
+ declare function context(db: PerSQLDatabase, opts?: ContextStoreOptions): ContextStore;
86
+
87
+ export { type ContextStats, ContextStore, type ContextStoreOptions, Edge, Entity, ExtractedContext, type Extractor, ListOptions, MemoryRow, RecallOptions, RememberInput, type WriteResult, context };
@@ -0,0 +1,87 @@
1
+ import { PerSQLDatabase } from '@persql/sdk';
2
+ import { ExtractedContext, RememberInput, RecallOptions, MemoryRow, ListOptions, Entity, Edge } from './core.js';
3
+ export { EXTRACTION_JSON_SCHEMA, EXTRACTION_SYSTEM_PROMPT, EdgeInput, EntityInput, MemoryKind, SCHEMA_SQL, SCHEMA_VERSION, SqlStatement, TABLE_PREFIX, buildByTag, buildEdgesAmong, buildExtractionMessages, buildForget, buildGet, buildInit, buildNeighborEntities, buildRecall, buildRecent, buildRemember, buildStats, buildSupersede, buildUpsertEdge, buildUpsertEntity, entityId, normalizeTags, toFtsQuery } from './core.js';
4
+
5
+ /**
6
+ * @persql/context — shared, structured agent context on the PerSQL substrate.
7
+ *
8
+ * One store, readable and writable from every agent surface PerSQL speaks
9
+ * (SDK, MCP, published endpoints, CLI). Reads and structured writes are plain
10
+ * SQL over `@persql/sdk` — cheap, exact, lexical (FTS5). The raw-dump extract
11
+ * path puts the LLM on the *write* side: file once, recall by keyword forever.
12
+ */
13
+
14
+ /** Bring-your-own-LLM extractor, or use the hosted PerSQL Context worker. */
15
+ type Extractor = (raw: string, ctx: {
16
+ hint?: string;
17
+ }) => Promise<ExtractedContext>;
18
+ interface ContextStoreOptions {
19
+ /** Default extractor for `rememberRaw` (model-agnostic; you supply it). */
20
+ extract?: Extractor;
21
+ /** Default provenance label stamped on writes (e.g. "claude-code"). */
22
+ source?: string;
23
+ }
24
+ interface WriteResult {
25
+ memoryIds: string[];
26
+ entityIds: string[];
27
+ edgeCount: number;
28
+ }
29
+ interface ContextStats {
30
+ facts: number;
31
+ factsTotal: number;
32
+ entities: number;
33
+ edges: number;
34
+ }
35
+ declare class ContextStore {
36
+ private readonly db;
37
+ private readonly opts;
38
+ constructor(db: PerSQLDatabase, opts?: ContextStoreOptions);
39
+ /** Create the schema (idempotent). Run once before first use. */
40
+ init(): Promise<void>;
41
+ /** Store one structured fact/episode/artifact. Returns its id. */
42
+ remember(input: RememberInput): Promise<string>;
43
+ /**
44
+ * Extract durable context from raw text and store it. The LLM runs on the
45
+ * write path; pass `extract` here or to the constructor (or use the hosted
46
+ * Context MCP, which runs extraction server-side and meters it).
47
+ */
48
+ rememberRaw(raw: string, opts?: {
49
+ extract?: Extractor;
50
+ hint?: string;
51
+ source?: string;
52
+ }): Promise<WriteResult>;
53
+ /** Persist an already-extracted bundle of facts, entities, and edges. */
54
+ write(extracted: ExtractedContext, opts?: {
55
+ source?: string;
56
+ }): Promise<WriteResult>;
57
+ /** Mark older memory rows as replaced by `newId` (filtered out of recall). */
58
+ supersede(oldIds: string | string[], newId: string): Promise<void>;
59
+ /** Hard-delete a memory row. */
60
+ forget(id: string): Promise<void>;
61
+ /** Add a relationship between two entities (created if absent). */
62
+ link(src: string, rel: string, dst: string, opts?: {
63
+ source?: string;
64
+ }): Promise<void>;
65
+ /** Keyword recall, BM25-ranked, most relevant first. */
66
+ recall(query: string, opts?: RecallOptions): Promise<MemoryRow[]>;
67
+ /** Most recent memory rows. */
68
+ recent(opts?: ListOptions): Promise<MemoryRow[]>;
69
+ /** Memory rows carrying a given tag. */
70
+ byTag(tag: string, opts?: ListOptions): Promise<MemoryRow[]>;
71
+ /** Fetch one memory row by id, or null. */
72
+ get(id: string): Promise<MemoryRow | null>;
73
+ /** The subgraph around an entity: reachable entities + the edges among them. */
74
+ neighbors(name: string, opts?: {
75
+ depth?: number;
76
+ limit?: number;
77
+ }): Promise<{
78
+ entities: Entity[];
79
+ edges: Edge[];
80
+ }>;
81
+ /** Counts: current facts, total facts, entities, edges. */
82
+ stats(): Promise<ContextStats>;
83
+ }
84
+ /** Wrap a PerSQL database handle as a shared context store. */
85
+ declare function context(db: PerSQLDatabase, opts?: ContextStoreOptions): ContextStore;
86
+
87
+ export { type ContextStats, ContextStore, type ContextStoreOptions, Edge, Entity, ExtractedContext, type Extractor, ListOptions, MemoryRow, RecallOptions, RememberInput, type WriteResult, context };
package/dist/index.js ADDED
@@ -0,0 +1,210 @@
1
+ import {
2
+ EXTRACTION_JSON_SCHEMA,
3
+ EXTRACTION_SYSTEM_PROMPT,
4
+ SCHEMA_SQL,
5
+ SCHEMA_VERSION,
6
+ TABLE_PREFIX,
7
+ buildByTag,
8
+ buildEdgesAmong,
9
+ buildExtractionMessages,
10
+ buildForget,
11
+ buildGet,
12
+ buildInit,
13
+ buildNeighborEntities,
14
+ buildRecall,
15
+ buildRecent,
16
+ buildRemember,
17
+ buildStats,
18
+ buildSupersede,
19
+ buildUpsertEdge,
20
+ buildUpsertEntity,
21
+ entityId,
22
+ normalizeTags,
23
+ toFtsQuery
24
+ } from "./chunk-RMG66FDI.js";
25
+
26
+ // src/index.ts
27
+ function uid(prefix) {
28
+ const g = globalThis;
29
+ const r = g.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`;
30
+ return prefix + r;
31
+ }
32
+ var ContextStore = class {
33
+ constructor(db, opts = {}) {
34
+ this.db = db;
35
+ this.opts = opts;
36
+ }
37
+ /** Create the schema (idempotent). Run once before first use. */
38
+ async init() {
39
+ await this.db.batch(buildInit());
40
+ }
41
+ // --- writes -------------------------------------------------------------
42
+ /** Store one structured fact/episode/artifact. Returns its id. */
43
+ async remember(input) {
44
+ const id = input.id ?? uid("m_");
45
+ const now = Date.now();
46
+ const stmts = [
47
+ buildRemember({ ...input, source: input.source ?? this.opts.source }, now, id)
48
+ ];
49
+ const sup = input.supersedes ? Array.isArray(input.supersedes) ? input.supersedes : [input.supersedes] : [];
50
+ for (const old of sup) stmts.push(buildSupersede(old, id));
51
+ await this.db.transaction(stmts);
52
+ return id;
53
+ }
54
+ /**
55
+ * Extract durable context from raw text and store it. The LLM runs on the
56
+ * write path; pass `extract` here or to the constructor (or use the hosted
57
+ * Context MCP, which runs extraction server-side and meters it).
58
+ */
59
+ async rememberRaw(raw, opts = {}) {
60
+ const extract = opts.extract ?? this.opts.extract;
61
+ if (!extract) {
62
+ throw new Error(
63
+ "ContextStore.rememberRaw needs an extractor: pass { extract } here or to the constructor, or use the hosted PerSQL Context MCP."
64
+ );
65
+ }
66
+ const extracted = await extract(raw, { hint: opts.hint });
67
+ return this.write(extracted, { source: opts.source });
68
+ }
69
+ /** Persist an already-extracted bundle of facts, entities, and edges. */
70
+ async write(extracted, opts = {}) {
71
+ const now = Date.now();
72
+ const source = opts.source ?? this.opts.source;
73
+ const stmts = [];
74
+ const memoryIds = [];
75
+ const entityIds = /* @__PURE__ */ new Set();
76
+ for (const f of extracted.facts ?? []) {
77
+ const id = uid("m_");
78
+ memoryIds.push(id);
79
+ stmts.push(buildRemember({ ...f, source }, now, id));
80
+ }
81
+ for (const e of extracted.entities ?? []) {
82
+ stmts.push(buildUpsertEntity(e, now));
83
+ entityIds.add(e.id ?? entityId(e.name));
84
+ }
85
+ for (const ed of extracted.edges ?? []) {
86
+ stmts.push(buildUpsertEntity({ name: ed.src }, now));
87
+ stmts.push(buildUpsertEntity({ name: ed.dst }, now));
88
+ stmts.push(buildUpsertEdge({ ...ed, source: ed.source ?? source }, now));
89
+ entityIds.add(entityId(ed.src));
90
+ entityIds.add(entityId(ed.dst));
91
+ }
92
+ if (stmts.length) await this.db.transaction(stmts);
93
+ return {
94
+ memoryIds,
95
+ entityIds: [...entityIds],
96
+ edgeCount: (extracted.edges ?? []).length
97
+ };
98
+ }
99
+ /** Mark older memory rows as replaced by `newId` (filtered out of recall). */
100
+ async supersede(oldIds, newId) {
101
+ const ids = Array.isArray(oldIds) ? oldIds : [oldIds];
102
+ await this.db.transaction(ids.map((o) => buildSupersede(o, newId)));
103
+ }
104
+ /** Hard-delete a memory row. */
105
+ async forget(id) {
106
+ const s = buildForget(id);
107
+ await this.db.query(s.sql, s.params);
108
+ }
109
+ /** Add a relationship between two entities (created if absent). */
110
+ async link(src, rel, dst, opts = {}) {
111
+ const now = Date.now();
112
+ await this.db.transaction([
113
+ buildUpsertEntity({ name: src }, now),
114
+ buildUpsertEntity({ name: dst }, now),
115
+ buildUpsertEdge(
116
+ { src, rel, dst, source: opts.source ?? this.opts.source },
117
+ now
118
+ )
119
+ ]);
120
+ }
121
+ // --- reads (no AI, pure lexical SQL) ------------------------------------
122
+ /** Keyword recall, BM25-ranked, most relevant first. */
123
+ async recall(query, opts = {}) {
124
+ const resolved = { ...opts };
125
+ if (opts.withinDays != null && opts.sinceMs == null) {
126
+ resolved.sinceMs = Date.now() - opts.withinDays * 864e5;
127
+ }
128
+ const s = buildRecall(query, resolved);
129
+ if (!s) return [];
130
+ const { data } = await this.db.query(s.sql, s.params);
131
+ return data;
132
+ }
133
+ /** Most recent memory rows. */
134
+ async recent(opts = {}) {
135
+ const s = buildRecent(opts);
136
+ const { data } = await this.db.query(s.sql, s.params);
137
+ return data;
138
+ }
139
+ /** Memory rows carrying a given tag. */
140
+ async byTag(tag, opts = {}) {
141
+ const s = buildByTag(tag, opts);
142
+ const { data } = await this.db.query(s.sql, s.params);
143
+ return data;
144
+ }
145
+ /** Fetch one memory row by id, or null. */
146
+ async get(id) {
147
+ const s = buildGet(id);
148
+ const { data } = await this.db.query(s.sql, s.params);
149
+ return data[0] ?? null;
150
+ }
151
+ /** The subgraph around an entity: reachable entities + the edges among them. */
152
+ async neighbors(name, opts = {}) {
153
+ const seed = name.startsWith("e_") ? name : entityId(name);
154
+ const depth = Math.min(Math.max(opts.depth ?? 1, 1), 4);
155
+ const entStmt = buildNeighborEntities(seed, depth, opts.limit ?? 50);
156
+ const { data: entities } = await this.db.query(
157
+ entStmt.sql,
158
+ entStmt.params
159
+ );
160
+ const ids = [seed, ...entities.map((e) => e.id)];
161
+ const edgeStmt = buildEdgesAmong(ids);
162
+ const { data: edges } = await this.db.query(
163
+ edgeStmt.sql,
164
+ edgeStmt.params
165
+ );
166
+ return { entities, edges };
167
+ }
168
+ /** Counts: current facts, total facts, entities, edges. */
169
+ async stats() {
170
+ const s = buildStats();
171
+ const { data } = await this.db.query(s.sql, s.params);
172
+ const r = data[0];
173
+ return {
174
+ facts: r?.facts ?? 0,
175
+ factsTotal: r?.facts_total ?? 0,
176
+ entities: r?.entities ?? 0,
177
+ edges: r?.edges ?? 0
178
+ };
179
+ }
180
+ };
181
+ function context(db, opts) {
182
+ return new ContextStore(db, opts);
183
+ }
184
+ export {
185
+ ContextStore,
186
+ EXTRACTION_JSON_SCHEMA,
187
+ EXTRACTION_SYSTEM_PROMPT,
188
+ SCHEMA_SQL,
189
+ SCHEMA_VERSION,
190
+ TABLE_PREFIX,
191
+ buildByTag,
192
+ buildEdgesAmong,
193
+ buildExtractionMessages,
194
+ buildForget,
195
+ buildGet,
196
+ buildInit,
197
+ buildNeighborEntities,
198
+ buildRecall,
199
+ buildRecent,
200
+ buildRemember,
201
+ buildStats,
202
+ buildSupersede,
203
+ buildUpsertEdge,
204
+ buildUpsertEntity,
205
+ context,
206
+ entityId,
207
+ normalizeTags,
208
+ toFtsQuery
209
+ };
210
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @persql/context — shared, structured agent context on the PerSQL substrate.\n *\n * One store, readable and writable from every agent surface PerSQL speaks\n * (SDK, MCP, published endpoints, CLI). Reads and structured writes are plain\n * SQL over `@persql/sdk` — cheap, exact, lexical (FTS5). The raw-dump extract\n * path puts the LLM on the *write* side: file once, recall by keyword forever.\n */\n\nimport type { PerSQLDatabase } from \"@persql/sdk\";\nimport {\n buildInit,\n buildRemember,\n buildSupersede,\n buildForget,\n buildGet,\n buildRecall,\n buildRecent,\n buildByTag,\n buildStats,\n buildUpsertEntity,\n buildUpsertEdge,\n buildNeighborEntities,\n buildEdgesAmong,\n entityId,\n type RememberInput,\n type RecallOptions,\n type ListOptions,\n type MemoryRow,\n type EntityInput,\n type Edge,\n type Entity,\n type ExtractedContext,\n type SqlStatement,\n} from \"./core\";\n\nexport * from \"./core\";\n\n/** Bring-your-own-LLM extractor, or use the hosted PerSQL Context worker. */\nexport type Extractor = (\n raw: string,\n ctx: { hint?: string }\n) => Promise<ExtractedContext>;\n\nexport interface ContextStoreOptions {\n /** Default extractor for `rememberRaw` (model-agnostic; you supply it). */\n extract?: Extractor;\n /** Default provenance label stamped on writes (e.g. \"claude-code\"). */\n source?: string;\n}\n\nexport interface WriteResult {\n memoryIds: string[];\n entityIds: string[];\n edgeCount: number;\n}\n\nexport interface ContextStats {\n facts: number;\n factsTotal: number;\n entities: number;\n edges: number;\n}\n\nfunction uid(prefix: string): string {\n const g = globalThis as { crypto?: { randomUUID?: () => string } };\n const r =\n g.crypto?.randomUUID?.() ??\n `${Date.now().toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`;\n return prefix + r;\n}\n\nexport class ContextStore {\n constructor(\n private readonly db: PerSQLDatabase,\n private readonly opts: ContextStoreOptions = {}\n ) {}\n\n /** Create the schema (idempotent). Run once before first use. */\n async init(): Promise<void> {\n await this.db.batch(buildInit());\n }\n\n // --- writes -------------------------------------------------------------\n\n /** Store one structured fact/episode/artifact. Returns its id. */\n async remember(input: RememberInput): Promise<string> {\n const id = input.id ?? uid(\"m_\");\n const now = Date.now();\n const stmts: SqlStatement[] = [\n buildRemember({ ...input, source: input.source ?? this.opts.source }, now, id),\n ];\n const sup = input.supersedes\n ? Array.isArray(input.supersedes)\n ? input.supersedes\n : [input.supersedes]\n : [];\n for (const old of sup) stmts.push(buildSupersede(old, id));\n await this.db.transaction(stmts);\n return id;\n }\n\n /**\n * Extract durable context from raw text and store it. The LLM runs on the\n * write path; pass `extract` here or to the constructor (or use the hosted\n * Context MCP, which runs extraction server-side and meters it).\n */\n async rememberRaw(\n raw: string,\n opts: { extract?: Extractor; hint?: string; source?: string } = {}\n ): Promise<WriteResult> {\n const extract = opts.extract ?? this.opts.extract;\n if (!extract) {\n throw new Error(\n \"ContextStore.rememberRaw needs an extractor: pass { extract } here or to the constructor, or use the hosted PerSQL Context MCP.\"\n );\n }\n const extracted = await extract(raw, { hint: opts.hint });\n return this.write(extracted, { source: opts.source });\n }\n\n /** Persist an already-extracted bundle of facts, entities, and edges. */\n async write(\n extracted: ExtractedContext,\n opts: { source?: string } = {}\n ): Promise<WriteResult> {\n const now = Date.now();\n const source = opts.source ?? this.opts.source;\n const stmts: SqlStatement[] = [];\n const memoryIds: string[] = [];\n const entityIds = new Set<string>();\n\n for (const f of extracted.facts ?? []) {\n const id = uid(\"m_\");\n memoryIds.push(id);\n stmts.push(buildRemember({ ...f, source }, now, id));\n }\n for (const e of extracted.entities ?? []) {\n stmts.push(buildUpsertEntity(e, now));\n entityIds.add(e.id ?? entityId(e.name));\n }\n for (const ed of extracted.edges ?? []) {\n // Ensure both endpoints exist before linking them.\n stmts.push(buildUpsertEntity({ name: ed.src }, now));\n stmts.push(buildUpsertEntity({ name: ed.dst }, now));\n stmts.push(buildUpsertEdge({ ...ed, source: ed.source ?? source }, now));\n entityIds.add(entityId(ed.src));\n entityIds.add(entityId(ed.dst));\n }\n\n if (stmts.length) await this.db.transaction(stmts);\n return {\n memoryIds,\n entityIds: [...entityIds],\n edgeCount: (extracted.edges ?? []).length,\n };\n }\n\n /** Mark older memory rows as replaced by `newId` (filtered out of recall). */\n async supersede(oldIds: string | string[], newId: string): Promise<void> {\n const ids = Array.isArray(oldIds) ? oldIds : [oldIds];\n await this.db.transaction(ids.map((o) => buildSupersede(o, newId)));\n }\n\n /** Hard-delete a memory row. */\n async forget(id: string): Promise<void> {\n const s = buildForget(id);\n await this.db.query(s.sql, s.params);\n }\n\n /** Add a relationship between two entities (created if absent). */\n async link(\n src: string,\n rel: string,\n dst: string,\n opts: { source?: string } = {}\n ): Promise<void> {\n const now = Date.now();\n await this.db.transaction([\n buildUpsertEntity({ name: src }, now),\n buildUpsertEntity({ name: dst }, now),\n buildUpsertEdge(\n { src, rel, dst, source: opts.source ?? this.opts.source },\n now\n ),\n ]);\n }\n\n // --- reads (no AI, pure lexical SQL) ------------------------------------\n\n /** Keyword recall, BM25-ranked, most relevant first. */\n async recall(query: string, opts: RecallOptions = {}): Promise<MemoryRow[]> {\n const resolved: RecallOptions = { ...opts };\n if (opts.withinDays != null && opts.sinceMs == null) {\n resolved.sinceMs = Date.now() - opts.withinDays * 86_400_000;\n }\n const s = buildRecall(query, resolved);\n if (!s) return [];\n const { data } = await this.db.query<MemoryRow>(s.sql, s.params);\n return data;\n }\n\n /** Most recent memory rows. */\n async recent(opts: ListOptions = {}): Promise<MemoryRow[]> {\n const s = buildRecent(opts);\n const { data } = await this.db.query<MemoryRow>(s.sql, s.params);\n return data;\n }\n\n /** Memory rows carrying a given tag. */\n async byTag(tag: string, opts: ListOptions = {}): Promise<MemoryRow[]> {\n const s = buildByTag(tag, opts);\n const { data } = await this.db.query<MemoryRow>(s.sql, s.params);\n return data;\n }\n\n /** Fetch one memory row by id, or null. */\n async get(id: string): Promise<MemoryRow | null> {\n const s = buildGet(id);\n const { data } = await this.db.query<MemoryRow>(s.sql, s.params);\n return data[0] ?? null;\n }\n\n /** The subgraph around an entity: reachable entities + the edges among them. */\n async neighbors(\n name: string,\n opts: { depth?: number; limit?: number } = {}\n ): Promise<{ entities: Entity[]; edges: Edge[] }> {\n const seed = name.startsWith(\"e_\") ? name : entityId(name);\n const depth = Math.min(Math.max(opts.depth ?? 1, 1), 4);\n const entStmt = buildNeighborEntities(seed, depth, opts.limit ?? 50);\n const { data: entities } = await this.db.query<Entity>(\n entStmt.sql,\n entStmt.params\n );\n const ids = [seed, ...entities.map((e) => e.id)];\n const edgeStmt = buildEdgesAmong(ids);\n const { data: edges } = await this.db.query<Edge>(\n edgeStmt.sql,\n edgeStmt.params\n );\n return { entities, edges };\n }\n\n /** Counts: current facts, total facts, entities, edges. */\n async stats(): Promise<ContextStats> {\n const s = buildStats();\n const { data } = await this.db.query<{\n facts: number;\n facts_total: number;\n entities: number;\n edges: number;\n }>(s.sql, s.params);\n const r = data[0];\n return {\n facts: r?.facts ?? 0,\n factsTotal: r?.facts_total ?? 0,\n entities: r?.entities ?? 0,\n edges: r?.edges ?? 0,\n };\n }\n}\n\n/** Wrap a PerSQL database handle as a shared context store. */\nexport function context(\n db: PerSQLDatabase,\n opts?: ContextStoreOptions\n): ContextStore {\n return new ContextStore(db, opts);\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@persql/context",
3
+ "version": "0.1.0",
4
+ "description": "Shared, structured agent context for PerSQL — durable facts, entities, and a keyword-recallable memory graph in plain SQL. No vector database.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ },
16
+ "./core": {
17
+ "types": "./dist/core.d.ts",
18
+ "import": "./dist/core.js",
19
+ "require": "./dist/core.cjs"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "peerDependencies": {
27
+ "@persql/sdk": "^1.4.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.10.0",
31
+ "better-sqlite3": "^11.7.0",
32
+ "tsup": "^8.4.0",
33
+ "typescript": "^5.8.3",
34
+ "vitest": "^3.1.1",
35
+ "@persql/sdk": "1.4.0"
36
+ },
37
+ "keywords": [
38
+ "persql",
39
+ "agent",
40
+ "context",
41
+ "memory",
42
+ "shared-memory",
43
+ "fts5",
44
+ "sqlite",
45
+ "mcp"
46
+ ],
47
+ "scripts": {
48
+ "build": "tsup",
49
+ "typecheck": "tsc --noEmit",
50
+ "test": "vitest run",
51
+ "clean": "rm -rf dist"
52
+ }
53
+ }