persyst-mcp 2.2.5 → 2.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -114
- package/bin/export.js +4 -4
- package/bin/extract.js +8 -8
- package/bin/import.js +15 -15
- package/bin/init.js +185 -38
- package/bin/mcp.js +3 -0
- package/bin/monitor.js +511 -0
- package/bin/setup.js +9 -9
- package/index.js +31 -11
- package/package.json +10 -11
- package/src/attestation.js +49 -28
- package/src/cache.js +3 -1
- package/src/database.js +227 -34
- package/src/embeddings.js +4 -2
- package/src/events.js +2 -0
- package/src/extractor-heuristic.js +5 -2
- package/src/sdk.js +4 -3
- package/src/search.js +55 -84
- package/src/server.js +884 -723
- package/src/setup-wasm.js +34 -39
- package/src/text-utils.js +52 -0
- package/src/tools.js +98 -53
- package/src/watcher.js +157 -49
package/bin/init.js
CHANGED
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* persyst-init — Workspace rules generator
|
|
4
|
+
* persyst-init — Workspace rules generator and global IDE configuration builder
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
7
|
* npx persyst-mcp init
|
|
8
|
+
* npx persyst-mcp init --mcp cursor,aider
|
|
8
9
|
*
|
|
9
10
|
* What it does:
|
|
10
|
-
* 1. Safely creates or appends system instructions to `.cursorrules`
|
|
11
|
-
* 2.
|
|
12
|
-
* 3.
|
|
13
|
-
* 4.
|
|
14
|
-
*
|
|
15
|
-
* Design:
|
|
16
|
-
* - Non-destructive: checks for existing content before appending to avoid duplication
|
|
17
|
-
* - Idempotent: safe to run multiple times
|
|
18
|
-
* - Localized: targets the current working directory (project root)
|
|
11
|
+
* 1. Safely creates or appends system instructions to `.cursorrules` and `.windsurfrules`
|
|
12
|
+
* 2. Creates a general `.persystrules.md` workspace guide
|
|
13
|
+
* 3. Configures Git post-commit hook for auto-ingestion
|
|
14
|
+
* 4. Generates cryptographic Ed25519 keys inside ~/.persyst
|
|
15
|
+
* 5. Automatically detects and configures global settings for Cursor, Aider, Claude Code, and Continue
|
|
19
16
|
*/
|
|
20
17
|
|
|
21
18
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'fs';
|
|
22
|
-
import { join, resolve, dirname } from 'path';
|
|
19
|
+
import { join, resolve, dirname, basename } from 'path';
|
|
20
|
+
import { homedir } from 'os';
|
|
23
21
|
import { fileURLToPath } from 'url';
|
|
22
|
+
import { execSync } from 'child_process';
|
|
23
|
+
import { initializeKeys } from '../src/attestation.js';
|
|
24
24
|
|
|
25
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
26
26
|
const __dirname = dirname(__filename);
|
|
27
27
|
|
|
28
|
+
const CONFIG_DIR = join(homedir(), '.persyst');
|
|
29
|
+
const PERSYST_DB = join(CONFIG_DIR, 'persyst.db');
|
|
30
|
+
|
|
28
31
|
// ============================================================
|
|
29
32
|
// SYSTEM INSTRUCTION CONTENT
|
|
30
33
|
// ============================================================
|
|
@@ -46,6 +49,10 @@ You are integrated with Persyst, a local-first MCP memory server that stores use
|
|
|
46
49
|
- Handle Contradictions: Persyst handles contradiction detection automatically. If a new fact contradicts an old memory, Persyst will flag it.
|
|
47
50
|
- Quality Over Quantity: Do NOT store trivial facts, temporary conversation noise, or duplicate data. "Bad data is worse than no data". Only store long-term architecture decisions, project details, and explicit user preferences.
|
|
48
51
|
|
|
52
|
+
## Explicit User Save Requests
|
|
53
|
+
- If the user explicitly asks you to remember, save, or keep a note of a fact (e.g., "Remember that John handles deployment", "remind me that staging is flaky"), call the \`add_memory\` tool immediately with that content.
|
|
54
|
+
- Bypassing Tech Filters: Explicit user requests bypass the programming keyword filters. Ensure they are captured verbatim.
|
|
55
|
+
|
|
49
56
|
## Mandatory Completion Checklist (HARD CONSTRAINT)
|
|
50
57
|
Before writing your final response declaring a task, feature, or bug fix complete:
|
|
51
58
|
1. Ask yourself: "Did I implement a feature, fix a bug, configure a tool, or discover a project rule?"
|
|
@@ -82,7 +89,7 @@ ${RULE_CONTENT.trim()}
|
|
|
82
89
|
`;
|
|
83
90
|
|
|
84
91
|
// ============================================================
|
|
85
|
-
// HELPERS
|
|
92
|
+
// WORKSPACE HELPERS
|
|
86
93
|
// ============================================================
|
|
87
94
|
|
|
88
95
|
function setupRuleFile(filePath, fileName) {
|
|
@@ -92,7 +99,7 @@ function setupRuleFile(filePath, fileName) {
|
|
|
92
99
|
if (existsSync(filePath)) {
|
|
93
100
|
const existing = readFileSync(filePath, 'utf8');
|
|
94
101
|
if (existing.includes(INSTRUCTION_HEADER)) {
|
|
95
|
-
console.log(`
|
|
102
|
+
console.log(` [SKIP] ${fileName} already has Persyst rules configured.`);
|
|
96
103
|
return;
|
|
97
104
|
}
|
|
98
105
|
content = existing + '\n' + RULE_CONTENT;
|
|
@@ -100,37 +107,166 @@ function setupRuleFile(filePath, fileName) {
|
|
|
100
107
|
}
|
|
101
108
|
|
|
102
109
|
writeFileSync(filePath, content.trim() + '\n', 'utf8');
|
|
103
|
-
console.log(`
|
|
110
|
+
console.log(` [OK] ${action} ${fileName}`);
|
|
104
111
|
}
|
|
105
112
|
|
|
106
113
|
// ============================================================
|
|
107
|
-
//
|
|
114
|
+
// GLOBAL CONFIG WRITERS
|
|
115
|
+
// ============================================================
|
|
116
|
+
|
|
117
|
+
function detectEditors() {
|
|
118
|
+
const editors = [];
|
|
119
|
+
const home = homedir();
|
|
120
|
+
|
|
121
|
+
// Cursor
|
|
122
|
+
const cursorDir = join(home, '.cursor');
|
|
123
|
+
const winCursorDir = join(home, 'AppData', 'Roaming', 'Cursor');
|
|
124
|
+
if (existsSync(cursorDir) || existsSync(winCursorDir) || existsSync('/Applications/Cursor.app') || existsSync(join(home, 'AppData', 'Local', 'Programs', 'cursor'))) {
|
|
125
|
+
editors.push('cursor');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Aider
|
|
129
|
+
try {
|
|
130
|
+
execSync('aider --version', { stdio: 'ignore' });
|
|
131
|
+
editors.push('aider');
|
|
132
|
+
} catch (_) {}
|
|
133
|
+
|
|
134
|
+
// Claude Code
|
|
135
|
+
const claudeDir = join(home, '.claude');
|
|
136
|
+
if (existsSync(claudeDir) || existsSync('/Applications/Claude Code.app')) {
|
|
137
|
+
editors.push('claude-code');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Continue.dev
|
|
141
|
+
const continueConfig = join(home, '.continue', 'config.json');
|
|
142
|
+
if (existsSync(continueConfig)) {
|
|
143
|
+
editors.push('continue');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return editors;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function writeCursorConfig(projectName) {
|
|
150
|
+
const cursorMcp = join(homedir(), '.cursor', 'mcp.json');
|
|
151
|
+
try {
|
|
152
|
+
const config = existsSync(cursorMcp) ? JSON.parse(readFileSync(cursorMcp, 'utf8')) : {};
|
|
153
|
+
config.mcpServers = config.mcpServers || {};
|
|
154
|
+
config.mcpServers.persyst = {
|
|
155
|
+
"command": "npx",
|
|
156
|
+
"args": ["-y", "persyst-mcp"],
|
|
157
|
+
"env": {
|
|
158
|
+
"PERSYST_DB": PERSYST_DB,
|
|
159
|
+
"PERSYST_PROJECT": projectName
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
mkdirSync(dirname(cursorMcp), { recursive: true });
|
|
163
|
+
writeFileSync(cursorMcp, JSON.stringify(config, null, 2));
|
|
164
|
+
console.log(' [OK] Cursor MCP config written to ~/.cursor/mcp.json');
|
|
165
|
+
} catch (err) {
|
|
166
|
+
console.error(` [ERROR] Failed to configure Cursor: ${err.message}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function writeAiderConfig(projectName) {
|
|
171
|
+
const aiderYml = join(homedir(), '.aider.conf.yml');
|
|
172
|
+
try {
|
|
173
|
+
let content = '';
|
|
174
|
+
if (existsSync(aiderYml)) {
|
|
175
|
+
content = readFileSync(aiderYml, 'utf8');
|
|
176
|
+
}
|
|
177
|
+
if (!content.includes('persyst')) {
|
|
178
|
+
content += `\n# Persyst MCP integration\nmcp:\n - name: persyst\n cmd: npx\n args: ["-y", "persyst-mcp"]\n env:\n PERSYST_DB: ${PERSYST_DB}\n PERSYST_PROJECT: ${projectName}\n`;
|
|
179
|
+
writeFileSync(aiderYml, content);
|
|
180
|
+
console.log(' [OK] Aider MCP config appended to ~/.aider.conf.yml');
|
|
181
|
+
} else {
|
|
182
|
+
console.log(' [SKIP] Aider already has Persyst configured.');
|
|
183
|
+
}
|
|
184
|
+
} catch (err) {
|
|
185
|
+
console.error(` [ERROR] Failed to configure Aider: ${err.message}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function writeClaudeCodeConfig(projectName) {
|
|
190
|
+
const claudeJson = join(homedir(), '.claude.json');
|
|
191
|
+
try {
|
|
192
|
+
const config = existsSync(claudeJson) ? JSON.parse(readFileSync(claudeJson, 'utf8')) : {};
|
|
193
|
+
config.mcpServers = config.mcpServers || {};
|
|
194
|
+
config.mcpServers.persyst = {
|
|
195
|
+
"command": "npx",
|
|
196
|
+
"args": ["-y", "persyst-mcp"],
|
|
197
|
+
"env": {
|
|
198
|
+
"PERSYST_DB": PERSYST_DB,
|
|
199
|
+
"PERSYST_PROJECT": projectName
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
writeFileSync(claudeJson, JSON.stringify(config, null, 2));
|
|
203
|
+
console.log(' [OK] Claude Code MCP config written to ~/.claude.json');
|
|
204
|
+
} catch (err) {
|
|
205
|
+
console.error(` [ERROR] Failed to configure Claude Code: ${err.message}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function writeContinueConfig(projectName) {
|
|
210
|
+
const continueConfig = join(homedir(), '.continue', 'config.json');
|
|
211
|
+
try {
|
|
212
|
+
const config = existsSync(continueConfig) ? JSON.parse(readFileSync(continueConfig, 'utf8')) : {};
|
|
213
|
+
config.mcpServers = config.mcpServers || [];
|
|
214
|
+
// Remove existing persyst entry
|
|
215
|
+
config.mcpServers = config.mcpServers.filter(s => s.name !== 'persyst');
|
|
216
|
+
config.mcpServers.push({
|
|
217
|
+
"name": "persyst",
|
|
218
|
+
"command": "npx",
|
|
219
|
+
"args": ["-y", "persyst-mcp"],
|
|
220
|
+
"env": {
|
|
221
|
+
"PERSYST_DB": PERSYST_DB,
|
|
222
|
+
"PERSYST_PROJECT": projectName
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
mkdirSync(dirname(continueConfig), { recursive: true });
|
|
226
|
+
writeFileSync(continueConfig, JSON.stringify(config, null, 2));
|
|
227
|
+
console.log(' [OK] Continue.dev MCP config written to ~/.continue/config.json');
|
|
228
|
+
} catch (err) {
|
|
229
|
+
console.error(` [ERROR] Failed to configure Continue.dev: ${err.message}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ============================================================
|
|
234
|
+
// MAIN RUNNER
|
|
108
235
|
// ============================================================
|
|
109
236
|
|
|
110
237
|
function run() {
|
|
111
238
|
console.log('');
|
|
112
|
-
console.log('
|
|
113
|
-
console.log('
|
|
239
|
+
console.log(' Persyst — Workspace & Editor Setup');
|
|
240
|
+
console.log(' ══════════════════════════════════════');
|
|
114
241
|
console.log('');
|
|
115
242
|
|
|
116
243
|
const cwd = process.cwd();
|
|
117
|
-
console.log(`
|
|
118
|
-
console.log('');
|
|
244
|
+
console.log(` Target workspace: ${cwd}`);
|
|
119
245
|
|
|
120
|
-
// 1.
|
|
246
|
+
// 1. Initialize local configuration folder and attestations
|
|
247
|
+
console.log(' [1/4] Initializing keypairs & DB folders...');
|
|
248
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
249
|
+
initializeKeys();
|
|
250
|
+
console.log(' [OK] Cryptographic keypairs generated');
|
|
251
|
+
|
|
252
|
+
// 2. Local workspace configurations
|
|
253
|
+
console.log('');
|
|
254
|
+
console.log(' [2/4] Initializing workspace rule files...');
|
|
255
|
+
|
|
121
256
|
const cursorRulesPath = join(cwd, '.cursorrules');
|
|
122
257
|
setupRuleFile(cursorRulesPath, '.cursorrules');
|
|
123
258
|
|
|
124
|
-
// 2. Create/Append Windsurf Rules
|
|
125
259
|
const windsurfRulesPath = join(cwd, '.windsurfrules');
|
|
126
260
|
setupRuleFile(windsurfRulesPath, '.windsurfrules');
|
|
127
261
|
|
|
128
|
-
|
|
262
|
+
const clineRulesPath = join(cwd, '.clinerules');
|
|
263
|
+
setupRuleFile(clineRulesPath, '.clinerules');
|
|
264
|
+
|
|
129
265
|
const generalGuidePath = join(cwd, '.persystrules.md');
|
|
130
266
|
writeFileSync(generalGuidePath, GENERAL_GUIDE.trim() + '\n', 'utf8');
|
|
131
|
-
console.log('
|
|
267
|
+
console.log(' [OK] Created .persystrules.md (General Guide)');
|
|
132
268
|
|
|
133
|
-
//
|
|
269
|
+
// 3. Git post-commit hook
|
|
134
270
|
const gitDir = join(cwd, '.git');
|
|
135
271
|
if (existsSync(gitDir)) {
|
|
136
272
|
const hooksDir = join(gitDir, 'hooks');
|
|
@@ -156,25 +292,36 @@ fi
|
|
|
156
292
|
try {
|
|
157
293
|
chmodSync(postCommitPath, 0o755);
|
|
158
294
|
} catch (_) {}
|
|
159
|
-
console.log('
|
|
295
|
+
console.log(' [OK] Configured Git post-commit hook for auto-ingestion');
|
|
160
296
|
}
|
|
161
297
|
|
|
162
|
-
//
|
|
298
|
+
// 4. Global editor configurations
|
|
163
299
|
console.log('');
|
|
164
|
-
console.log('
|
|
165
|
-
|
|
300
|
+
console.log(' [3/4] Initializing global IDE configurations...');
|
|
301
|
+
|
|
302
|
+
const args = process.argv.slice(2);
|
|
303
|
+
const mcpFlag = args.find(a => a.startsWith('--mcp='));
|
|
304
|
+
const requestedEditors = mcpFlag ? mcpFlag.split('=')[1].split(',') : [];
|
|
305
|
+
|
|
306
|
+
const editors = requestedEditors.length > 0 ? requestedEditors : detectEditors();
|
|
307
|
+
console.log(` Detected editors/environments: ${editors.join(', ') || 'none'}`);
|
|
308
|
+
|
|
309
|
+
const projectName = basename(cwd);
|
|
310
|
+
|
|
311
|
+
if (editors.includes('cursor')) writeCursorConfig(projectName);
|
|
312
|
+
if (editors.includes('aider')) writeAiderConfig(projectName);
|
|
313
|
+
if (editors.includes('claude-code')) writeClaudeCodeConfig(projectName);
|
|
314
|
+
if (editors.includes('continue')) writeContinueConfig(projectName);
|
|
315
|
+
|
|
316
|
+
// 5. Final self-test and notes
|
|
166
317
|
console.log('');
|
|
167
|
-
console.log('
|
|
168
|
-
console.log('
|
|
169
|
-
console.log(' 2. Add a new command server:');
|
|
170
|
-
console.log(' • Name: persyst');
|
|
171
|
-
console.log(' • Command: npx');
|
|
172
|
-
console.log(' • Arguments: -y persyst-mcp');
|
|
318
|
+
console.log(' ══════════════════════════════════════');
|
|
319
|
+
console.log(' Setup complete: Persyst is successfully configured.');
|
|
173
320
|
console.log('');
|
|
174
|
-
console.log('
|
|
175
|
-
console.log('
|
|
176
|
-
console.log('
|
|
177
|
-
console.log('
|
|
321
|
+
console.log(' Next steps:');
|
|
322
|
+
console.log(' 1. Restart your editor to load the new MCP configurations.');
|
|
323
|
+
console.log(' 2. Test gateway connection:');
|
|
324
|
+
console.log(' curl http://127.0.0.1:4321/health');
|
|
178
325
|
console.log('');
|
|
179
326
|
}
|
|
180
327
|
|
package/bin/mcp.js
ADDED