engramx 2.1.0 → 3.0.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.
- package/CHANGELOG.md +110 -0
- package/README.md +114 -17
- package/dist/{aider-context-J557IHIP.js → aider-context-6IDE3R7U.js} +1 -1
- package/dist/{chunk-PEH54LYC.js → chunk-645NBY6L.js} +42 -5
- package/dist/chunk-73IBCRFI.js +215 -0
- package/dist/{chunk-ZVWRIVWQ.js → chunk-B4UOE64J.js} +29 -11
- package/dist/{chunk-XFE6ZANP.js → chunk-FKY6HIT2.js} +1 -1
- package/dist/chunk-RJC6RNXJ.js +1405 -0
- package/dist/{chunk-4XA6ENNL.js → chunk-VLTWBTQ7.js} +14 -15
- package/dist/chunk-ZUC6OXSL.js +178 -0
- package/dist/cli.js +277 -1259
- package/dist/{core-TSXA5XZH.js → core-77F2BVYV.js} +2 -2
- package/dist/{cursor-mdc-VEOFFDVO.js → cursor-mdc-EEO7PYZ3.js} +1 -1
- package/dist/{exporter-AWXS34AS.js → exporter-ZYJ4WM2F.js} +1 -1
- package/dist/{importer-3Q5M6QBL.js → importer-4UWQDH4W.js} +1 -1
- package/dist/index.js +3 -3
- package/dist/mcp-client-ROOJF76V.js +9 -0
- package/dist/mcp-config-QD4NPVXB.js +12 -0
- package/dist/{migrate-UKCO6BUU.js → migrate-KJ5K5NWO.js} +1 -1
- package/dist/{plugin-loader-STTGYIL5.js → plugin-loader-SQQB6V74.js} +69 -23
- package/dist/resolver-H7GXVP73.js +21 -0
- package/dist/serve.js +2 -2
- package/dist/{server-A6MUVKQK.js → server-2ZQKXJ5M.js} +74 -6
- package/dist/{windsurf-rules-RWPKBHRD.js → windsurf-rules-XF7MYF6J.js} +1 -1
- package/dist/{wizard-AOXWMSXW.js → wizard-UH27IO4I.js} +2 -2
- package/package.json +8 -3
- package/scripts/postinstall.mjs +32 -0
- package/scripts/preuninstall.mjs +200 -0
- package/dist/{tuner-KFNNGKG3.js → tuner-Y2YENAZC.js} +3 -3
|
@@ -310,7 +310,7 @@ function writeToFile(filePath, summary) {
|
|
|
310
310
|
writeFileSync2(filePath, newContent);
|
|
311
311
|
}
|
|
312
312
|
async function autogen(projectRoot, target, task) {
|
|
313
|
-
const { getStore } = await import("./core-
|
|
313
|
+
const { getStore } = await import("./core-77F2BVYV.js");
|
|
314
314
|
const store = await getStore(projectRoot);
|
|
315
315
|
try {
|
|
316
316
|
let view = VIEWS.general;
|
|
@@ -326,26 +326,25 @@ async function autogen(projectRoot, target, task) {
|
|
|
326
326
|
}
|
|
327
327
|
const summary = generateSummary(store, view);
|
|
328
328
|
const stats = store.getStats();
|
|
329
|
-
|
|
329
|
+
const targetFiles = [];
|
|
330
330
|
if (target === "claude") {
|
|
331
|
-
|
|
331
|
+
targetFiles.push(join2(projectRoot, "CLAUDE.md"));
|
|
332
332
|
} else if (target === "cursor") {
|
|
333
|
-
|
|
333
|
+
targetFiles.push(join2(projectRoot, ".cursorrules"));
|
|
334
334
|
} else if (target === "agents") {
|
|
335
|
-
|
|
335
|
+
targetFiles.push(join2(projectRoot, "AGENTS.md"));
|
|
336
336
|
} else {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
targetFile = join2(projectRoot, "AGENTS.md");
|
|
343
|
-
} else {
|
|
344
|
-
targetFile = join2(projectRoot, "CLAUDE.md");
|
|
337
|
+
targetFiles.push(join2(projectRoot, "CLAUDE.md"));
|
|
338
|
+
targetFiles.push(join2(projectRoot, "AGENTS.md"));
|
|
339
|
+
const cursorRules = join2(projectRoot, ".cursorrules");
|
|
340
|
+
if (existsSync2(cursorRules)) {
|
|
341
|
+
targetFiles.push(cursorRules);
|
|
345
342
|
}
|
|
346
343
|
}
|
|
347
|
-
|
|
348
|
-
|
|
344
|
+
for (const f of targetFiles) {
|
|
345
|
+
writeToFile(f, summary);
|
|
346
|
+
}
|
|
347
|
+
return { files: targetFiles, nodesIncluded: stats.nodes, view: view.name };
|
|
349
348
|
} finally {
|
|
350
349
|
store.close();
|
|
351
350
|
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// src/providers/mcp-config.ts
|
|
2
|
+
import { readFileSync, existsSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
function getMcpConfigPath() {
|
|
6
|
+
const override = process.env.ENGRAM_MCP_CONFIG_PATH;
|
|
7
|
+
if (override && override.length > 0) return override;
|
|
8
|
+
return join(homedir(), ".engram", "mcp-providers.json");
|
|
9
|
+
}
|
|
10
|
+
function loadMcpConfigs(path = getMcpConfigPath()) {
|
|
11
|
+
if (!existsSync(path)) {
|
|
12
|
+
return { configs: [], failed: [] };
|
|
13
|
+
}
|
|
14
|
+
let raw;
|
|
15
|
+
try {
|
|
16
|
+
raw = readFileSync(path, "utf-8");
|
|
17
|
+
} catch (err) {
|
|
18
|
+
return {
|
|
19
|
+
configs: [],
|
|
20
|
+
failed: [
|
|
21
|
+
{
|
|
22
|
+
index: -1,
|
|
23
|
+
reason: `failed to read config file: ${err.message}`
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = JSON.parse(raw);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
return {
|
|
33
|
+
configs: [],
|
|
34
|
+
failed: [
|
|
35
|
+
{
|
|
36
|
+
index: -1,
|
|
37
|
+
reason: `invalid JSON in ${path}: ${err.message}`
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (!isMcpProvidersFile(parsed)) {
|
|
43
|
+
return {
|
|
44
|
+
configs: [],
|
|
45
|
+
failed: [
|
|
46
|
+
{
|
|
47
|
+
index: -1,
|
|
48
|
+
reason: `expected { providers: [...] } shape in ${path}`
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const valid = [];
|
|
54
|
+
const failed = [];
|
|
55
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
56
|
+
for (let i = 0; i < parsed.providers.length; i++) {
|
|
57
|
+
const entry = parsed.providers[i];
|
|
58
|
+
const validation = validateProviderConfig(entry);
|
|
59
|
+
if (validation.ok) {
|
|
60
|
+
if (seenNames.has(validation.value.name)) {
|
|
61
|
+
failed.push({
|
|
62
|
+
index: i,
|
|
63
|
+
reason: `duplicate provider name '${validation.value.name}' \u2014 first occurrence wins`
|
|
64
|
+
});
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
seenNames.add(validation.value.name);
|
|
68
|
+
valid.push(validation.value);
|
|
69
|
+
} else {
|
|
70
|
+
failed.push({ index: i, reason: validation.reason });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { configs: valid, failed };
|
|
74
|
+
}
|
|
75
|
+
function isMcpProvidersFile(v) {
|
|
76
|
+
if (!v || typeof v !== "object") return false;
|
|
77
|
+
const obj = v;
|
|
78
|
+
return Array.isArray(obj.providers);
|
|
79
|
+
}
|
|
80
|
+
function validateProviderConfig(raw) {
|
|
81
|
+
if (!raw || typeof raw !== "object") {
|
|
82
|
+
return { ok: false, reason: "entry is not an object" };
|
|
83
|
+
}
|
|
84
|
+
const o = raw;
|
|
85
|
+
if (typeof o.name !== "string" || o.name.length === 0) {
|
|
86
|
+
return { ok: false, reason: "`name` must be a non-empty string" };
|
|
87
|
+
}
|
|
88
|
+
if (typeof o.label !== "string" || o.label.length === 0) {
|
|
89
|
+
return { ok: false, reason: `[${o.name}] 'label' must be a non-empty string` };
|
|
90
|
+
}
|
|
91
|
+
if (o.transport !== "stdio" && o.transport !== "http") {
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
reason: `[${o.name}] 'transport' must be 'stdio' or 'http'`
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (!Array.isArray(o.tools)) {
|
|
98
|
+
return { ok: false, reason: `[${o.name}] 'tools' must be an array` };
|
|
99
|
+
}
|
|
100
|
+
for (let i = 0; i < o.tools.length; i++) {
|
|
101
|
+
const t = o.tools[i];
|
|
102
|
+
if (!t || typeof t.name !== "string" || t.name.length === 0) {
|
|
103
|
+
return {
|
|
104
|
+
ok: false,
|
|
105
|
+
reason: `[${o.name}] tools[${i}].name must be a non-empty string`
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (t.args !== void 0 && (typeof t.args !== "object" || t.args === null)) {
|
|
109
|
+
return { ok: false, reason: `[${o.name}] tools[${i}].args must be an object` };
|
|
110
|
+
}
|
|
111
|
+
if (t.confidence !== void 0) {
|
|
112
|
+
if (typeof t.confidence !== "number" || t.confidence < 0 || t.confidence > 1) {
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
reason: `[${o.name}] tools[${i}].confidence must be in [0, 1]`
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (o.transport === "stdio") {
|
|
121
|
+
if (typeof o.command !== "string" || o.command.length === 0) {
|
|
122
|
+
return { ok: false, reason: `[${o.name}] 'command' required for stdio transport` };
|
|
123
|
+
}
|
|
124
|
+
if (o.args !== void 0 && !Array.isArray(o.args)) {
|
|
125
|
+
return { ok: false, reason: `[${o.name}] 'args' must be an array of strings` };
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
if (typeof o.url !== "string" || o.url.length === 0) {
|
|
129
|
+
return { ok: false, reason: `[${o.name}] 'url' required for http transport` };
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
new URL(o.url);
|
|
133
|
+
} catch {
|
|
134
|
+
return { ok: false, reason: `[${o.name}] 'url' is not a valid URL` };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for (const field of ["tokenBudget", "timeoutMs", "cacheTtlSec", "priority"]) {
|
|
138
|
+
if (o[field] !== void 0) {
|
|
139
|
+
if (typeof o[field] !== "number" || o[field] < 0) {
|
|
140
|
+
return {
|
|
141
|
+
ok: false,
|
|
142
|
+
reason: `[${o.name}] '${field}' must be a non-negative number`
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { ok: true, value: raw };
|
|
148
|
+
}
|
|
149
|
+
function applyArgTemplate(template, ctx) {
|
|
150
|
+
const defaults = { path: "{filePath}" };
|
|
151
|
+
const src = template ?? defaults;
|
|
152
|
+
const out = {};
|
|
153
|
+
const basename = ctx.fileBasename ?? ctx.filePath.split(/[\\/]/).pop() ?? ctx.filePath;
|
|
154
|
+
const tokens = {
|
|
155
|
+
filePath: ctx.filePath,
|
|
156
|
+
projectRoot: ctx.projectRoot,
|
|
157
|
+
imports: ctx.imports.join(","),
|
|
158
|
+
fileBasename: basename
|
|
159
|
+
};
|
|
160
|
+
for (const [key, value] of Object.entries(src)) {
|
|
161
|
+
if (typeof value === "string") {
|
|
162
|
+
out[key] = value.replace(
|
|
163
|
+
/\{(\w+)\}/g,
|
|
164
|
+
(match, token) => Object.prototype.hasOwnProperty.call(tokens, token) ? tokens[token] : match
|
|
165
|
+
);
|
|
166
|
+
} else {
|
|
167
|
+
out[key] = value;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export {
|
|
174
|
+
getMcpConfigPath,
|
|
175
|
+
loadMcpConfigs,
|
|
176
|
+
validateProviderConfig,
|
|
177
|
+
applyArgTemplate
|
|
178
|
+
};
|