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/bin/init.js CHANGED
@@ -1,30 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * persyst-init — Workspace rules generator for VS Code-based IDEs (Cursor, Windsurf, Antigravity)
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. Safely creates or appends system instructions to `.windsurfrules`
12
- * 3. Creates a general `.persystrules.md` copy-pasteable guide
13
- * 4. Prints instructions on configuring MCP servers in Cursor/VS Code/Antigravity
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(` ℹ️ ${fileName} already has Persyst rules configured (skipped).`);
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(` ${action} ${fileName}`);
110
+ console.log(` [OK] ${action} ${fileName}`);
104
111
  }
105
112
 
106
113
  // ============================================================
107
- // MAIN
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(' 🧠 Persyst — Workspace Rules Setup');
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(` 📁 Target workspace: ${cwd}`);
118
- console.log('');
244
+ console.log(` Target workspace: ${cwd}`);
119
245
 
120
- // 1. Create/Append Cursor Rules
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
- // 3. Create General Guide File
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(' Created .persystrules.md (General Guide)');
267
+ console.log(' [OK] Created .persystrules.md (General Guide)');
132
268
 
133
- // 4. Configure Git post-commit hook for automatic commit ingestion
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(' Configured Git post-commit hook for auto-ingestion');
295
+ console.log(' [OK] Configured Git post-commit hook for auto-ingestion');
160
296
  }
161
297
 
162
- // 5. Print Success & Configuration Help
298
+ // 4. Global editor configurations
163
299
  console.log('');
164
- console.log(' ════════════════════════════════════');
165
- console.log(' ✅ Rules and Git hooks initialization complete!');
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(' To connect the memory server to Cursor, Antigravity, or VS Code:');
168
- console.log(' 1. Open your IDE Settings -> MCP (Model Context Protocol).');
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(' The rules we generated will guide the AI agents in this workspace to:');
175
- console.log(' Proactively search memory before answering prompts.');
176
- console.log(' Log milestone achievements and user preferences.');
177
- console.log(' Keep the memory clean ("no bad data").');
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
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import '../index.js';
3
+