@compr/opscontext-mcp 2.5.2 โ 2.5.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/dist/cli.js +52 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -226,6 +226,52 @@ function generateMcpJson() {
|
|
|
226
226
|
// ---------------------------------------------------------------------------
|
|
227
227
|
// Template for pre-commit hook (CE doc freshness + secret scanner)
|
|
228
228
|
// ---------------------------------------------------------------------------
|
|
229
|
+
/**
|
|
230
|
+
* ๐ LOCKED [SKIPPING-A-HOOK-MUST-NAME-WHAT-IS-UNENFORCED] โ 2026-08-20
|
|
231
|
+
* โ NEVER print a bare "already exists, skipping" for a hook slot. NEVER overwrite or
|
|
232
|
+
* append to a foreign hook either.
|
|
233
|
+
* WHY: `init` refuses to clobber an existing hook, which is right, but it said so with one
|
|
234
|
+
* grey line among a column of green ticks. The user reads "init done" and believes the
|
|
235
|
+
* policy gates are live; in that repo they were never installed and enforce nothing.
|
|
236
|
+
* This is exactly ยงE1 arriving through a different door: there, the rule existed and no
|
|
237
|
+
* hook called it; here, a hook exists and does not call the rule. Both produce a gate
|
|
238
|
+
* that is present in every document and absent at runtime, and neither produces an error.
|
|
239
|
+
* A real instance is on this machine: invocme-odoo-connector has a hand-written
|
|
240
|
+
* pre-commit, so `init` skipped it, and none of that repo's CE gates have ever run.
|
|
241
|
+
* Appending instead is not the fix, and is how that repo ended up with a whole secret
|
|
242
|
+
* scanner sitting unreachable behind an earlier `exit 0`.
|
|
243
|
+
* FIX: on skip, read the existing hook. If it does not invoke the CE CLI, say which gates are
|
|
244
|
+
* therefore unenforced and print the one line that wires them in. Silence here reads as
|
|
245
|
+
* success.
|
|
246
|
+
*/
|
|
247
|
+
function existingHookInvokesCE(path) {
|
|
248
|
+
try {
|
|
249
|
+
const body = readFileSync(path, "utf-8");
|
|
250
|
+
return /\b(contextengine|opscontext)\b/.test(body);
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
// Unreadable is not proof of absence; say nothing rather than claim a verdict.
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function warnSkippedHook(path, slot) {
|
|
258
|
+
if (existingHookInvokesCE(path))
|
|
259
|
+
return;
|
|
260
|
+
const gates = {
|
|
261
|
+
"pre-commit": "secret-scan, doc-coverage, rule-parity",
|
|
262
|
+
"commit-msg": "commit-message-required",
|
|
263
|
+
"post-commit": "audit trail of the push",
|
|
264
|
+
};
|
|
265
|
+
const wire = {
|
|
266
|
+
"pre-commit": 'contextengine hook secret-scan && contextengine hook doc-coverage && contextengine hook rule-parity',
|
|
267
|
+
"commit-msg": 'contextengine hook commit-message-required "$1"',
|
|
268
|
+
"post-commit": "contextengine end-session",
|
|
269
|
+
};
|
|
270
|
+
console.log(` โ ๏ธ that hook never calls ContextEngine, so these enforce NOTHING here:`);
|
|
271
|
+
console.log(` ${gates[slot]}`);
|
|
272
|
+
console.log(` Wire them by adding this line to ${path}:`);
|
|
273
|
+
console.log(` ${wire[slot]}`);
|
|
274
|
+
}
|
|
229
275
|
function generatePreCommitHook() {
|
|
230
276
|
const lines = [];
|
|
231
277
|
lines.push("#!/bin/zsh");
|
|
@@ -508,7 +554,8 @@ async function runInit() {
|
|
|
508
554
|
const postCommitDest = join(hooksDir, "post-commit");
|
|
509
555
|
const commitMsgDest = join(hooksDir, "commit-msg");
|
|
510
556
|
if (existsSync(preCommitDest)) {
|
|
511
|
-
console.log(" โญ .git/hooks/pre-commit already exists โ skipping");
|
|
557
|
+
console.log(" โญ .git/hooks/pre-commit already exists โ skipping (never overwritten)");
|
|
558
|
+
warnSkippedHook(preCommitDest, "pre-commit");
|
|
512
559
|
skipped++;
|
|
513
560
|
}
|
|
514
561
|
else {
|
|
@@ -523,7 +570,8 @@ async function runInit() {
|
|
|
523
570
|
// [COMMIT-MSG-HOOK-MUST-BE-INSTALLED] โ without this, every
|
|
524
571
|
// commit_message_required rule is silently unenforced.
|
|
525
572
|
if (existsSync(commitMsgDest)) {
|
|
526
|
-
console.log(" โญ .git/hooks/commit-msg already exists โ skipping");
|
|
573
|
+
console.log(" โญ .git/hooks/commit-msg already exists โ skipping (never overwritten)");
|
|
574
|
+
warnSkippedHook(commitMsgDest, "commit-msg");
|
|
527
575
|
skipped++;
|
|
528
576
|
}
|
|
529
577
|
else {
|
|
@@ -536,7 +584,8 @@ async function runInit() {
|
|
|
536
584
|
}
|
|
537
585
|
}
|
|
538
586
|
if (existsSync(postCommitDest)) {
|
|
539
|
-
console.log(" โญ .git/hooks/post-commit already exists โ skipping");
|
|
587
|
+
console.log(" โญ .git/hooks/post-commit already exists โ skipping (never overwritten)");
|
|
588
|
+
warnSkippedHook(postCommitDest, "post-commit");
|
|
540
589
|
skipped++;
|
|
541
590
|
}
|
|
542
591
|
else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@compr/opscontext-mcp",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.3",
|
|
4
4
|
"description": "OpsContext for AI Agents โ read-only fleet visibility (PM2/nginx/Docker/git/cron) + tamper-evident audit log + policy-as-code hooks. The ops + compliance layer Claude Code can't grow natively.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|