contextmate 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.
Files changed (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +142 -0
  3. package/dist/src/adapters/base.d.ts +32 -0
  4. package/dist/src/adapters/base.d.ts.map +1 -0
  5. package/dist/src/adapters/base.js +49 -0
  6. package/dist/src/adapters/base.js.map +1 -0
  7. package/dist/src/adapters/claude.d.ts +30 -0
  8. package/dist/src/adapters/claude.d.ts.map +1 -0
  9. package/dist/src/adapters/claude.js +534 -0
  10. package/dist/src/adapters/claude.js.map +1 -0
  11. package/dist/src/adapters/index.d.ts +7 -0
  12. package/dist/src/adapters/index.d.ts.map +1 -0
  13. package/dist/src/adapters/index.js +16 -0
  14. package/dist/src/adapters/index.js.map +1 -0
  15. package/dist/src/adapters/openclaw.d.ts +15 -0
  16. package/dist/src/adapters/openclaw.d.ts.map +1 -0
  17. package/dist/src/adapters/openclaw.js +198 -0
  18. package/dist/src/adapters/openclaw.js.map +1 -0
  19. package/dist/src/bin/contextmate.d.ts +3 -0
  20. package/dist/src/bin/contextmate.d.ts.map +1 -0
  21. package/dist/src/bin/contextmate.js +4 -0
  22. package/dist/src/bin/contextmate.js.map +1 -0
  23. package/dist/src/cli/adapter.d.ts +3 -0
  24. package/dist/src/cli/adapter.d.ts.map +1 -0
  25. package/dist/src/cli/adapter.js +187 -0
  26. package/dist/src/cli/adapter.js.map +1 -0
  27. package/dist/src/cli/daemon.d.ts +3 -0
  28. package/dist/src/cli/daemon.d.ts.map +1 -0
  29. package/dist/src/cli/daemon.js +212 -0
  30. package/dist/src/cli/daemon.js.map +1 -0
  31. package/dist/src/cli/files.d.ts +3 -0
  32. package/dist/src/cli/files.d.ts.map +1 -0
  33. package/dist/src/cli/files.js +158 -0
  34. package/dist/src/cli/files.js.map +1 -0
  35. package/dist/src/cli/index.d.ts +3 -0
  36. package/dist/src/cli/index.d.ts.map +1 -0
  37. package/dist/src/cli/index.js +20 -0
  38. package/dist/src/cli/index.js.map +1 -0
  39. package/dist/src/cli/init.d.ts +3 -0
  40. package/dist/src/cli/init.d.ts.map +1 -0
  41. package/dist/src/cli/init.js +88 -0
  42. package/dist/src/cli/init.js.map +1 -0
  43. package/dist/src/cli/log.d.ts +3 -0
  44. package/dist/src/cli/log.d.ts.map +1 -0
  45. package/dist/src/cli/log.js +141 -0
  46. package/dist/src/cli/log.js.map +1 -0
  47. package/dist/src/cli/mcp.d.ts +3 -0
  48. package/dist/src/cli/mcp.d.ts.map +1 -0
  49. package/dist/src/cli/mcp.js +186 -0
  50. package/dist/src/cli/mcp.js.map +1 -0
  51. package/dist/src/cli/status.d.ts +3 -0
  52. package/dist/src/cli/status.d.ts.map +1 -0
  53. package/dist/src/cli/status.js +107 -0
  54. package/dist/src/cli/status.js.map +1 -0
  55. package/dist/src/config.d.ts +42 -0
  56. package/dist/src/config.d.ts.map +1 -0
  57. package/dist/src/config.js +93 -0
  58. package/dist/src/config.js.map +1 -0
  59. package/dist/src/crypto/auth.d.ts +4 -0
  60. package/dist/src/crypto/auth.d.ts.map +1 -0
  61. package/dist/src/crypto/auth.js +21 -0
  62. package/dist/src/crypto/auth.js.map +1 -0
  63. package/dist/src/crypto/encrypt.d.ts +9 -0
  64. package/dist/src/crypto/encrypt.d.ts.map +1 -0
  65. package/dist/src/crypto/encrypt.js +39 -0
  66. package/dist/src/crypto/encrypt.js.map +1 -0
  67. package/dist/src/crypto/index.d.ts +4 -0
  68. package/dist/src/crypto/index.d.ts.map +1 -0
  69. package/dist/src/crypto/index.js +4 -0
  70. package/dist/src/crypto/index.js.map +1 -0
  71. package/dist/src/crypto/keys.d.ts +9 -0
  72. package/dist/src/crypto/keys.d.ts.map +1 -0
  73. package/dist/src/crypto/keys.js +43 -0
  74. package/dist/src/crypto/keys.js.map +1 -0
  75. package/dist/src/mcp/embeddings.d.ts +16 -0
  76. package/dist/src/mcp/embeddings.d.ts.map +1 -0
  77. package/dist/src/mcp/embeddings.js +237 -0
  78. package/dist/src/mcp/embeddings.js.map +1 -0
  79. package/dist/src/mcp/index.d.ts +10 -0
  80. package/dist/src/mcp/index.d.ts.map +1 -0
  81. package/dist/src/mcp/index.js +6 -0
  82. package/dist/src/mcp/index.js.map +1 -0
  83. package/dist/src/mcp/rerank.d.ts +14 -0
  84. package/dist/src/mcp/rerank.d.ts.map +1 -0
  85. package/dist/src/mcp/rerank.js +47 -0
  86. package/dist/src/mcp/rerank.js.map +1 -0
  87. package/dist/src/mcp/scope.d.ts +26 -0
  88. package/dist/src/mcp/scope.d.ts.map +1 -0
  89. package/dist/src/mcp/scope.js +71 -0
  90. package/dist/src/mcp/scope.js.map +1 -0
  91. package/dist/src/mcp/search.d.ts +18 -0
  92. package/dist/src/mcp/search.d.ts.map +1 -0
  93. package/dist/src/mcp/search.js +110 -0
  94. package/dist/src/mcp/search.js.map +1 -0
  95. package/dist/src/mcp/server.d.ts +15 -0
  96. package/dist/src/mcp/server.d.ts.map +1 -0
  97. package/dist/src/mcp/server.js +340 -0
  98. package/dist/src/mcp/server.js.map +1 -0
  99. package/dist/src/sync/client.d.ts +25 -0
  100. package/dist/src/sync/client.d.ts.map +1 -0
  101. package/dist/src/sync/client.js +109 -0
  102. package/dist/src/sync/client.js.map +1 -0
  103. package/dist/src/sync/engine.d.ts +21 -0
  104. package/dist/src/sync/engine.d.ts.map +1 -0
  105. package/dist/src/sync/engine.js +304 -0
  106. package/dist/src/sync/engine.js.map +1 -0
  107. package/dist/src/sync/index.d.ts +6 -0
  108. package/dist/src/sync/index.d.ts.map +1 -0
  109. package/dist/src/sync/index.js +6 -0
  110. package/dist/src/sync/index.js.map +1 -0
  111. package/dist/src/sync/state.d.ts +33 -0
  112. package/dist/src/sync/state.d.ts.map +1 -0
  113. package/dist/src/sync/state.js +146 -0
  114. package/dist/src/sync/state.js.map +1 -0
  115. package/dist/src/sync/watcher.d.ts +14 -0
  116. package/dist/src/sync/watcher.d.ts.map +1 -0
  117. package/dist/src/sync/watcher.js +74 -0
  118. package/dist/src/sync/watcher.js.map +1 -0
  119. package/dist/src/sync/websocket.d.ts +22 -0
  120. package/dist/src/sync/websocket.d.ts.map +1 -0
  121. package/dist/src/sync/websocket.js +103 -0
  122. package/dist/src/sync/websocket.js.map +1 -0
  123. package/dist/src/types.d.ts +63 -0
  124. package/dist/src/types.d.ts.map +1 -0
  125. package/dist/src/types.js +2 -0
  126. package/dist/src/types.js.map +1 -0
  127. package/dist/src/utils/paths.d.ts +9 -0
  128. package/dist/src/utils/paths.d.ts.map +1 -0
  129. package/dist/src/utils/paths.js +24 -0
  130. package/dist/src/utils/paths.js.map +1 -0
  131. package/package.json +61 -0
@@ -0,0 +1,110 @@
1
+ import Database from 'better-sqlite3';
2
+ import { readdir, readFile } from 'node:fs/promises';
3
+ import { join, relative } from 'node:path';
4
+ export class SearchIndex {
5
+ db;
6
+ constructor(dbPath) {
7
+ this.db = new Database(dbPath);
8
+ this.db.pragma('journal_mode = WAL');
9
+ this.db.exec(`
10
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
11
+ path,
12
+ content,
13
+ tokenize='porter unicode61'
14
+ );
15
+ CREATE TABLE IF NOT EXISTS memory_files (
16
+ path TEXT PRIMARY KEY,
17
+ content TEXT NOT NULL,
18
+ last_indexed INTEGER NOT NULL
19
+ );
20
+ `);
21
+ }
22
+ indexFile(path, content) {
23
+ const now = Date.now();
24
+ const txn = this.db.transaction(() => {
25
+ this.db.prepare('DELETE FROM memory_fts WHERE path = ?').run(path);
26
+ this.db.prepare('INSERT INTO memory_fts (path, content) VALUES (?, ?)').run(path, content);
27
+ this.db.prepare('INSERT OR REPLACE INTO memory_files (path, content, last_indexed) VALUES (?, ?, ?)').run(path, content, now);
28
+ });
29
+ txn();
30
+ }
31
+ removeFromIndex(path) {
32
+ const txn = this.db.transaction(() => {
33
+ this.db.prepare('DELETE FROM memory_fts WHERE path = ?').run(path);
34
+ this.db.prepare('DELETE FROM memory_files WHERE path = ?').run(path);
35
+ });
36
+ txn();
37
+ }
38
+ search(query, limit = 10) {
39
+ const sanitized = this.sanitizeQuery(query);
40
+ if (!sanitized)
41
+ return [];
42
+ const stmt = this.db.prepare(`
43
+ SELECT
44
+ path,
45
+ snippet(memory_fts, 1, '>>>', '<<<', '...', 64) as snippet,
46
+ bm25(memory_fts) as score
47
+ FROM memory_fts
48
+ WHERE memory_fts MATCH ?
49
+ ORDER BY bm25(memory_fts)
50
+ LIMIT ?
51
+ `);
52
+ const rows = stmt.all(sanitized, limit);
53
+ return rows.map((row) => ({
54
+ path: row.path,
55
+ snippet: row.snippet,
56
+ score: row.score,
57
+ }));
58
+ }
59
+ async rebuildIndex(vaultPath) {
60
+ this.db.exec('DELETE FROM memory_fts');
61
+ this.db.exec('DELETE FROM memory_files');
62
+ const mdFiles = await this.collectMdFiles(vaultPath, vaultPath);
63
+ for (const filePath of mdFiles) {
64
+ const content = await readFile(join(vaultPath, filePath), 'utf-8');
65
+ this.indexFile(filePath, content);
66
+ }
67
+ }
68
+ getIndexedFiles() {
69
+ const rows = this.db.prepare('SELECT path FROM memory_files ORDER BY path').all();
70
+ return rows.map((r) => r.path);
71
+ }
72
+ close() {
73
+ this.db.close();
74
+ }
75
+ sanitizeQuery(query) {
76
+ // Remove FTS5 special characters that could break the query
77
+ const cleaned = query.replace(/[":*^~(){}[\]\\]/g, ' ').trim();
78
+ if (!cleaned)
79
+ return '';
80
+ // Wrap individual terms in quotes to avoid syntax issues
81
+ const terms = cleaned.split(/\s+/).filter(Boolean);
82
+ if (terms.length === 0)
83
+ return '';
84
+ return terms.map((t) => `"${t}"`).join(' ');
85
+ }
86
+ async collectMdFiles(dir, basePath) {
87
+ const results = [];
88
+ let entries;
89
+ try {
90
+ entries = await readdir(dir, { withFileTypes: true });
91
+ }
92
+ catch {
93
+ return results;
94
+ }
95
+ for (const entry of entries) {
96
+ const fullPath = join(dir, entry.name);
97
+ if (entry.isDirectory()) {
98
+ if (entry.name.startsWith('.'))
99
+ continue;
100
+ const sub = await this.collectMdFiles(fullPath, basePath);
101
+ results.push(...sub);
102
+ }
103
+ else if (entry.isFile() && entry.name.endsWith('.md')) {
104
+ results.push(relative(basePath, fullPath));
105
+ }
106
+ }
107
+ return results;
108
+ }
109
+ }
110
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/mcp/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ApiPermission } from '../types.js';
3
+ export interface McpServerOptions {
4
+ vaultPath: string;
5
+ searchDbPath: string;
6
+ scope?: string;
7
+ permission?: ApiPermission;
8
+ }
9
+ export declare function createMcpServer(options: McpServerOptions): McpServer;
10
+ export declare function createMcpServer(vaultPath: string, searchDbPath: string): McpServer;
11
+ export declare function startMcpServer(vaultPath: string, searchDbPath: string, scopeOptions?: {
12
+ scope: string;
13
+ permission: ApiPermission;
14
+ }): Promise<void>;
15
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,aAAa,CAAC;CAC5B;AA0CD,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAC;AACtE,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;AA+VpF,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,aAAa,CAAA;CAAE,GAC1D,OAAO,CAAC,IAAI,CAAC,CAMf"}
@@ -0,0 +1,340 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { z } from 'zod';
4
+ import { readFile, writeFile, readdir, stat, mkdir } from 'node:fs/promises';
5
+ import { join, normalize, resolve, dirname } from 'node:path';
6
+ import { SearchIndex } from './search.js';
7
+ import { VectorIndex } from './embeddings.js';
8
+ import { hybridSearch } from './rerank.js';
9
+ import { matchesScope, hasPermission, requiredPermission, extractFilePath } from './scope.js';
10
+ function isPathSafe(vaultPath, filePath) {
11
+ const resolved = resolve(vaultPath, filePath);
12
+ const normalizedVault = normalize(vaultPath);
13
+ return resolved.startsWith(normalizedVault + '/') || resolved === normalizedVault;
14
+ }
15
+ function todayDateString() {
16
+ const d = new Date();
17
+ const year = d.getFullYear();
18
+ const month = String(d.getMonth() + 1).padStart(2, '0');
19
+ const day = String(d.getDate()).padStart(2, '0');
20
+ return `${year}-${month}-${day}`;
21
+ }
22
+ async function collectFiles(dir, basePath, predicate) {
23
+ const results = [];
24
+ let entries;
25
+ try {
26
+ entries = await readdir(dir, { withFileTypes: true });
27
+ }
28
+ catch {
29
+ return results;
30
+ }
31
+ for (const entry of entries) {
32
+ const fullPath = join(dir, entry.name);
33
+ if (entry.isDirectory()) {
34
+ if (entry.name.startsWith('.'))
35
+ continue;
36
+ const sub = await collectFiles(fullPath, basePath, predicate);
37
+ results.push(...sub);
38
+ }
39
+ else if (entry.isFile() && predicate(entry.name)) {
40
+ const rel = fullPath.slice(basePath.length + 1);
41
+ results.push(rel);
42
+ }
43
+ }
44
+ return results;
45
+ }
46
+ export function createMcpServer(vaultPathOrOptions, searchDbPathArg) {
47
+ const opts = typeof vaultPathOrOptions === 'string'
48
+ ? { vaultPath: vaultPathOrOptions, searchDbPath: searchDbPathArg }
49
+ : vaultPathOrOptions;
50
+ const vault = resolve(opts.vaultPath);
51
+ const searchIndex = new SearchIndex(opts.searchDbPath);
52
+ // Derive vector DB path from search DB path (sibling file)
53
+ const vectorDbPath = opts.searchDbPath.replace(/\.db$/, '-vectors.db');
54
+ const vectorIndex = new VectorIndex(vectorDbPath !== opts.searchDbPath ? vectorDbPath : opts.searchDbPath + '-vectors.db');
55
+ // Build initial index (fire and forget, errors logged)
56
+ Promise.all([
57
+ searchIndex.rebuildIndex(vault),
58
+ vectorIndex.rebuildIndex(vault),
59
+ ]).catch((err) => {
60
+ process.stderr.write(`[contextmate] Failed to build search index: ${err}\n`);
61
+ });
62
+ /**
63
+ * Check scope and permission enforcement for a tool call.
64
+ * Returns an error message string if access is denied, or null if allowed.
65
+ */
66
+ function checkAccess(toolName, args) {
67
+ // No scope configured = unrestricted local access
68
+ if (!opts.scope || !opts.permission)
69
+ return null;
70
+ // Check permission level
71
+ const required = requiredPermission(toolName);
72
+ if (!hasPermission(opts.permission, required)) {
73
+ return `Permission denied: "${toolName}" requires "${required}" permission, but key only has "${opts.permission}".`;
74
+ }
75
+ // Check scope for tools that target specific files
76
+ const filePath = extractFilePath(toolName, args);
77
+ if (filePath && !matchesScope(filePath, opts.scope)) {
78
+ return `Scope denied: file "${filePath}" is outside the allowed scope "${opts.scope}".`;
79
+ }
80
+ return null;
81
+ }
82
+ const server = new McpServer({
83
+ name: 'contextmate',
84
+ version: '0.1.0',
85
+ });
86
+ // --- search-memory ---
87
+ server.tool('search-memory', 'Search through memories using keyword, semantic, or hybrid search. Returns ranked results.', {
88
+ query: z.string().describe('Search query'),
89
+ limit: z.number().optional().default(10).describe('Maximum number of results'),
90
+ mode: z
91
+ .enum(['keyword', 'semantic', 'hybrid'])
92
+ .optional()
93
+ .default('hybrid')
94
+ .describe('Search mode: keyword (BM25), semantic (vector), or hybrid (both merged via RRF)'),
95
+ }, async ({ query, limit, mode }) => {
96
+ const denied = checkAccess('search-memory', { query });
97
+ if (denied) {
98
+ return { content: [{ type: 'text', text: denied }], isError: true };
99
+ }
100
+ try {
101
+ if (mode === 'keyword') {
102
+ const results = searchIndex.search(query, limit);
103
+ if (results.length === 0) {
104
+ return { content: [{ type: 'text', text: 'No results found.' }] };
105
+ }
106
+ const formatted = results
107
+ .map((r, i) => `${i + 1}. **${r.path}** (score: ${r.score.toFixed(4)})\n ${r.snippet}`)
108
+ .join('\n\n');
109
+ return { content: [{ type: 'text', text: formatted }] };
110
+ }
111
+ if (mode === 'semantic') {
112
+ const results = vectorIndex.search(query, limit);
113
+ if (results.length === 0) {
114
+ return { content: [{ type: 'text', text: 'No results found.' }] };
115
+ }
116
+ const formatted = results
117
+ .map((r, i) => `${i + 1}. **${r.path}** (similarity: ${r.score.toFixed(4)})`)
118
+ .join('\n\n');
119
+ return { content: [{ type: 'text', text: formatted }] };
120
+ }
121
+ // hybrid mode
122
+ const bm25Results = searchIndex.search(query, limit);
123
+ const vectorResults = vectorIndex.search(query, limit);
124
+ const merged = hybridSearch(bm25Results, vectorResults);
125
+ const topResults = merged.slice(0, limit);
126
+ if (topResults.length === 0) {
127
+ return { content: [{ type: 'text', text: 'No results found.' }] };
128
+ }
129
+ const formatted = topResults
130
+ .map((r, i) => {
131
+ const sources = r.sources.join('+');
132
+ const snippetLine = r.snippet ? `\n ${r.snippet}` : '';
133
+ return `${i + 1}. **${r.path}** (score: ${r.score.toFixed(4)}, via: ${sources})${snippetLine}`;
134
+ })
135
+ .join('\n\n');
136
+ return { content: [{ type: 'text', text: formatted }] };
137
+ }
138
+ catch (err) {
139
+ return {
140
+ content: [{ type: 'text', text: `Search error: ${String(err)}` }],
141
+ isError: true,
142
+ };
143
+ }
144
+ });
145
+ // --- read-memory ---
146
+ server.tool('read-memory', 'Read the contents of a specific memory file.', {
147
+ file: z
148
+ .string()
149
+ .describe('Relative path within vault, e.g. "openclaw/MEMORY.md"'),
150
+ }, async ({ file }) => {
151
+ const denied = checkAccess('read-memory', { file });
152
+ if (denied) {
153
+ return { content: [{ type: 'text', text: denied }], isError: true };
154
+ }
155
+ try {
156
+ if (!isPathSafe(vault, file)) {
157
+ return {
158
+ content: [{ type: 'text', text: 'Error: Invalid file path.' }],
159
+ isError: true,
160
+ };
161
+ }
162
+ const fullPath = resolve(vault, file);
163
+ const content = await readFile(fullPath, 'utf-8');
164
+ return { content: [{ type: 'text', text: content }] };
165
+ }
166
+ catch (err) {
167
+ return {
168
+ content: [{ type: 'text', text: `Error reading file: ${String(err)}` }],
169
+ isError: true,
170
+ };
171
+ }
172
+ });
173
+ // --- write-memory ---
174
+ server.tool('write-memory', "Write or append content to a memory file. Defaults to today's daily log.", {
175
+ content: z.string().describe('Content to write'),
176
+ file: z
177
+ .string()
178
+ .optional()
179
+ .describe('Relative path within vault. Defaults to daily log.'),
180
+ }, async ({ content, file }) => {
181
+ const relPath = file ?? `openclaw/memory/${todayDateString()}.md`;
182
+ const denied = checkAccess('write-memory', { file: relPath });
183
+ if (denied) {
184
+ return { content: [{ type: 'text', text: denied }], isError: true };
185
+ }
186
+ try {
187
+ if (!isPathSafe(vault, relPath)) {
188
+ return {
189
+ content: [{ type: 'text', text: 'Error: Invalid file path.' }],
190
+ isError: true,
191
+ };
192
+ }
193
+ const fullPath = resolve(vault, relPath);
194
+ await mkdir(dirname(fullPath), { recursive: true });
195
+ let existing = '';
196
+ try {
197
+ existing = await readFile(fullPath, 'utf-8');
198
+ }
199
+ catch {
200
+ // File doesn't exist, will be created
201
+ }
202
+ const newContent = existing ? existing + '\n\n' + content : content;
203
+ await writeFile(fullPath, newContent, 'utf-8');
204
+ // Re-index the file in both indexes
205
+ searchIndex.indexFile(relPath, newContent);
206
+ vectorIndex.indexFile(relPath, newContent);
207
+ vectorIndex.recomputeIdf();
208
+ return {
209
+ content: [
210
+ {
211
+ type: 'text',
212
+ text: `Written to ${relPath}${existing ? ' (appended)' : ' (created)'}`,
213
+ },
214
+ ],
215
+ };
216
+ }
217
+ catch (err) {
218
+ return {
219
+ content: [{ type: 'text', text: `Error writing file: ${String(err)}` }],
220
+ isError: true,
221
+ };
222
+ }
223
+ });
224
+ // --- read-skill ---
225
+ server.tool('read-skill', 'Read the contents of a specific skill file.', {
226
+ skill: z.string().describe('Skill name, e.g. "my-skill"'),
227
+ }, async ({ skill }) => {
228
+ const denied = checkAccess('read-skill', { skill });
229
+ if (denied) {
230
+ return { content: [{ type: 'text', text: denied }], isError: true };
231
+ }
232
+ try {
233
+ // Validate skill name (no path traversal)
234
+ if (skill.includes('..') || skill.includes('/') || skill.includes('\\')) {
235
+ return {
236
+ content: [{ type: 'text', text: 'Error: Invalid skill name.' }],
237
+ isError: true,
238
+ };
239
+ }
240
+ // Try multiple possible locations
241
+ const candidates = [
242
+ join(vault, 'skills', skill, 'SKILL.md'),
243
+ join(vault, 'openclaw', 'skills', skill, 'SKILL.md'),
244
+ ];
245
+ for (const candidate of candidates) {
246
+ try {
247
+ const content = await readFile(candidate, 'utf-8');
248
+ return { content: [{ type: 'text', text: content }] };
249
+ }
250
+ catch {
251
+ continue;
252
+ }
253
+ }
254
+ return {
255
+ content: [{ type: 'text', text: `Skill "${skill}" not found.` }],
256
+ isError: true,
257
+ };
258
+ }
259
+ catch (err) {
260
+ return {
261
+ content: [{ type: 'text', text: `Error reading skill: ${String(err)}` }],
262
+ isError: true,
263
+ };
264
+ }
265
+ });
266
+ // --- list-skills ---
267
+ server.tool('list-skills', 'List all available skills.', {}, async () => {
268
+ const denied = checkAccess('list-skills', {});
269
+ if (denied) {
270
+ return { content: [{ type: 'text', text: denied }], isError: true };
271
+ }
272
+ try {
273
+ const skillFiles = await collectFiles(vault, vault, (name) => name === 'SKILL.md');
274
+ if (skillFiles.length === 0) {
275
+ return { content: [{ type: 'text', text: 'No skills found.' }] };
276
+ }
277
+ const entries = [];
278
+ for (const relPath of skillFiles) {
279
+ const fullPath = join(vault, relPath);
280
+ const content = await readFile(fullPath, 'utf-8');
281
+ const firstLines = content.split('\n').slice(0, 3).join('\n').trim();
282
+ // Extract skill name from path: e.g. "skills/my-skill/SKILL.md" -> "my-skill"
283
+ const parts = relPath.split('/');
284
+ const skillIdx = parts.indexOf('SKILL.md');
285
+ const skillName = skillIdx > 0 ? parts[skillIdx - 1] : relPath;
286
+ entries.push(`- **${skillName}** (${relPath})\n ${firstLines}`);
287
+ }
288
+ return { content: [{ type: 'text', text: entries.join('\n\n') }] };
289
+ }
290
+ catch (err) {
291
+ return {
292
+ content: [{ type: 'text', text: `Error listing skills: ${String(err)}` }],
293
+ isError: true,
294
+ };
295
+ }
296
+ });
297
+ // --- list-memories ---
298
+ server.tool('list-memories', 'List all memory files.', {}, async () => {
299
+ const denied = checkAccess('list-memories', {});
300
+ if (denied) {
301
+ return { content: [{ type: 'text', text: denied }], isError: true };
302
+ }
303
+ try {
304
+ const mdFiles = await collectFiles(vault, vault, (name) => name.endsWith('.md'));
305
+ // Filter to memory-related files
306
+ const memoryFiles = mdFiles.filter((f) => f.includes('memory/') || f.includes('memory\\') || f.endsWith('MEMORY.md'));
307
+ if (memoryFiles.length === 0) {
308
+ return { content: [{ type: 'text', text: 'No memory files found.' }] };
309
+ }
310
+ const entries = [];
311
+ for (const relPath of memoryFiles) {
312
+ const fullPath = join(vault, relPath);
313
+ try {
314
+ const info = await stat(fullPath);
315
+ const modified = new Date(info.mtimeMs).toISOString().slice(0, 19).replace('T', ' ');
316
+ entries.push(`- ${relPath} (modified: ${modified})`);
317
+ }
318
+ catch {
319
+ entries.push(`- ${relPath}`);
320
+ }
321
+ }
322
+ return { content: [{ type: 'text', text: entries.join('\n') }] };
323
+ }
324
+ catch (err) {
325
+ return {
326
+ content: [{ type: 'text', text: `Error listing memories: ${String(err)}` }],
327
+ isError: true,
328
+ };
329
+ }
330
+ });
331
+ return server;
332
+ }
333
+ export async function startMcpServer(vaultPath, searchDbPath, scopeOptions) {
334
+ const server = scopeOptions
335
+ ? createMcpServer({ vaultPath, searchDbPath, scope: scopeOptions.scope, permission: scopeOptions.permission })
336
+ : createMcpServer(vaultPath, searchDbPath);
337
+ const transport = new StdioServerTransport();
338
+ await server.connect(transport);
339
+ }
340
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { FileMetadata, RemoteChange, DeviceInfo } from '../types.js';
2
+ export declare class SyncClient {
3
+ private readonly baseUrl;
4
+ private readonly authToken;
5
+ private readonly maxRetries;
6
+ constructor(baseUrl: string, authToken: string);
7
+ uploadFile(path: string, encryptedData: Uint8Array, encryptedHash: string, version: number): Promise<{
8
+ version: number;
9
+ }>;
10
+ downloadFile(path: string): Promise<{
11
+ data: Uint8Array;
12
+ version: number;
13
+ encryptedHash: string;
14
+ }>;
15
+ listRemoteFiles(): Promise<FileMetadata[]>;
16
+ getRemoteChanges(since: number): Promise<RemoteChange[]>;
17
+ registerDevice(name: string, publicKey: string): Promise<string>;
18
+ listDevices(): Promise<DeviceInfo[]>;
19
+ private fetchWithRetry;
20
+ }
21
+ export declare class ConflictError extends Error {
22
+ readonly filePath: string;
23
+ constructor(filePath: string);
24
+ }
25
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/sync/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1E,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAK;gBAEpB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKxC,UAAU,CACd,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,UAAU,EACzB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IA0BzB,YAAY,CAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAiBlE,eAAe,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAa1C,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAaxD,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBhE,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAa5B,cAAc;CAkC7B;AAED,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAgB,QAAQ,EAAE,MAAM,CAAC;gBAErB,QAAQ,EAAE,MAAM;CAK7B"}
@@ -0,0 +1,109 @@
1
+ export class SyncClient {
2
+ baseUrl;
3
+ authToken;
4
+ maxRetries = 3;
5
+ constructor(baseUrl, authToken) {
6
+ this.baseUrl = baseUrl.replace(/\/+$/, '');
7
+ this.authToken = authToken;
8
+ }
9
+ async uploadFile(path, encryptedData, encryptedHash, version) {
10
+ const response = await this.fetchWithRetry(`${this.baseUrl}/api/files/${encodeURIComponent(path)}`, {
11
+ method: 'PUT',
12
+ headers: {
13
+ 'Content-Type': 'application/octet-stream',
14
+ 'X-Content-Hash': encryptedHash,
15
+ 'X-Version': String(version),
16
+ },
17
+ body: encryptedData,
18
+ });
19
+ if (response.status === 409) {
20
+ throw new ConflictError(path);
21
+ }
22
+ if (!response.ok) {
23
+ throw new Error(`Upload failed for ${path}: ${response.status} ${response.statusText}`);
24
+ }
25
+ const result = (await response.json());
26
+ return result;
27
+ }
28
+ async downloadFile(path) {
29
+ const response = await this.fetchWithRetry(`${this.baseUrl}/api/files/${encodeURIComponent(path)}`, { method: 'GET' });
30
+ if (!response.ok) {
31
+ throw new Error(`Download failed for ${path}: ${response.status} ${response.statusText}`);
32
+ }
33
+ const data = new Uint8Array(await response.arrayBuffer());
34
+ const version = Number(response.headers.get('X-Version') ?? '0');
35
+ const encryptedHash = response.headers.get('X-Content-Hash') ?? '';
36
+ return { data, version, encryptedHash };
37
+ }
38
+ async listRemoteFiles() {
39
+ const response = await this.fetchWithRetry(`${this.baseUrl}/api/files`, { method: 'GET' });
40
+ if (!response.ok) {
41
+ throw new Error(`List files failed: ${response.status} ${response.statusText}`);
42
+ }
43
+ return (await response.json());
44
+ }
45
+ async getRemoteChanges(since) {
46
+ const response = await this.fetchWithRetry(`${this.baseUrl}/api/changes?since=${since}`, { method: 'GET' });
47
+ if (!response.ok) {
48
+ throw new Error(`Get changes failed: ${response.status} ${response.statusText}`);
49
+ }
50
+ return (await response.json());
51
+ }
52
+ async registerDevice(name, publicKey) {
53
+ const response = await this.fetchWithRetry(`${this.baseUrl}/api/auth/devices`, {
54
+ method: 'POST',
55
+ headers: { 'Content-Type': 'application/json' },
56
+ body: JSON.stringify({ name, publicKey }),
57
+ });
58
+ if (!response.ok) {
59
+ throw new Error(`Register device failed: ${response.status} ${response.statusText}`);
60
+ }
61
+ const result = (await response.json());
62
+ return result.id;
63
+ }
64
+ async listDevices() {
65
+ const response = await this.fetchWithRetry(`${this.baseUrl}/api/auth/devices`, { method: 'GET' });
66
+ if (!response.ok) {
67
+ throw new Error(`List devices failed: ${response.status} ${response.statusText}`);
68
+ }
69
+ return (await response.json());
70
+ }
71
+ async fetchWithRetry(url, init) {
72
+ const headers = new Headers(init.headers);
73
+ headers.set('Authorization', `Bearer ${this.authToken}`);
74
+ const requestInit = {
75
+ ...init,
76
+ headers,
77
+ };
78
+ let lastError;
79
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
80
+ try {
81
+ const response = await fetch(url, requestInit);
82
+ // Don't retry client errors (4xx) except 429
83
+ if (response.status >= 400 && response.status < 500 && response.status !== 429) {
84
+ return response;
85
+ }
86
+ if (response.ok) {
87
+ return response;
88
+ }
89
+ lastError = new Error(`HTTP ${response.status}: ${response.statusText}`);
90
+ }
91
+ catch (err) {
92
+ lastError = err instanceof Error ? err : new Error(String(err));
93
+ }
94
+ // Exponential backoff: 1s, 2s, 4s
95
+ const delay = 1000 * Math.pow(2, attempt);
96
+ await new Promise((resolve) => setTimeout(resolve, delay));
97
+ }
98
+ throw lastError ?? new Error('Request failed after retries');
99
+ }
100
+ }
101
+ export class ConflictError extends Error {
102
+ filePath;
103
+ constructor(filePath) {
104
+ super(`Conflict detected for file: ${filePath}`);
105
+ this.name = 'ConflictError';
106
+ this.filePath = filePath;
107
+ }
108
+ }
109
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/sync/client.ts"],"names":[],"mappings":"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"}