@j0hanz/memdb 1.0.11 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +82 -120
  2. package/dist/config.d.ts +4 -0
  3. package/dist/config.js +13 -0
  4. package/dist/core/database-schema.d.ts +0 -1
  5. package/dist/core/database-schema.js +0 -1
  6. package/dist/core/database.d.ts +0 -1
  7. package/dist/core/database.js +0 -1
  8. package/dist/core/db.d.ts +16 -0
  9. package/dist/core/db.js +232 -0
  10. package/dist/core/memory-create.d.ts +0 -1
  11. package/dist/core/memory-create.js +13 -7
  12. package/dist/core/memory-db.d.ts +0 -1
  13. package/dist/core/memory-db.js +0 -1
  14. package/dist/core/memory-read.d.ts +2 -2
  15. package/dist/core/memory-read.js +32 -4
  16. package/dist/core/memory-relations.d.ts +0 -1
  17. package/dist/core/memory-relations.js +0 -1
  18. package/dist/core/memory-search.d.ts +8 -7
  19. package/dist/core/memory-search.js +15 -9
  20. package/dist/core/memory-stats.d.ts +0 -1
  21. package/dist/core/memory-stats.js +0 -1
  22. package/dist/core/memory-updates.d.ts +0 -1
  23. package/dist/core/memory-updates.js +1 -2
  24. package/dist/core/memory-write.d.ts +13 -0
  25. package/dist/core/memory-write.js +113 -0
  26. package/dist/core/relation-queries.d.ts +0 -1
  27. package/dist/core/relation-queries.js +0 -1
  28. package/dist/core/relations.d.ts +10 -0
  29. package/dist/core/relations.js +177 -0
  30. package/dist/core/row-mappers.d.ts +0 -1
  31. package/dist/core/row-mappers.js +0 -1
  32. package/dist/core/search-errors.d.ts +0 -1
  33. package/dist/core/search-errors.js +0 -1
  34. package/dist/core/search.d.ts +5 -12
  35. package/dist/core/search.js +77 -56
  36. package/dist/core/sqlite.d.ts +0 -1
  37. package/dist/core/sqlite.js +0 -3
  38. package/dist/core/tags.d.ts +0 -1
  39. package/dist/core/tags.js +1 -2
  40. package/dist/index.d.ts +0 -1
  41. package/dist/index.js +58 -37
  42. package/dist/lib/errors.d.ts +0 -1
  43. package/dist/lib/errors.js +0 -1
  44. package/dist/logger.d.ts +5 -0
  45. package/dist/logger.js +17 -0
  46. package/dist/protocol-version-guard.d.ts +17 -0
  47. package/dist/protocol-version-guard.js +100 -0
  48. package/dist/schemas/inputs.d.ts +0 -1
  49. package/dist/schemas/inputs.js +0 -1
  50. package/dist/schemas/outputs.d.ts +0 -1
  51. package/dist/schemas/outputs.js +0 -1
  52. package/dist/schemas.d.ts +28 -0
  53. package/dist/schemas.js +65 -0
  54. package/dist/tools/definitions/memory-core.d.ts +0 -1
  55. package/dist/tools/definitions/memory-core.js +0 -1
  56. package/dist/tools/definitions/memory-relations.d.ts +0 -1
  57. package/dist/tools/definitions/memory-relations.js +0 -1
  58. package/dist/tools/definitions/memory-search.d.ts +0 -1
  59. package/dist/tools/definitions/memory-search.js +1 -11
  60. package/dist/tools/definitions/memory-stats.d.ts +0 -1
  61. package/dist/tools/definitions/memory-stats.js +0 -1
  62. package/dist/tools/index.d.ts +0 -1
  63. package/dist/tools/index.js +0 -1
  64. package/dist/tools/tool-handlers.d.ts +0 -1
  65. package/dist/tools/tool-handlers.js +0 -1
  66. package/dist/tools/tool-types.d.ts +0 -1
  67. package/dist/tools/tool-types.js +0 -1
  68. package/dist/tools.d.ts +18 -0
  69. package/dist/tools.js +167 -0
  70. package/dist/tsconfig.tsbuildinfo +1 -0
  71. package/dist/types/index.d.ts +0 -1
  72. package/dist/types/index.js +0 -1
  73. package/dist/types.d.ts +30 -0
  74. package/dist/types.js +1 -0
  75. package/dist/utils/config.d.ts +0 -1
  76. package/dist/utils/config.js +0 -1
  77. package/dist/utils/logger.d.ts +0 -1
  78. package/dist/utils/logger.js +0 -1
  79. package/dist/utils.d.ts +11 -0
  80. package/dist/utils.js +118 -0
  81. package/dist/worker/db-worker-client.d.ts +9 -0
  82. package/dist/worker/db-worker-client.js +93 -0
  83. package/dist/worker/db-worker.d.ts +1 -0
  84. package/dist/worker/db-worker.js +174 -0
  85. package/dist/worker/protocol.d.ts +9 -0
  86. package/dist/worker/protocol.js +14 -0
  87. package/package.json +8 -5
@@ -1,78 +1,91 @@
1
- import { toSearchError } from './search-errors.js';
2
- import { executeAll, prepareCached } from './sqlite.js';
1
+ import { executeAll, mapRowToSearchResult, prepareCached, } from './db.js';
3
2
  const MAX_QUERY_TOKENS = 50;
3
+ const DEFAULT_LIMIT = 100;
4
4
  const tokenizeQuery = (query) => {
5
5
  const parts = query
6
6
  .trim()
7
7
  .split(/\s+/)
8
8
  .filter((w) => w.length > 0);
9
9
  if (parts.length === 0)
10
- return '""';
10
+ return [];
11
11
  if (parts.length > MAX_QUERY_TOKENS) {
12
- throw new Error('Query has too many terms (max ' + String(MAX_QUERY_TOKENS) + ')');
13
- }
14
- const tokens = [];
15
- for (const part of parts) {
16
- tokens.push(`"${part.replace(/"/g, '""')}"`);
12
+ throw new Error(`Query has too many terms (max ${MAX_QUERY_TOKENS})`);
17
13
  }
18
- return tokens.join(' OR ');
14
+ return parts;
19
15
  };
20
- const buildTagFilter = (tags) => {
21
- if (tags.length === 0)
22
- return { clause: '', params: [] };
23
- const placeholders = tags.map(() => '?').join(', ');
24
- return {
25
- clause: ` AND m.id IN (SELECT memory_id FROM tags WHERE tag IN (${placeholders}))`,
26
- params: [...tags],
27
- };
16
+ const buildFtsQuery = (tokens) => {
17
+ if (tokens.length === 0)
18
+ return '""';
19
+ const escaped = tokens.map((t) => `"${t.replace(/"/g, '""')}"`);
20
+ return escaped.join(' OR ');
28
21
  };
29
- const buildBaseSql = (whereClause) => {
22
+ const buildTagPlaceholders = (count) => {
23
+ return Array.from({ length: count }, () => '?').join(', ');
24
+ };
25
+ // Search both content (FTS) and tags, deduplicated by memory id
26
+ const buildSearchQuery = (tokens) => {
27
+ const ftsQuery = buildFtsQuery(tokens);
28
+ const tagPlaceholders = buildTagPlaceholders(tokens.length);
30
29
  const relevanceExpr = '1.0 / (1.0 + abs(bm25(memories_fts)))';
31
- return `
32
- WITH ranked AS (
30
+ // Union of FTS content matches and tag matches, deduplicated
31
+ const sql = `
32
+ WITH content_matches AS (
33
33
  SELECT m.*, ${relevanceExpr} as relevance
34
34
  FROM memories m
35
35
  JOIN memories_fts ON m.id = memories_fts.rowid
36
- WHERE memories_fts MATCH ?${whereClause}
36
+ WHERE memories_fts MATCH ?
37
+ ),
38
+ tag_matches AS (
39
+ SELECT DISTINCT m.*, 0.5 as relevance
40
+ FROM memories m
41
+ JOIN tags t ON m.id = t.memory_id
42
+ WHERE t.tag IN (${tagPlaceholders})
43
+ ),
44
+ combined AS (
45
+ SELECT * FROM content_matches
46
+ UNION ALL
47
+ SELECT * FROM tag_matches
37
48
  )
38
- SELECT * FROM ranked
49
+ SELECT id, content, summary, created_at, accessed_at, hash,
50
+ MAX(relevance) as relevance
51
+ FROM combined
52
+ GROUP BY id
53
+ ORDER BY relevance DESC
54
+ LIMIT ?
39
55
  `;
56
+ return { sql, params: [ftsQuery, ...tokens, DEFAULT_LIMIT] };
40
57
  };
41
- const appendMinRelevance = (input) => {
42
- if (input.minRelevance === undefined)
43
- return input;
44
- return {
45
- sql: `${input.sql} WHERE relevance >= ?`,
46
- params: [...input.params, input.minRelevance],
47
- };
48
- };
49
- const appendPagination = (input) => {
50
- const params = [...input.params, input.limit];
51
- let sql = `${input.sql} ORDER BY relevance DESC LIMIT ?`;
52
- if (input.offset !== undefined && input.offset > 0) {
53
- sql += ' OFFSET ?';
54
- params.push(input.offset);
58
+ const INDEX_MISSING_TOKENS = [
59
+ 'no such module: fts5',
60
+ 'no such table: memories_fts',
61
+ ];
62
+ const QUERY_INVALID_TOKENS = ['fts5', 'syntax error'];
63
+ const isSearchIndexMissing = (message) => INDEX_MISSING_TOKENS.some((token) => message.includes(token));
64
+ const isSearchQueryInvalid = (message) => QUERY_INVALID_TOKENS.some((token) => message.includes(token));
65
+ const getErrorMessage = (err) => err instanceof Error ? err.message : String(err);
66
+ const SEARCH_ERROR_MAP = [
67
+ {
68
+ matches: isSearchIndexMissing,
69
+ build: () => new Error('Search index unavailable. Ensure FTS5 is enabled and the index is ' +
70
+ 'initialized.'),
71
+ },
72
+ {
73
+ matches: isSearchQueryInvalid,
74
+ build: (message) => new Error('Invalid search query syntax. Check for unbalanced quotes or special ' +
75
+ 'characters. ' +
76
+ `Details: ${message}`),
77
+ },
78
+ ];
79
+ const toSearchError = (err) => {
80
+ const message = getErrorMessage(err);
81
+ for (const mapping of SEARCH_ERROR_MAP) {
82
+ if (mapping.matches(message)) {
83
+ return mapping.build(message);
84
+ }
55
85
  }
56
- return { sql, params };
57
- };
58
- export const buildSearchQuery = (input) => {
59
- const sanitizedQuery = tokenizeQuery(input.query);
60
- const tagFilter = buildTagFilter(input.tags);
61
- const baseSql = buildBaseSql(tagFilter.clause);
62
- const baseParams = [sanitizedQuery, ...tagFilter.params];
63
- const baseQuery = { sql: baseSql, params: baseParams };
64
- const withRelevance = input.minRelevance === undefined
65
- ? baseQuery
66
- : appendMinRelevance({
67
- ...baseQuery,
68
- minRelevance: input.minRelevance,
69
- });
70
- const paginatedQuery = input.offset === undefined
71
- ? { ...withRelevance, limit: input.limit }
72
- : { ...withRelevance, limit: input.limit, offset: input.offset };
73
- return appendPagination(paginatedQuery);
86
+ return undefined;
74
87
  };
75
- export const executeSearch = (sql, params) => {
88
+ const executeSearch = (sql, params) => {
76
89
  try {
77
90
  const stmt = prepareCached(sql);
78
91
  return executeAll(stmt, ...params);
@@ -85,4 +98,12 @@ export const executeSearch = (sql, params) => {
85
98
  throw err;
86
99
  }
87
100
  };
88
- //# sourceMappingURL=search.js.map
101
+ export const searchMemories = (input) => {
102
+ const tokens = tokenizeQuery(input.query);
103
+ if (tokens.length === 0) {
104
+ throw new Error('Query cannot be empty');
105
+ }
106
+ const { sql, params } = buildSearchQuery(tokens);
107
+ const rows = executeSearch(sql, params);
108
+ return rows.map((row) => mapRowToSearchResult(row));
109
+ };
@@ -8,4 +8,3 @@ export declare const executeRun: (stmt: StatementSync, ...params: SqlParam[]) =>
8
8
  changes: number | bigint;
9
9
  };
10
10
  export declare const withImmediateTransaction: <T>(operation: () => T) => T;
11
- //# sourceMappingURL=sqlite.d.ts.map
@@ -8,9 +8,7 @@ const enforceStatementCacheLimit = () => {
8
8
  const oldestSql = statementCacheOrder.shift();
9
9
  if (!oldestSql)
10
10
  return;
11
- const toEvict = statementCache.get(oldestSql);
12
11
  statementCache.delete(oldestSql);
13
- void toEvict;
14
12
  };
15
13
  const isDbRow = (value) => {
16
14
  return typeof value === 'object' && value !== null;
@@ -71,4 +69,3 @@ export const withImmediateTransaction = (operation) => {
71
69
  throw err;
72
70
  }
73
71
  };
74
- //# sourceMappingURL=sqlite.js.map
@@ -1,2 +1 @@
1
1
  export declare const normalizeTags: (tags: readonly string[], maxTags: number) => string[];
2
- //# sourceMappingURL=tags.d.ts.map
package/dist/core/tags.js CHANGED
@@ -8,7 +8,7 @@ const validateTag = (tag) => {
8
8
  };
9
9
  const validateTagCount = (tags, maxTags) => {
10
10
  if (tags.length > maxTags) {
11
- throw new Error('Too many tags (max ' + String(maxTags) + ')');
11
+ throw new Error(`Too many tags (max ${maxTags})`);
12
12
  }
13
13
  };
14
14
  const dedupeTags = (tags) => {
@@ -25,4 +25,3 @@ export const normalizeTags = (tags, maxTags) => {
25
25
  validateTagCount(tags, maxTags);
26
26
  return dedupeTags(tags);
27
27
  };
28
- //# sourceMappingURL=tags.js.map
package/dist/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env node
2
2
  export {};
3
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -3,28 +3,46 @@ import { readFile } from 'node:fs/promises';
3
3
  import process from 'node:process';
4
4
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
5
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
6
- import { closeDb } from './core/database.js';
7
- import { registerAllTools } from './tools/index.js';
8
- import { config } from './utils/config.js';
9
- import { logger } from './utils/logger.js';
10
- const packageJsonText = await readFile(new URL('../package.json', import.meta.url), {
11
- encoding: 'utf-8',
12
- signal: AbortSignal.timeout(5000),
13
- });
14
- const packageVersion = (() => {
6
+ import { SUPPORTED_PROTOCOL_VERSIONS, } from '@modelcontextprotocol/sdk/types.js';
7
+ import { closeDb } from './core/db.js';
8
+ import { logger } from './logger.js';
9
+ import { ProtocolVersionGuardTransport } from './protocol-version-guard.js';
10
+ import { registerAllTools } from './tools.js';
11
+ const readPackageVersion = async () => {
12
+ const packageJsonText = await readFile(new URL('../package.json', import.meta.url), {
13
+ encoding: 'utf-8',
14
+ signal: AbortSignal.timeout(5000),
15
+ });
15
16
  const parsed = JSON.parse(packageJsonText);
16
17
  if (typeof parsed !== 'object' || parsed === null)
17
18
  return undefined;
18
19
  const version = Reflect.get(parsed, 'version');
19
20
  return typeof version === 'string' ? version : undefined;
20
- })();
21
+ };
22
+ const packageVersion = await readPackageVersion();
21
23
  const server = new McpServer({ name: 'memdb', version: packageVersion ?? '0.0.0' }, {
22
24
  instructions: 'A Memory MCP Server for AI Assistants using node:sqlite',
23
25
  capabilities: { logging: {}, tools: {} },
24
26
  });
27
+ const patchToolErrorResults = (target) => {
28
+ const patched = target;
29
+ patched.createToolError = (message) => {
30
+ const structured = {
31
+ ok: false,
32
+ error: { code: 'E_TOOL_ERROR', message },
33
+ };
34
+ return {
35
+ content: [{ type: 'text', text: JSON.stringify(structured) }],
36
+ structuredContent: structured,
37
+ isError: true,
38
+ };
39
+ };
40
+ };
41
+ patchToolErrorResults(server);
25
42
  registerAllTools(server);
26
43
  let transport;
27
44
  let shuttingDown = false;
45
+ const SHUTDOWN_TIMEOUT = 5000;
28
46
  async function shutdown(signal) {
29
47
  if (shuttingDown)
30
48
  return;
@@ -33,45 +51,48 @@ async function shutdown(signal) {
33
51
  const forceExitTimer = setTimeout(() => {
34
52
  logger.warn('Shutdown timeout exceeded, forcing exit');
35
53
  process.exit(1);
36
- }, config.shutdownTimeout);
37
- const exit = (code) => {
38
- clearTimeout(forceExitTimer);
39
- process.exit(code);
40
- };
54
+ }, SHUTDOWN_TIMEOUT);
41
55
  try {
42
56
  closeDb();
43
- if (transport) {
44
- await transport.close();
45
- }
46
- exit(0);
57
+ await transport?.close();
58
+ clearTimeout(forceExitTimer);
59
+ process.exit(0);
47
60
  }
48
61
  catch (err) {
49
62
  logger.error('Error during shutdown:', err);
50
- exit(1);
63
+ clearTimeout(forceExitTimer);
64
+ process.exit(1);
51
65
  }
52
66
  }
53
- async function main() {
67
+ const main = async () => {
54
68
  try {
55
- const stdio = new StdioServerTransport();
56
- transport = stdio;
57
- await server.connect(stdio);
69
+ const stdioTransport = new StdioServerTransport();
70
+ const guardedTransport = new ProtocolVersionGuardTransport(stdioTransport, SUPPORTED_PROTOCOL_VERSIONS);
71
+ transport = guardedTransport;
72
+ await server.connect(guardedTransport);
58
73
  logger.info('Memory MCP Server running on stdio');
59
74
  }
60
75
  catch (error) {
61
76
  logger.error('Failed to start server', error);
62
77
  process.exit(1);
63
78
  }
64
- }
79
+ };
80
+ const registerSignalHandlers = () => {
81
+ const signals = ['SIGTERM', 'SIGINT', 'SIGBREAK'];
82
+ for (const signal of signals) {
83
+ process.on(signal, () => void shutdown(signal));
84
+ }
85
+ };
86
+ const registerProcessHandlers = () => {
87
+ process.on('uncaughtException', (err, origin) => {
88
+ logger.error(`Uncaught exception (${origin}):`, err);
89
+ process.exit(1);
90
+ });
91
+ process.on('unhandledRejection', (reason) => {
92
+ logger.error('Unhandled rejection:', reason);
93
+ process.exit(1);
94
+ });
95
+ };
65
96
  void main();
66
- process.on('SIGTERM', () => void shutdown('SIGTERM'));
67
- process.on('SIGINT', () => void shutdown('SIGINT'));
68
- process.on('SIGBREAK', () => void shutdown('SIGBREAK'));
69
- process.on('uncaughtException', (err, origin) => {
70
- logger.error(`Uncaught exception (${origin}):`, err);
71
- process.exit(1);
72
- });
73
- process.on('unhandledRejection', (reason) => {
74
- logger.error('Unhandled rejection:', reason);
75
- process.exit(1);
76
- });
77
- //# sourceMappingURL=index.js.map
97
+ registerSignalHandlers();
98
+ registerProcessHandlers();
@@ -17,4 +17,3 @@ type ErrorResponse = CallToolResult & {
17
17
  export declare function getErrorMessage(error: unknown): string;
18
18
  export declare function createErrorResponse(code: string, message: string, result?: unknown): ErrorResponse;
19
19
  export {};
20
- //# sourceMappingURL=errors.d.ts.map
@@ -20,4 +20,3 @@ export function createErrorResponse(code, message, result) {
20
20
  isError: true,
21
21
  };
22
22
  }
23
- //# sourceMappingURL=errors.js.map
@@ -0,0 +1,5 @@
1
+ export declare const logger: {
2
+ info: (msg: string, ...args: unknown[]) => void;
3
+ warn: (msg: string, ...args: unknown[]) => void;
4
+ error: (msg: string, ...args: unknown[]) => void;
5
+ };
package/dist/logger.js ADDED
@@ -0,0 +1,17 @@
1
+ import { config } from './config.js';
2
+ const LEVELS = {
3
+ error: 0,
4
+ warn: 1,
5
+ info: 2,
6
+ };
7
+ const threshold = LEVELS[config.logLevel];
8
+ const createWriter = (level) => (msg, ...args) => {
9
+ if (LEVELS[level] > threshold)
10
+ return;
11
+ console.error(`[${level.toUpperCase()}] ${msg}`, ...args);
12
+ };
13
+ export const logger = {
14
+ info: createWriter('info'),
15
+ warn: createWriter('warn'),
16
+ error: createWriter('error'),
17
+ };
@@ -0,0 +1,17 @@
1
+ import type { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';
2
+ import { type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
3
+ export declare class ProtocolVersionGuardTransport implements Transport {
4
+ readonly inner: Transport;
5
+ private readonly supportedVersions;
6
+ onclose: () => void;
7
+ onerror: (error: Error) => void;
8
+ onmessage: NonNullable<Transport['onmessage']>;
9
+ private sawInitialize;
10
+ private ready;
11
+ constructor(inner: Transport, supportedVersions: readonly string[]);
12
+ setProtocolVersion(version: string): void;
13
+ start(): Promise<void>;
14
+ send(message: JSONRPCMessage, options?: TransportSendOptions): Promise<void>;
15
+ close(): Promise<void>;
16
+ private handleMessage;
17
+ }
@@ -0,0 +1,100 @@
1
+ import { isInitializedNotification, isInitializeRequest, isJSONRPCErrorResponse, isJSONRPCRequest, isJSONRPCResultResponse, } from '@modelcontextprotocol/sdk/types.js';
2
+ const buildUnsupportedVersionMessage = (version, supportedVersions) => `Unsupported protocol version: ${version} (supported versions: ${supportedVersions.join(', ')})`;
3
+ const isObject = (value) => typeof value === 'object' && value !== null;
4
+ const getInitializeInfo = (message) => {
5
+ if (!isInitializeRequest(message))
6
+ return undefined;
7
+ const { params, id } = message;
8
+ if (typeof id !== 'string' && typeof id !== 'number')
9
+ return undefined;
10
+ if (!isObject(params))
11
+ return undefined;
12
+ const { protocolVersion } = params;
13
+ if (typeof protocolVersion !== 'string')
14
+ return undefined;
15
+ return { id, protocolVersion };
16
+ };
17
+ const createUnsupportedVersionError = (id, version, supportedVersions) => ({
18
+ jsonrpc: '2.0',
19
+ id,
20
+ error: {
21
+ code: -32000,
22
+ message: buildUnsupportedVersionMessage(version, supportedVersions),
23
+ },
24
+ });
25
+ const createLifecycleError = (id, message) => ({
26
+ jsonrpc: '2.0',
27
+ id,
28
+ error: {
29
+ code: -32600,
30
+ message,
31
+ },
32
+ });
33
+ export class ProtocolVersionGuardTransport {
34
+ inner;
35
+ supportedVersions;
36
+ onclose = () => { };
37
+ onerror = () => { };
38
+ onmessage = () => { };
39
+ sawInitialize = false;
40
+ ready = false;
41
+ constructor(inner, supportedVersions) {
42
+ this.inner = inner;
43
+ this.supportedVersions = supportedVersions;
44
+ }
45
+ setProtocolVersion(version) {
46
+ this.inner.setProtocolVersion?.(version);
47
+ }
48
+ async start() {
49
+ this.inner.onmessage = (message, extra) => {
50
+ this.handleMessage(message, extra);
51
+ };
52
+ this.inner.onerror = (error) => {
53
+ this.onerror(error);
54
+ };
55
+ this.inner.onclose = () => {
56
+ this.onclose();
57
+ };
58
+ await this.inner.start();
59
+ }
60
+ async send(message, options) {
61
+ await this.inner.send(message, options);
62
+ }
63
+ async close() {
64
+ await this.inner.close();
65
+ }
66
+ handleMessage(message, extra) {
67
+ const initializeInfo = getInitializeInfo(message);
68
+ if (initializeInfo) {
69
+ if (this.sawInitialize) {
70
+ void this.inner.send(createLifecycleError(initializeInfo.id, 'Invalid request: initialize already received'), { relatedRequestId: initializeInfo.id });
71
+ return;
72
+ }
73
+ if (!this.supportedVersions.includes(initializeInfo.protocolVersion)) {
74
+ void this.inner.send(createUnsupportedVersionError(initializeInfo.id, initializeInfo.protocolVersion, this.supportedVersions), { relatedRequestId: initializeInfo.id });
75
+ return;
76
+ }
77
+ this.sawInitialize = true;
78
+ this.onmessage(message, extra);
79
+ return;
80
+ }
81
+ if (isInitializedNotification(message)) {
82
+ if (this.sawInitialize && !this.ready) {
83
+ this.ready = true;
84
+ this.onmessage(message, extra);
85
+ }
86
+ return;
87
+ }
88
+ if (!this.sawInitialize || !this.ready) {
89
+ if (isJSONRPCRequest(message)) {
90
+ void this.inner.send(createLifecycleError(message.id, 'Invalid request: initialize must be sent before other requests'), { relatedRequestId: message.id });
91
+ }
92
+ else if (isJSONRPCResultResponse(message) ||
93
+ isJSONRPCErrorResponse(message)) {
94
+ this.onmessage(message, extra);
95
+ }
96
+ return;
97
+ }
98
+ this.onmessage(message, extra);
99
+ }
100
+ }
@@ -42,4 +42,3 @@ export declare const UpdateMemoryInputSchema: z.ZodObject<{
42
42
  removeTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
43
43
  }, z.core.$strict>;
44
44
  export declare const MemoryStatsInputSchema: z.ZodObject<{}, z.core.$strict>;
45
- //# sourceMappingURL=inputs.d.ts.map
@@ -95,4 +95,3 @@ export const UpdateMemoryInputSchema = z.strictObject({
95
95
  export const MemoryStatsInputSchema = z
96
96
  .strictObject({})
97
97
  .meta({ description: 'No parameters required' });
98
- //# sourceMappingURL=inputs.js.map
@@ -7,4 +7,3 @@ export declare const DefaultOutputSchema: z.ZodObject<{
7
7
  message: z.ZodString;
8
8
  }, z.core.$strict>>;
9
9
  }, z.core.$strict>;
10
- //# sourceMappingURL=outputs.d.ts.map
@@ -26,4 +26,3 @@ export const DefaultOutputSchema = DefaultOutputSchemaBase.superRefine((value, c
26
26
  addIssue(ctx, ['error'], 'error is required when ok is false');
27
27
  }
28
28
  });
29
- //# sourceMappingURL=outputs.js.map
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+ export declare const StoreMemoryInputSchema: z.ZodObject<{
3
+ content: z.ZodString;
4
+ tags: z.ZodArray<z.ZodString>;
5
+ }, z.core.$strict>;
6
+ export declare const SearchMemoriesInputSchema: z.ZodObject<{
7
+ query: z.ZodString;
8
+ }, z.core.$strict>;
9
+ export declare const GetMemoryInputSchema: z.ZodObject<{
10
+ hash: z.ZodString;
11
+ }, z.core.$strict>;
12
+ export declare const DeleteMemoryInputSchema: z.ZodObject<{
13
+ hash: z.ZodString;
14
+ }, z.core.$strict>;
15
+ export declare const UpdateMemoryInputSchema: z.ZodObject<{
16
+ hash: z.ZodString;
17
+ content: z.ZodString;
18
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
19
+ }, z.core.$strict>;
20
+ export declare const MemoryStatsInputSchema: z.ZodObject<{}, z.core.$strict>;
21
+ export declare const DefaultOutputSchema: z.ZodObject<{
22
+ ok: z.ZodBoolean;
23
+ result: z.ZodOptional<z.ZodUnknown>;
24
+ error: z.ZodOptional<z.ZodObject<{
25
+ code: z.ZodString;
26
+ message: z.ZodString;
27
+ }, z.core.$strict>>;
28
+ }, z.core.$strict>;
@@ -0,0 +1,65 @@
1
+ import { z } from 'zod';
2
+ const hashSchema = z.string().regex(/^[a-f0-9]{32}$/i);
3
+ const tagSchema = z
4
+ .string()
5
+ .min(1)
6
+ .max(50)
7
+ .regex(/^\S+$/, 'Tag must not contain whitespace');
8
+ const tagsSchema = z.array(tagSchema);
9
+ const contentSchema = z.string().min(1).max(100000);
10
+ const querySchema = z.string().trim().min(1).max(1000);
11
+ export const StoreMemoryInputSchema = z.strictObject({
12
+ content: contentSchema.meta({ description: 'The content of the memory' }),
13
+ tags: tagsSchema.min(1).max(100).meta({
14
+ description: 'Tags to categorize the memory (1-100 tags, no whitespace, max 50 chars each)',
15
+ }),
16
+ });
17
+ export const SearchMemoriesInputSchema = z.strictObject({
18
+ query: querySchema.meta({
19
+ description: 'Search query (searches content and tags)',
20
+ }),
21
+ });
22
+ export const GetMemoryInputSchema = z.strictObject({
23
+ hash: hashSchema.meta({ description: 'MD5 hash of the memory' }),
24
+ });
25
+ export const DeleteMemoryInputSchema = z.strictObject({
26
+ hash: hashSchema.meta({ description: 'MD5 hash of the memory' }),
27
+ });
28
+ export const UpdateMemoryInputSchema = z.strictObject({
29
+ hash: hashSchema.meta({ description: 'MD5 hash of the memory to update' }),
30
+ content: contentSchema.meta({ description: 'New content for the memory' }),
31
+ tags: tagsSchema
32
+ .max(100)
33
+ .optional()
34
+ .meta({ description: 'Replace tags (max 100 tags, each max 50 chars)' }),
35
+ });
36
+ export const MemoryStatsInputSchema = z
37
+ .strictObject({})
38
+ .meta({ description: 'No parameters required' });
39
+ const ErrorSchema = z.strictObject({
40
+ code: z.string(),
41
+ message: z.string(),
42
+ });
43
+ const DefaultOutputSchemaBase = z.strictObject({
44
+ ok: z.boolean(),
45
+ result: z.unknown().optional(),
46
+ error: ErrorSchema.optional(),
47
+ });
48
+ const addIssue = (ctx, path, message) => {
49
+ ctx.addIssue({
50
+ code: 'custom',
51
+ message,
52
+ path,
53
+ });
54
+ };
55
+ export const DefaultOutputSchema = DefaultOutputSchemaBase.superRefine((value, ctx) => {
56
+ if (value.ok) {
57
+ if (value.error !== undefined) {
58
+ addIssue(ctx, ['error'], 'error must be absent when ok is true');
59
+ }
60
+ return;
61
+ }
62
+ if (value.error === undefined) {
63
+ addIssue(ctx, ['error'], 'error is required when ok is false');
64
+ }
65
+ });
@@ -1,3 +1,2 @@
1
1
  import type { ToolDef } from '../tool-types.js';
2
2
  export declare const coreTools: ToolDef[];
3
- //# sourceMappingURL=memory-core.d.ts.map
@@ -77,4 +77,3 @@ export const coreTools = [
77
77
  }),
78
78
  },
79
79
  ];
80
- //# sourceMappingURL=memory-core.js.map
@@ -1,3 +1,2 @@
1
1
  import type { ToolDef } from '../tool-types.js';
2
2
  export declare const relationTools: ToolDef[];
3
- //# sourceMappingURL=memory-relations.d.ts.map
@@ -41,4 +41,3 @@ export const relationTools = [
41
41
  }),
42
42
  },
43
43
  ];
44
- //# sourceMappingURL=memory-relations.js.map
@@ -1,3 +1,2 @@
1
1
  import type { ToolDef } from '../tool-types.js';
2
2
  export declare const searchTools: ToolDef[];
3
- //# sourceMappingURL=memory-search.d.ts.map
@@ -14,17 +14,7 @@ export const searchTools = [
14
14
  },
15
15
  handler: wrapHandler('E_SEARCH_MEMORIES', (params) => {
16
16
  const input = SearchMemoriesInputSchema.parse(params);
17
- const searchInput = {
18
- query: input.query,
19
- limit: input.limit ?? 10,
20
- tags: input.tags ?? [],
21
- ...(input.minRelevance !== undefined
22
- ? { minRelevance: input.minRelevance }
23
- : {}),
24
- ...(input.offset !== undefined ? { offset: input.offset } : {}),
25
- };
26
- return ok(searchMemories(searchInput));
17
+ return ok(searchMemories(input));
27
18
  }),
28
19
  },
29
20
  ];
30
- //# sourceMappingURL=memory-search.js.map