engram-mcp-server 1.2.2 → 1.2.3

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 CHANGED
@@ -216,15 +216,17 @@ Engram is published to the npm registry. **You do not need to download or compil
216
216
 
217
217
  As long as you have Node.js installed, your IDE will download and run the latest version of Engram automatically using `npx`.
218
218
 
219
- ### Option 1: The Magic Installer (Zero Config)
219
+ ### Option 1: The Magic Installer (Interactive)
220
220
 
221
- Run this single command in your terminal. It will automatically detect your IDEs (Cursor, VS Code, Visual Studio, Cline, Windsurf, Antigravity) and inject the correct configuration for you:
221
+ Run this single command in your terminal. It will automatically detect your IDE (Cursor, VS Code, Visual Studio, Cline, Windsurf, Antigravity) and ask for confirmation before injecting the configuration:
222
222
 
223
223
  ```bash
224
224
  npx -y engram-mcp-server --install
225
225
  ```
226
226
 
227
- *(You can also run `npx -y engram-mcp-server --list` to see what IDEs it detects before installing)*
227
+ If it cannot detect your IDE automatically, it will present a numbered menu where you can choose your IDE from a list, or even **provide a custom path** to any `mcp.json` file on your system.
228
+
229
+ *(You can also run `npx -y engram-mcp-server --list` to preview which IDEs are detected on your machine!)*
228
230
 
229
231
  Restart your IDE, and Engram is ready!
230
232
 
@@ -1,5 +1,5 @@
1
1
  export declare const SERVER_NAME = "engram-mcp-server";
2
- export declare const SERVER_VERSION = "1.2.2";
2
+ export declare const SERVER_VERSION = "1.2.3";
3
3
  export declare const TOOL_PREFIX = "engram";
4
4
  export declare const DB_DIR_NAME = ".engram";
5
5
  export declare const DB_FILE_NAME = "memory.db";
package/dist/constants.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // Engram MCP Server — Constants
3
3
  // ============================================================================
4
4
  export const SERVER_NAME = "engram-mcp-server";
5
- export const SERVER_VERSION = "1.2.2";
5
+ export const SERVER_VERSION = "1.2.3";
6
6
  export const TOOL_PREFIX = "engram";
7
7
  // Database
8
8
  export const DB_DIR_NAME = ".engram";
@@ -1,2 +1,2 @@
1
- export declare function runInstaller(args: string[]): void;
1
+ export declare function runInstaller(args: string[]): Promise<void>;
2
2
  //# sourceMappingURL=installer.d.ts.map
package/dist/installer.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import os from "os";
4
+ import readline from "readline";
4
5
  const HOME = os.homedir();
5
6
  const APPDATA = process.env.APPDATA || path.join(HOME, ".config");
6
7
  // ─── IDE Config Locations ────────────────────────────────────────────
@@ -82,18 +83,62 @@ function addToConfig(configPath, format) {
82
83
  const key = format; // "mcpServers" or "servers"
83
84
  if (!config[key])
84
85
  config[key] = {};
86
+ const newEntry = makeEngramEntry(format);
85
87
  if (config[key].engram) {
86
- // Already exists — update to use npx
87
- config[key].engram = makeEngramEntry(format);
88
+ // Already exists — check if it's identical
89
+ if (JSON.stringify(config[key].engram) === JSON.stringify(newEntry)) {
90
+ return "exists";
91
+ }
92
+ // Exists but different (e.g. old local path) — update to use npx
93
+ config[key].engram = newEntry;
88
94
  writeJson(configPath, config);
89
95
  return "updated";
90
96
  }
91
- config[key].engram = makeEngramEntry(format);
97
+ config[key].engram = newEntry;
92
98
  writeJson(configPath, config);
93
99
  return "added";
94
100
  }
101
+ // ─── Environment Detection ──────────────────────────────────────────
102
+ function detectCurrentIde() {
103
+ const env = process.env;
104
+ // Explicit hints usually present in extension hosts or integrated terminals
105
+ if (env.ANTIGRAVITY_EDITOR_APP_ROOT)
106
+ return "antigravity";
107
+ if (env.WINDSURF_PROFILE)
108
+ return "windsurf";
109
+ // VS Code forks share TERM_PROGRAM="vscode", but we can distinguish them by checking VSCODE_CWD or path
110
+ if (env.TERM_PROGRAM === "vscode" || env.VSCODE_IPC_HOOK || env.VSCODE_CWD) {
111
+ const cwdLower = (env.VSCODE_CWD || "").toLowerCase();
112
+ if (cwdLower.includes("antigravity"))
113
+ return "antigravity";
114
+ if (cwdLower.includes("cursor"))
115
+ return "cursor";
116
+ if (cwdLower.includes("windsurf"))
117
+ return "windsurf";
118
+ // Final fallback: check PATH but ONLY for the specific IDE execution paths, not generically
119
+ const pathLower = (env.PATH || "").toLowerCase();
120
+ if (pathLower.includes("antigravity"))
121
+ return "antigravity";
122
+ if (pathLower.includes("cursor\\cli"))
123
+ return "cursor"; // more specific to avoid false positives
124
+ if (pathLower.includes("windsurf"))
125
+ return "windsurf";
126
+ return "vscode";
127
+ }
128
+ return null;
129
+ }
95
130
  // ─── Main ────────────────────────────────────────────────────────────
96
- export function runInstaller(args) {
131
+ async function askQuestion(query) {
132
+ const rl = readline.createInterface({
133
+ input: process.stdin,
134
+ output: process.stdout,
135
+ });
136
+ return new Promise(resolve => rl.question(query, ans => {
137
+ rl.close();
138
+ resolve(ans);
139
+ }));
140
+ }
141
+ export async function runInstaller(args) {
97
142
  if (args.includes("--list")) {
98
143
  console.log("\nEngram can be auto-installed into these IDEs:\n");
99
144
  for (const [id, ide] of Object.entries(IDE_CONFIGS)) {
@@ -102,17 +147,75 @@ export function runInstaller(args) {
102
147
  }
103
148
  process.exit(0);
104
149
  }
105
- // Specific IDE requested?
150
+ // Specific IDE requested via CLI flag?
106
151
  const ideFlagIdx = args.indexOf("--ide");
107
- const targetIde = ideFlagIdx >= 0 ? args[ideFlagIdx + 1] : null;
108
- const idesToProcess = targetIde
109
- ? (IDE_CONFIGS[targetIde] ? { [targetIde]: IDE_CONFIGS[targetIde] } : null)
110
- : IDE_CONFIGS;
111
- if (!idesToProcess) {
112
- console.error(`Unknown IDE: "${targetIde}". Options: ${Object.keys(IDE_CONFIGS).join(", ")}`);
113
- process.exit(1);
152
+ if (ideFlagIdx >= 0 && args[ideFlagIdx + 1]) {
153
+ const targetIde = args[ideFlagIdx + 1];
154
+ if (!IDE_CONFIGS[targetIde]) {
155
+ console.error(`Unknown IDE: "${targetIde}". Options: ${Object.keys(IDE_CONFIGS).join(", ")}`);
156
+ process.exit(1);
157
+ }
158
+ await performInstallation({ [targetIde]: IDE_CONFIGS[targetIde] });
159
+ return;
114
160
  }
115
161
  console.log("\n🧠 Engram MCP Installer\n");
162
+ // Auto-detect environment if it's run without specific args
163
+ const currentIde = detectCurrentIde();
164
+ if (currentIde && IDE_CONFIGS[currentIde]) {
165
+ console.log(`🔍 Detected environment: ${IDE_CONFIGS[currentIde].name}`);
166
+ const ans = await askQuestion(" Install Engram for this IDE? [Y/n]: ");
167
+ if (ans.trim().toLowerCase() !== 'n') {
168
+ await performInstallation({ [currentIde]: IDE_CONFIGS[currentIde] });
169
+ return;
170
+ }
171
+ console.log(""); // Skip to menu
172
+ }
173
+ // Interactive Menu
174
+ console.log("Where would you like to configure the Engram MCP server?\n");
175
+ const ideKeys = Object.keys(IDE_CONFIGS);
176
+ ideKeys.forEach((key, index) => {
177
+ console.log(` ${index + 1}. ${IDE_CONFIGS[key].name}`);
178
+ });
179
+ const allOpt = ideKeys.length + 1;
180
+ const customOpt = ideKeys.length + 2;
181
+ console.log(` ${allOpt}. Install to ALL detected IDEs`);
182
+ console.log(` ${customOpt}. Custom IDE config path...`);
183
+ console.log(` 0. Cancel`);
184
+ const answer = await askQuestion(`\nSelect an option [0-${customOpt}]: `);
185
+ const choice = parseInt(answer.trim(), 10);
186
+ if (isNaN(choice) || choice === 0) {
187
+ console.log("Installation cancelled.");
188
+ process.exit(0);
189
+ }
190
+ let idesToProcess = {};
191
+ if (choice === allOpt) {
192
+ idesToProcess = IDE_CONFIGS; // All
193
+ }
194
+ else if (choice === customOpt) {
195
+ const customPath = await askQuestion("Enter the absolute path to your MCP config JSON file: ");
196
+ if (!customPath.trim()) {
197
+ console.log("No path provided. Exiting.");
198
+ process.exit(1);
199
+ }
200
+ idesToProcess = {
201
+ custom: {
202
+ name: "Custom Path",
203
+ paths: [customPath.trim()],
204
+ format: "mcpServers" // Safe default for unknown IDEs
205
+ }
206
+ };
207
+ }
208
+ else if (choice >= 1 && choice <= ideKeys.length) {
209
+ const selectedKey = ideKeys[choice - 1];
210
+ idesToProcess = { [selectedKey]: IDE_CONFIGS[selectedKey] };
211
+ }
212
+ else {
213
+ console.log("\nInvalid selection. Exiting.");
214
+ process.exit(1);
215
+ }
216
+ await performInstallation(idesToProcess);
217
+ }
218
+ async function performInstallation(idesToProcess) {
116
219
  let installed = 0;
117
220
  for (const [id, ide] of Object.entries(idesToProcess)) {
118
221
  const configPath = ide.paths.find((p) => fs.existsSync(p)) || ide.paths[0];
@@ -120,8 +223,17 @@ export function runInstaller(args) {
120
223
  const result = addToConfig(configPath, ide.format);
121
224
  console.log(`\n ✅ ${ide.name}`);
122
225
  console.log(` Config: ${configPath}`);
123
- console.log(` Status: ${result === "added" ? "Engram added" : "Engram config updated to use npx"}`);
124
- installed++;
226
+ let statusText = "";
227
+ if (result === "added")
228
+ statusText = "Engram added";
229
+ else if (result === "updated")
230
+ statusText = "Engram config updated to use npx";
231
+ else if (result === "exists")
232
+ statusText = "Engram is already installed and up to date";
233
+ console.log(` Status: ${statusText}`);
234
+ if (result !== "exists") {
235
+ installed++;
236
+ }
125
237
  }
126
238
  catch (e) {
127
239
  console.log(`\n ⚠️ ${ide.name}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "engram-mcp-server",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Engram — Persistent Memory Cortex for AI coding agents. Gives agents session continuity, change tracking, decision logging, and project intelligence across sessions.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/constants.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // ============================================================================
4
4
 
5
5
  export const SERVER_NAME = "engram-mcp-server";
6
- export const SERVER_VERSION = "1.2.2";
6
+ export const SERVER_VERSION = "1.2.3";
7
7
  export const TOOL_PREFIX = "engram";
8
8
 
9
9
  // Database
package/src/installer.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import os from "os";
4
+ import readline from "readline";
4
5
 
5
6
  const HOME = os.homedir();
6
7
  const APPDATA = process.env.APPDATA || path.join(HOME, ".config");
@@ -88,26 +89,73 @@ function writeJson(filePath: string, data: any) {
88
89
  }
89
90
 
90
91
  function addToConfig(configPath: string, format: string) {
91
- let config = readJson(configPath) || {};
92
+ let config: Record<string, any> = readJson(configPath) || {};
92
93
  const key = format; // "mcpServers" or "servers"
93
94
 
94
95
  if (!config[key]) config[key] = {};
95
96
 
97
+ const newEntry = makeEngramEntry(format);
98
+
96
99
  if (config[key].engram) {
97
- // Already exists — update to use npx
98
- config[key].engram = makeEngramEntry(format);
100
+ // Already exists — check if it's identical
101
+ if (JSON.stringify(config[key].engram) === JSON.stringify(newEntry)) {
102
+ return "exists";
103
+ }
104
+
105
+ // Exists but different (e.g. old local path) — update to use npx
106
+ config[key].engram = newEntry;
99
107
  writeJson(configPath, config);
100
108
  return "updated";
101
109
  }
102
110
 
103
- config[key].engram = makeEngramEntry(format);
111
+ config[key].engram = newEntry;
104
112
  writeJson(configPath, config);
105
113
  return "added";
106
114
  }
107
115
 
116
+ // ─── Environment Detection ──────────────────────────────────────────
117
+
118
+ function detectCurrentIde(): string | null {
119
+ const env = process.env;
120
+
121
+ // Explicit hints usually present in extension hosts or integrated terminals
122
+ if (env.ANTIGRAVITY_EDITOR_APP_ROOT) return "antigravity";
123
+ if (env.WINDSURF_PROFILE) return "windsurf";
124
+
125
+ // VS Code forks share TERM_PROGRAM="vscode", but we can distinguish them by checking VSCODE_CWD or path
126
+ if (env.TERM_PROGRAM === "vscode" || env.VSCODE_IPC_HOOK || env.VSCODE_CWD) {
127
+ const cwdLower = (env.VSCODE_CWD || "").toLowerCase();
128
+ if (cwdLower.includes("antigravity")) return "antigravity";
129
+ if (cwdLower.includes("cursor")) return "cursor";
130
+ if (cwdLower.includes("windsurf")) return "windsurf";
131
+
132
+ // Final fallback: check PATH but ONLY for the specific IDE execution paths, not generically
133
+ const pathLower = (env.PATH || "").toLowerCase();
134
+ if (pathLower.includes("antigravity")) return "antigravity";
135
+ if (pathLower.includes("cursor\\cli")) return "cursor"; // more specific to avoid false positives
136
+ if (pathLower.includes("windsurf")) return "windsurf";
137
+
138
+ return "vscode";
139
+ }
140
+
141
+ return null;
142
+ }
143
+
108
144
  // ─── Main ────────────────────────────────────────────────────────────
109
145
 
110
- export function runInstaller(args: string[]) {
146
+ async function askQuestion(query: string): Promise<string> {
147
+ const rl = readline.createInterface({
148
+ input: process.stdin,
149
+ output: process.stdout,
150
+ });
151
+
152
+ return new Promise(resolve => rl.question(query, ans => {
153
+ rl.close();
154
+ resolve(ans);
155
+ }));
156
+ }
157
+
158
+ export async function runInstaller(args: string[]) {
111
159
  if (args.includes("--list")) {
112
160
  console.log("\nEngram can be auto-installed into these IDEs:\n");
113
161
  for (const [id, ide] of Object.entries(IDE_CONFIGS)) {
@@ -117,21 +165,86 @@ export function runInstaller(args: string[]) {
117
165
  process.exit(0);
118
166
  }
119
167
 
120
- // Specific IDE requested?
168
+ // Specific IDE requested via CLI flag?
121
169
  const ideFlagIdx = args.indexOf("--ide");
122
- const targetIde = ideFlagIdx >= 0 ? args[ideFlagIdx + 1] : null;
170
+ if (ideFlagIdx >= 0 && args[ideFlagIdx + 1]) {
171
+ const targetIde = args[ideFlagIdx + 1];
172
+ if (!IDE_CONFIGS[targetIde]) {
173
+ console.error(`Unknown IDE: "${targetIde}". Options: ${Object.keys(IDE_CONFIGS).join(", ")}`);
174
+ process.exit(1);
175
+ }
176
+ await performInstallation({ [targetIde]: IDE_CONFIGS[targetIde] });
177
+ return;
178
+ }
179
+
180
+ console.log("\n🧠 Engram MCP Installer\n");
181
+
182
+ // Auto-detect environment if it's run without specific args
183
+ const currentIde = detectCurrentIde();
123
184
 
124
- const idesToProcess = targetIde
125
- ? (IDE_CONFIGS[targetIde] ? { [targetIde]: IDE_CONFIGS[targetIde] } : null)
126
- : IDE_CONFIGS;
185
+ if (currentIde && IDE_CONFIGS[currentIde]) {
186
+ console.log(`🔍 Detected environment: ${IDE_CONFIGS[currentIde].name}`);
187
+ const ans = await askQuestion(" Install Engram for this IDE? [Y/n]: ");
127
188
 
128
- if (!idesToProcess) {
129
- console.error(`Unknown IDE: "${targetIde}". Options: ${Object.keys(IDE_CONFIGS).join(", ")}`);
189
+ if (ans.trim().toLowerCase() !== 'n') {
190
+ await performInstallation({ [currentIde]: IDE_CONFIGS[currentIde] });
191
+ return;
192
+ }
193
+ console.log(""); // Skip to menu
194
+ }
195
+
196
+ // Interactive Menu
197
+ console.log("Where would you like to configure the Engram MCP server?\n");
198
+
199
+ const ideKeys = Object.keys(IDE_CONFIGS);
200
+ ideKeys.forEach((key, index) => {
201
+ console.log(` ${index + 1}. ${IDE_CONFIGS[key].name}`);
202
+ });
203
+
204
+ const allOpt = ideKeys.length + 1;
205
+ const customOpt = ideKeys.length + 2;
206
+
207
+ console.log(` ${allOpt}. Install to ALL detected IDEs`);
208
+ console.log(` ${customOpt}. Custom IDE config path...`);
209
+ console.log(` 0. Cancel`);
210
+
211
+ const answer = await askQuestion(`\nSelect an option [0-${customOpt}]: `);
212
+ const choice = parseInt(answer.trim(), 10);
213
+
214
+ if (isNaN(choice) || choice === 0) {
215
+ console.log("Installation cancelled.");
216
+ process.exit(0);
217
+ }
218
+
219
+ let idesToProcess: Record<string, any> = {};
220
+
221
+ if (choice === allOpt) {
222
+ idesToProcess = IDE_CONFIGS; // All
223
+ } else if (choice === customOpt) {
224
+ const customPath = await askQuestion("Enter the absolute path to your MCP config JSON file: ");
225
+ if (!customPath.trim()) {
226
+ console.log("No path provided. Exiting.");
227
+ process.exit(1);
228
+ }
229
+ idesToProcess = {
230
+ custom: {
231
+ name: "Custom Path",
232
+ paths: [customPath.trim()],
233
+ format: "mcpServers" // Safe default for unknown IDEs
234
+ }
235
+ };
236
+ } else if (choice >= 1 && choice <= ideKeys.length) {
237
+ const selectedKey = ideKeys[choice - 1];
238
+ idesToProcess = { [selectedKey]: IDE_CONFIGS[selectedKey] };
239
+ } else {
240
+ console.log("\nInvalid selection. Exiting.");
130
241
  process.exit(1);
131
242
  }
132
243
 
133
- console.log("\n🧠 Engram MCP Installer\n");
244
+ await performInstallation(idesToProcess);
245
+ }
134
246
 
247
+ async function performInstallation(idesToProcess: Record<string, any>) {
135
248
  let installed = 0;
136
249
 
137
250
  for (const [id, ide] of Object.entries(idesToProcess)) {
@@ -141,8 +254,17 @@ export function runInstaller(args: string[]) {
141
254
  const result = addToConfig(configPath, ide.format);
142
255
  console.log(`\n ✅ ${ide.name}`);
143
256
  console.log(` Config: ${configPath}`);
144
- console.log(` Status: ${result === "added" ? "Engram added" : "Engram config updated to use npx"}`);
145
- installed++;
257
+
258
+ let statusText = "";
259
+ if (result === "added") statusText = "Engram added";
260
+ else if (result === "updated") statusText = "Engram config updated to use npx";
261
+ else if (result === "exists") statusText = "Engram is already installed and up to date";
262
+
263
+ console.log(` Status: ${statusText}`);
264
+
265
+ if (result !== "exists") {
266
+ installed++;
267
+ }
146
268
  } catch (e: any) {
147
269
  console.log(`\n ⚠️ ${ide.name}`);
148
270
  console.log(` Could not write to: ${configPath}`);