engineering-memory 0.2.2 → 0.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/install/installer.mjs +24 -11
- package/install/mcp-registration.mjs +25 -2
- package/package.json +1 -1
package/install/installer.mjs
CHANGED
|
@@ -107,8 +107,29 @@ export async function installEngineeringMemory(options = {}) {
|
|
|
107
107
|
dispatcherSection: dispatcherSections.claude,
|
|
108
108
|
},
|
|
109
109
|
};
|
|
110
|
+
const mcpPlans = await planMcpRegistrations({
|
|
111
|
+
selectedClients,
|
|
112
|
+
bridgeEntry,
|
|
113
|
+
nodePath,
|
|
114
|
+
apiUrl,
|
|
115
|
+
clientVersion,
|
|
116
|
+
state: existingState,
|
|
117
|
+
commandRunner,
|
|
118
|
+
clientsWereRequested: options.selectedClients !== undefined,
|
|
119
|
+
});
|
|
120
|
+
const absentClients = mcpPlans
|
|
121
|
+
.filter((plan) => plan.action === 'absent')
|
|
122
|
+
.map((plan) => plan.clientName);
|
|
123
|
+
const installedClients = selectedClients.filter(
|
|
124
|
+
(clientName) => !absentClients.includes(clientName),
|
|
125
|
+
);
|
|
126
|
+
if (installedClients.length === 0) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`None of the supported agent CLIs are on PATH: ${selectedClients.join(', ')}. Install one, then rerun the installer.`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
110
131
|
const clientPlans = await Promise.all(
|
|
111
|
-
|
|
132
|
+
installedClients.map(async (clientName) => {
|
|
112
133
|
const target = clientTargets[clientName];
|
|
113
134
|
return {
|
|
114
135
|
clientName,
|
|
@@ -120,15 +141,6 @@ export async function installEngineeringMemory(options = {}) {
|
|
|
120
141
|
};
|
|
121
142
|
}),
|
|
122
143
|
);
|
|
123
|
-
const mcpPlans = await planMcpRegistrations({
|
|
124
|
-
selectedClients,
|
|
125
|
-
bridgeEntry,
|
|
126
|
-
nodePath,
|
|
127
|
-
apiUrl,
|
|
128
|
-
clientVersion,
|
|
129
|
-
state: existingState,
|
|
130
|
-
commandRunner,
|
|
131
|
-
});
|
|
132
144
|
const hookPlan = await planGitHook({
|
|
133
145
|
repoRoot: options.repoRoot ? resolve(options.repoRoot) : null,
|
|
134
146
|
mode: options.hookMode ?? 'cancel',
|
|
@@ -189,7 +201,8 @@ export async function installEngineeringMemory(options = {}) {
|
|
|
189
201
|
statePath,
|
|
190
202
|
skillPaths: clientPlans.map((plan) => plan.skillPath),
|
|
191
203
|
dispatcherPaths: clientPlans.map((plan) => plan.dispatcherPath),
|
|
192
|
-
selectedClients,
|
|
204
|
+
selectedClients: installedClients,
|
|
205
|
+
absentClients,
|
|
193
206
|
apiUrl,
|
|
194
207
|
clientVersion,
|
|
195
208
|
runtimePath,
|
|
@@ -48,6 +48,7 @@ export async function planMcpRegistrations({
|
|
|
48
48
|
clientVersion,
|
|
49
49
|
state,
|
|
50
50
|
commandRunner,
|
|
51
|
+
clientsWereRequested = true,
|
|
51
52
|
}) {
|
|
52
53
|
const plans = [];
|
|
53
54
|
for (const clientName of selectedClients) {
|
|
@@ -55,6 +56,10 @@ export async function planMcpRegistrations({
|
|
|
55
56
|
if (!client) throw new Error(`Unsupported client: ${clientName}`);
|
|
56
57
|
const version = await commandRunner(client.executable, ['--version']);
|
|
57
58
|
if (version.code !== 0) {
|
|
59
|
+
if (!clientsWereRequested && !state?.mcp?.[clientName]) {
|
|
60
|
+
plans.push({ clientName, client, action: 'absent' });
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
58
63
|
throw new Error(
|
|
59
64
|
`${clientName} CLI is unavailable. Install its native CLI, ensure it is on PATH, then rerun the installer. ${commandFailure(client.executable, version)}`,
|
|
60
65
|
);
|
|
@@ -121,6 +126,7 @@ export async function planMcpRegistrations({
|
|
|
121
126
|
export async function applyMcpRegistrations(plans, commandRunner, transaction) {
|
|
122
127
|
const result = {};
|
|
123
128
|
for (const plan of plans) {
|
|
129
|
+
if (plan.action === 'absent') continue;
|
|
124
130
|
if (plan.action === 'add') {
|
|
125
131
|
await addRegistration(plan, plan.registration, commandRunner);
|
|
126
132
|
transaction.add(() => removeRegistration(plan, commandRunner));
|
|
@@ -211,6 +217,19 @@ function registrationFingerprint(clientName, registration) {
|
|
|
211
217
|
.digest('hex');
|
|
212
218
|
}
|
|
213
219
|
|
|
220
|
+
function fingerprintBeforeClientVersion(clientName, registration) {
|
|
221
|
+
return createHash('sha256')
|
|
222
|
+
.update(
|
|
223
|
+
JSON.stringify({
|
|
224
|
+
clientName,
|
|
225
|
+
nodePath: registration.nodePath,
|
|
226
|
+
bridgeEntry: registration.bridgeEntry,
|
|
227
|
+
apiUrl: registration.apiUrl ?? null,
|
|
228
|
+
}),
|
|
229
|
+
)
|
|
230
|
+
.digest('hex');
|
|
231
|
+
}
|
|
232
|
+
|
|
214
233
|
function sameRegistration(left, right) {
|
|
215
234
|
return (
|
|
216
235
|
left?.nodePath === right.nodePath &&
|
|
@@ -462,9 +481,13 @@ function isOwnedRegistration(clientName, managed) {
|
|
|
462
481
|
typeof managed.bridgeEntry === 'string'
|
|
463
482
|
);
|
|
464
483
|
}
|
|
484
|
+
if (typeof managed.apiUrl !== 'string') return false;
|
|
485
|
+
if (managed.fingerprint === registrationFingerprint(clientName, managed)) {
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
465
488
|
return (
|
|
466
|
-
|
|
467
|
-
managed.fingerprint ===
|
|
489
|
+
managed.clientVersion === undefined &&
|
|
490
|
+
managed.fingerprint === fingerprintBeforeClientVersion(clientName, managed)
|
|
468
491
|
);
|
|
469
492
|
}
|
|
470
493
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "engineering-memory",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Installs the Engineering Memory skill and its local MCP bridge. Sign in after installing; your organization and project are resolved from your account.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|