premanmcp 1.0.4 → 1.0.5
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/hook.js +61 -5
- package/package.json +1 -1
package/bin/hook.js
CHANGED
|
@@ -139,6 +139,57 @@ function isGeneratedInvocation(invocation) {
|
|
|
139
139
|
return invocation === "preman" || /^npm exec -y premanmcp@\S+ --$/.test(invocation);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* The release a generated invocation pins, or "" when it does not pin one.
|
|
144
|
+
*
|
|
145
|
+
* The bare `preman` form resolves at push time, and `@latest` is whatever we
|
|
146
|
+
* ship next, so neither can be out of date. Only an explicit version can be.
|
|
147
|
+
*/
|
|
148
|
+
export function pinnedRelease(invocation) {
|
|
149
|
+
const match = /^npm exec -y premanmcp@(\S+) --$/.exec(String(invocation || "").trim());
|
|
150
|
+
const version = match ? match[1] : "";
|
|
151
|
+
return version === "latest" ? "" : version;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Is `left` an earlier release than `right`?
|
|
156
|
+
*
|
|
157
|
+
* Anything this cannot read as three numbers compares as not-older, so a
|
|
158
|
+
* prerelease tag or a mirror's own numbering is left alone rather than being
|
|
159
|
+
* rewritten on a guess.
|
|
160
|
+
*/
|
|
161
|
+
export function isOlderRelease(left, right) {
|
|
162
|
+
const parse = (value) => String(value).split(".").map((part) => Number.parseInt(part, 10));
|
|
163
|
+
const a = parse(left);
|
|
164
|
+
const b = parse(right);
|
|
165
|
+
if (a.length !== 3 || b.length !== 3) return false;
|
|
166
|
+
if ([...a, ...b].some((part) => !Number.isFinite(part))) return false;
|
|
167
|
+
for (let index = 0; index < 3; index += 1) {
|
|
168
|
+
if (a[index] !== b[index]) return a[index] < b[index];
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Does this hook run a PreMan older than the one asking?
|
|
175
|
+
*
|
|
176
|
+
* A pinned hook keeps working long after it stops being current -- it answers
|
|
177
|
+
* `help`, it runs `verify`, it just does all of it as the version that wrote
|
|
178
|
+
* it. Found in the wild: a hook still on 0.13.0 while 1.0.4 was installed,
|
|
179
|
+
* printing an error message whose formatting had been fixed several releases
|
|
180
|
+
* earlier, with nothing anywhere to say why.
|
|
181
|
+
*
|
|
182
|
+
* Only ever true when we would be moving forward. An older CLI run for some
|
|
183
|
+
* other reason must not drag a newer hook back with it.
|
|
184
|
+
*/
|
|
185
|
+
export function hookIsBehind(invocation) {
|
|
186
|
+
if (declaredInvocation()) return false;
|
|
187
|
+
const pinned = pinnedRelease(invocation);
|
|
188
|
+
const running = packageVersion();
|
|
189
|
+
if (!pinned || !running) return false;
|
|
190
|
+
return isOlderRelease(pinned, running);
|
|
191
|
+
}
|
|
192
|
+
|
|
142
193
|
function hookBody(invocation) {
|
|
143
194
|
// `exec` is deliberately absent: we want the wrapper to survive the CLI exiting
|
|
144
195
|
// non-zero and still exit 0 itself.
|
|
@@ -319,9 +370,11 @@ function rememberHookCheck(cwd, now, fields) {
|
|
|
319
370
|
* PreMan is running here -- any command, the MCP server starting -- is taken as
|
|
320
371
|
* the moment to check.
|
|
321
372
|
*
|
|
322
|
-
* Deliberately narrow. It only ever rewrites a hook we wrote
|
|
323
|
-
*
|
|
324
|
-
*
|
|
373
|
+
* Deliberately narrow. It only ever rewrites a hook we wrote: an absent hook is
|
|
374
|
+
* not installed behind the user, and a foreign hook is not touched. A working
|
|
375
|
+
* hook is rewritten only when it pins a release older than the one running --
|
|
376
|
+
* see `hookIsBehind` -- because "it answers" and "it is the CLI we ship" stopped
|
|
377
|
+
* being the same question once a pin could outlive several releases.
|
|
325
378
|
*/
|
|
326
379
|
export function repairDeadHook({ cwd = process.cwd(), now = Date.now(), force = false } = {}) {
|
|
327
380
|
const remember = (fields) => rememberHookCheck(cwd, now, fields);
|
|
@@ -337,11 +390,14 @@ export function repairDeadHook({ cwd = process.cwd(), now = Date.now(), force =
|
|
|
337
390
|
return remember({ action: "not-a-repository" });
|
|
338
391
|
}
|
|
339
392
|
if (status.state !== "installed") return remember({ action: status.state });
|
|
340
|
-
|
|
393
|
+
const behind = hookIsBehind(status.invocation);
|
|
394
|
+
if (status.works && !behind) {
|
|
395
|
+
return remember({ action: "healthy", invocation: status.invocation });
|
|
396
|
+
}
|
|
341
397
|
|
|
342
398
|
const result = installHook(makeArgs([]));
|
|
343
399
|
return remember({
|
|
344
|
-
action: result.action === "updated" ? "repaired" : result.action,
|
|
400
|
+
action: result.action === "updated" ? (behind ? "upgraded" : "repaired") : result.action,
|
|
345
401
|
invocation: result.invocation || "",
|
|
346
402
|
replaced: status.invocation,
|
|
347
403
|
});
|