coderifts 3.2.0 → 3.3.0
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 +188 -2
- package/bin/coderifts.js +34 -4
- package/dist/cli.js +3864 -470
- package/package.json +4 -3
- package/scripts/assert-guard-major.js +125 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coderifts",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Detect breaking API changes from the command line. Works locally or with the CodeRifts cloud API.",
|
|
5
5
|
"author": "CodeRifts <hello@coderifts.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,12 +38,13 @@
|
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "node scripts/copy-corpus.js && esbuild bin/coderifts.js --bundle --platform=node --target=node18 --outfile=dist/cli.js",
|
|
41
|
-
"prepublishOnly": "bash ../../scripts/freeze-gate.sh && npm run build",
|
|
41
|
+
"prepublishOnly": "node scripts/assert-guard-major.js && bash ../../scripts/freeze-gate.sh && npm run build",
|
|
42
|
+
"assert-guard-major": "node scripts/assert-guard-major.js",
|
|
42
43
|
"postinstall": "node scripts/postinstall.js",
|
|
43
44
|
"test": "node --test test/*.test.js"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"@coderifts/agent-guard": "^
|
|
47
|
+
"@coderifts/agent-guard": "^6.4.0",
|
|
47
48
|
"chalk": "^4.1.2",
|
|
48
49
|
"cli-table3": "^0.6.4",
|
|
49
50
|
"commander": "^12.0.0",
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* CLI release gate (prepublishOnly): refuse to publish if the declared
|
|
6
|
+
* @coderifts/agent-guard range floors below the minimum acceptable major.
|
|
7
|
+
*
|
|
8
|
+
* Honest scope: compares the dependency *range floor* (e.g. ^6.4.0 → 6) to a
|
|
9
|
+
* pinned constant. Does not call npm registry. Optional: if node_modules has a
|
|
10
|
+
* resolved package, also fail when its major is below the floor (stale install).
|
|
11
|
+
*
|
|
12
|
+
* Why: evening audit 2.4 — CLI sat on ^1.6.0 while published guard is 6.x.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
/** Minimum acceptable major for @coderifts/agent-guard (published line). */
|
|
19
|
+
const MIN_GUARD_MAJOR = 6;
|
|
20
|
+
const DEP = '@coderifts/agent-guard';
|
|
21
|
+
|
|
22
|
+
function fail(msg) {
|
|
23
|
+
console.error(`assert-guard-major: FAIL — ${msg}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function ok(msg) {
|
|
28
|
+
console.log(`assert-guard-major: OK — ${msg}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Floor major from a semver range used in package.json dependencies.
|
|
33
|
+
* Supports: ^6.4.0, ~6.4.0, >=6.4.0, 6.4.0, 6.x, 6.*
|
|
34
|
+
* Rejects: * , latest, empty, multi-range with lower floor below MIN (takes first number).
|
|
35
|
+
*/
|
|
36
|
+
function floorMajorFromRange(range) {
|
|
37
|
+
if (typeof range !== 'string' || !range.trim()) return null;
|
|
38
|
+
const s = range.trim();
|
|
39
|
+
if (s === '*' || s === 'x' || s === 'latest' || s.startsWith('file:') || s.startsWith('workspace:')) {
|
|
40
|
+
return null; // wildcards / non-semver — treat as unacceptable for publish
|
|
41
|
+
}
|
|
42
|
+
// First MAJOR digit group after optional ^ ~ >= > =
|
|
43
|
+
const m = s.match(/(?:^|[\s^~>=<])(\d+)(?:\.\d+|\.x|\.\*)?/);
|
|
44
|
+
if (!m) return null;
|
|
45
|
+
return parseInt(m[1], 10);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function main() {
|
|
49
|
+
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
50
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
51
|
+
const range = pkg.dependencies && pkg.dependencies[DEP];
|
|
52
|
+
if (!range) fail(`${DEP} missing from dependencies`);
|
|
53
|
+
|
|
54
|
+
const floor = floorMajorFromRange(range);
|
|
55
|
+
if (floor == null) {
|
|
56
|
+
fail(
|
|
57
|
+
`${DEP} range ${JSON.stringify(range)} has no parseable major floor `
|
|
58
|
+
+ `(wildcards/non-semver not allowed; need e.g. ^${MIN_GUARD_MAJOR}.0.0)`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
if (floor < MIN_GUARD_MAJOR) {
|
|
62
|
+
fail(
|
|
63
|
+
`${DEP} range ${JSON.stringify(range)} floors at major ${floor}; `
|
|
64
|
+
+ `minimum acceptable major is ${MIN_GUARD_MAJOR}`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Optional: resolved install must not lag the declared floor (stale node_modules).
|
|
69
|
+
try {
|
|
70
|
+
const resolved = require(path.join(
|
|
71
|
+
path.dirname(require.resolve(`${DEP}`)),
|
|
72
|
+
// package root: require('@coderifts/agent-guard') → dist/cjs/index.js
|
|
73
|
+
'..',
|
|
74
|
+
'..',
|
|
75
|
+
'package.json',
|
|
76
|
+
));
|
|
77
|
+
// From dist/cjs → package root is ../..
|
|
78
|
+
} catch (_) {
|
|
79
|
+
// try alternate resolve
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let resolvedVersion = null;
|
|
83
|
+
try {
|
|
84
|
+
// Walk up from the main entry to package.json (exports block ./package.json).
|
|
85
|
+
let dir = path.dirname(require.resolve(DEP));
|
|
86
|
+
for (let i = 0; i < 6; i++) {
|
|
87
|
+
const cand = path.join(dir, 'package.json');
|
|
88
|
+
if (fs.existsSync(cand)) {
|
|
89
|
+
const rp = JSON.parse(fs.readFileSync(cand, 'utf8'));
|
|
90
|
+
if (rp.name === DEP) {
|
|
91
|
+
resolvedVersion = rp.version;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const parent = path.dirname(dir);
|
|
96
|
+
if (parent === dir) break;
|
|
97
|
+
dir = parent;
|
|
98
|
+
}
|
|
99
|
+
} catch (err) {
|
|
100
|
+
// Not installed — range check alone is enough for prepublish if install follows.
|
|
101
|
+
ok(`declared ${DEP}@${range} (floor major ${floor} ≥ ${MIN_GUARD_MAJOR}); package not resolved in tree (${err && err.message})`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (resolvedVersion) {
|
|
106
|
+
const rm = /^(\d+)/.exec(resolvedVersion);
|
|
107
|
+
const rMajor = rm ? parseInt(rm[1], 10) : null;
|
|
108
|
+
if (rMajor == null || rMajor < MIN_GUARD_MAJOR) {
|
|
109
|
+
fail(
|
|
110
|
+
`resolved ${DEP}@${resolvedVersion} major ${rMajor} is below minimum ${MIN_GUARD_MAJOR}`,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
if (rMajor < floor) {
|
|
114
|
+
fail(
|
|
115
|
+
`resolved ${DEP}@${resolvedVersion} major ${rMajor} is below declared range floor ${floor}`,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
ok(`declared ${DEP}@${range} (floor ${floor}); resolved ${resolvedVersion} (major ≥ ${MIN_GUARD_MAJOR})`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
ok(`declared ${DEP}@${range} (floor major ${floor} ≥ ${MIN_GUARD_MAJOR})`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
main();
|