@theglitchking/gimme-the-lint 2.4.0 → 2.5.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +15 -0
- package/README.md +4 -1
- package/bin/gimme-the-lint.js +13 -5
- package/lib/config-manager.js +62 -37
- package/lib/installer.js +5 -1
- package/package.json +1 -1
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Official marketplace for gimme-the-lint - polyglot progressive linting with per-app baselines and drift detection",
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.5.0"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "gimme-the-lint",
|
|
14
14
|
"description": "Polyglot progressive linting for monorepos — adapter-driven baselines, per-app drift detection, and idempotent skips across JavaScript/TypeScript, Python, Go, Rust, Terraform, and Ansible.",
|
|
15
|
-
"version": "2.
|
|
15
|
+
"version": "2.5.0",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "TheGlitchKing"
|
|
18
18
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gimme-the-lint",
|
|
3
3
|
"description": "Polyglot progressive linting for monorepos — adapter-driven baselines, per-app drift detection, and idempotent skips across JavaScript/TypeScript, Python, Go, Rust, Terraform, and Ansible.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.5.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TheGlitchKing",
|
|
7
7
|
"email": "theglitchking@users.noreply.github.com"
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.5.0] - 2026-05-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **`.gtl/config.js` — consolidated config location.** gimme-the-lint's own
|
|
12
|
+
config file now lives canonically at `.gtl/config.js` (`.gtl/config.cjs` for
|
|
13
|
+
ESM projects), so it travels with the committed `.gtl/` baselines rather than
|
|
14
|
+
sitting loose at the repo root. `install` and `migrate` write new configs
|
|
15
|
+
there; `config-manager.findConfig()` resolves the location. A repo-root
|
|
16
|
+
`gimme-the-lint.config.js` is still read as a fallback — existing projects
|
|
17
|
+
need no change — and `.gtl/` wins when both exist. `uninstall` removes a
|
|
18
|
+
repo-root config but leaves a `.gtl/` one in place (it is part of the
|
|
19
|
+
preserved `.gtl/` directory). Linter configs (`eslint.config.js`,
|
|
20
|
+
`.tflint.hcl`, …) are unaffected: each linter resolves its own config from a
|
|
21
|
+
fixed location gimme-the-lint does not own.
|
|
22
|
+
|
|
8
23
|
## [2.4.0] - 2026-05-17
|
|
9
24
|
|
|
10
25
|
### Fixed
|
package/README.md
CHANGED
|
@@ -173,7 +173,10 @@ git add -A && git commit -m "…" # retry
|
|
|
173
173
|
## Configuration
|
|
174
174
|
|
|
175
175
|
Zero config is the default — apps and their linters are auto-detected. To
|
|
176
|
-
override, add
|
|
176
|
+
override, add a config file. The canonical location is **`.gtl/config.js`**
|
|
177
|
+
(it travels with the committed `.gtl/` baselines); a repo-root
|
|
178
|
+
`gimme-the-lint.config.js` is also read, for back-compatibility. `install` and
|
|
179
|
+
`migrate` write new configs to `.gtl/`:
|
|
177
180
|
|
|
178
181
|
```js
|
|
179
182
|
module.exports = {
|
package/bin/gimme-the-lint.js
CHANGED
|
@@ -86,6 +86,7 @@ program
|
|
|
86
86
|
.action(async () => {
|
|
87
87
|
const chalk = require('chalk');
|
|
88
88
|
const gitHooksManager = require('../lib/git-hooks-manager');
|
|
89
|
+
const configManager = require('../lib/config-manager');
|
|
89
90
|
|
|
90
91
|
console.log(chalk.blue('\ngimme-the-lint: Uninstalling...\n'));
|
|
91
92
|
|
|
@@ -94,10 +95,17 @@ program
|
|
|
94
95
|
console.log(chalk.green(` ✓ Removed git hooks: ${removed.join(', ')}`));
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
// Remove a repo-root config. A config under .gtl/ is left in place — it is
|
|
99
|
+
// part of the .gtl/ directory, which uninstall preserves.
|
|
100
|
+
const cfgPath = configManager.findConfig(process.cwd());
|
|
101
|
+
if (cfgPath) {
|
|
102
|
+
const rel = path.relative(process.cwd(), cfgPath);
|
|
103
|
+
if (rel.startsWith(`.gtl${path.sep}`)) {
|
|
104
|
+
console.log(chalk.dim(` · Config kept (${rel} — part of .gtl/)`));
|
|
105
|
+
} else {
|
|
106
|
+
fs.unlinkSync(cfgPath);
|
|
107
|
+
console.log(chalk.green(` ✓ Removed ${path.basename(cfgPath)}`));
|
|
108
|
+
}
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
console.log(chalk.green('\n✓ Uninstall complete.\n'));
|
|
@@ -372,7 +380,7 @@ program
|
|
|
372
380
|
const projectType = await configManager.detectProjectType(projectRoot);
|
|
373
381
|
const venvStatus = venvManager.getStatus(projectRoot);
|
|
374
382
|
const hookStatus = await gitHooksManager.getStatus(projectRoot);
|
|
375
|
-
const configExists =
|
|
383
|
+
const configExists = Boolean(configManager.findConfig(projectRoot));
|
|
376
384
|
|
|
377
385
|
console.log(chalk.blue('\ngimme-the-lint Status\n'));
|
|
378
386
|
console.log(` Project type: ${projectType}`);
|
package/lib/config-manager.js
CHANGED
|
@@ -38,9 +38,49 @@ async function detectProjectType(projectRoot) {
|
|
|
38
38
|
return 'unknown';
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// Config-file lookup order. The .gtl/ location is canonical — the config
|
|
42
|
+
// travels with the committed .gtl/ baselines and keeps gimme-the-lint's own
|
|
43
|
+
// files in one place. The repo-root location is retained as a fallback so
|
|
44
|
+
// projects created before this layout keep working with no change.
|
|
45
|
+
const CONFIG_CANDIDATES = [
|
|
46
|
+
['.gtl', 'config.cjs'],
|
|
47
|
+
['.gtl', 'config.js'],
|
|
48
|
+
['gimme-the-lint.config.cjs'],
|
|
49
|
+
['gimme-the-lint.config.js'],
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
/** Absolute path of the project's gimme-the-lint config, or null if none. */
|
|
53
|
+
function findConfig(projectRoot) {
|
|
54
|
+
for (const parts of CONFIG_CANDIDATES) {
|
|
55
|
+
const candidate = path.join(projectRoot, ...parts);
|
|
56
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Is the target project ESM ("type": "module" in package.json)? */
|
|
62
|
+
async function isESMProject(projectRoot) {
|
|
63
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
64
|
+
if (await fs.pathExists(pkgPath)) {
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(await fs.readFile(pkgPath, 'utf8')).type === 'module';
|
|
67
|
+
} catch {
|
|
68
|
+
/* unreadable package.json — treat as CommonJS */
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Where a NEW config is written — the canonical .gtl/ location. ESM projects
|
|
76
|
+
* get a .cjs extension so `require()` of the CommonJS config still works.
|
|
77
|
+
*/
|
|
78
|
+
async function newConfigPath(projectRoot) {
|
|
79
|
+
const esm = await isESMProject(projectRoot);
|
|
80
|
+
return path.join(projectRoot, '.gtl', esm ? 'config.cjs' : 'config.js');
|
|
81
|
+
}
|
|
82
|
+
|
|
41
83
|
function getConfig(projectRoot) {
|
|
42
|
-
const cjsPath = path.join(projectRoot, 'gimme-the-lint.config.cjs');
|
|
43
|
-
const jsPath = path.join(projectRoot, 'gimme-the-lint.config.js');
|
|
44
84
|
const defaults = {
|
|
45
85
|
frontendDir: 'frontend',
|
|
46
86
|
backendDir: 'backend',
|
|
@@ -52,7 +92,7 @@ function getConfig(projectRoot) {
|
|
|
52
92
|
testExcludedBackend: ['tests', '*test*', '__pycache__'],
|
|
53
93
|
};
|
|
54
94
|
|
|
55
|
-
const configPath =
|
|
95
|
+
const configPath = findConfig(projectRoot);
|
|
56
96
|
if (configPath) {
|
|
57
97
|
try {
|
|
58
98
|
const userConfig = require(configPath);
|
|
@@ -66,26 +106,19 @@ function getConfig(projectRoot) {
|
|
|
66
106
|
}
|
|
67
107
|
|
|
68
108
|
async function initConfig(projectRoot, options = {}) {
|
|
69
|
-
const
|
|
70
|
-
const jsPath = path.join(projectRoot, 'gimme-the-lint.config.js');
|
|
109
|
+
const existing = findConfig(projectRoot);
|
|
71
110
|
|
|
72
|
-
// Don't overwrite
|
|
73
|
-
if (!options.force &&
|
|
74
|
-
const existing = await fs.pathExists(cjsPath) ? cjsPath : jsPath;
|
|
111
|
+
// Don't overwrite an existing config (wherever it lives).
|
|
112
|
+
if (!options.force && existing) {
|
|
75
113
|
return { created: false, path: existing };
|
|
76
114
|
}
|
|
77
115
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
|
|
84
|
-
isESM = pkg.type === 'module';
|
|
85
|
-
} catch {}
|
|
86
|
-
}
|
|
116
|
+
// New config → the canonical .gtl/ location. --force overwrites in place,
|
|
117
|
+
// so a legacy repo-root config is never silently shadowed by a .gtl/ one.
|
|
118
|
+
const configPath = existing && options.force
|
|
119
|
+
? existing
|
|
120
|
+
: await newConfigPath(projectRoot);
|
|
87
121
|
|
|
88
|
-
const configPath = isESM ? cjsPath : jsPath;
|
|
89
122
|
const projectType = await detectProjectType(projectRoot);
|
|
90
123
|
const config = {
|
|
91
124
|
projectType,
|
|
@@ -100,36 +133,26 @@ async function initConfig(projectRoot, options = {}) {
|
|
|
100
133
|
module.exports = ${JSON.stringify(config, null, 2)};
|
|
101
134
|
`;
|
|
102
135
|
|
|
136
|
+
await fs.ensureDir(path.dirname(configPath));
|
|
103
137
|
await fs.writeFile(configPath, content, 'utf8');
|
|
104
138
|
return { created: true, path: configPath, projectType };
|
|
105
139
|
}
|
|
106
140
|
|
|
107
141
|
/**
|
|
108
|
-
* Write an explicit `apps` map into gimme-the-lint
|
|
109
|
-
* app/linter layout is visible and editable instead of silently
|
|
110
|
-
* every run. Never overwrites an existing config
|
|
142
|
+
* Write an explicit `apps` map into the gimme-the-lint config so the
|
|
143
|
+
* discovered app/linter layout is visible and editable instead of silently
|
|
144
|
+
* re-guessed on every run. Never overwrites an existing config; a new one is
|
|
145
|
+
* written to the canonical .gtl/ location.
|
|
111
146
|
* @param {string} projectRoot
|
|
112
147
|
* @param {{appPath: string, linters: string[]}[]} apps
|
|
113
148
|
*/
|
|
114
149
|
async function writeAppsConfig(projectRoot, apps) {
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return {
|
|
119
|
-
created: false,
|
|
120
|
-
path: (await fs.pathExists(cjsPath)) ? cjsPath : jsPath,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
let isESM = false;
|
|
125
|
-
const pkgPath = path.join(projectRoot, 'package.json');
|
|
126
|
-
if (await fs.pathExists(pkgPath)) {
|
|
127
|
-
try {
|
|
128
|
-
isESM = JSON.parse(await fs.readFile(pkgPath, 'utf8')).type === 'module';
|
|
129
|
-
} catch {}
|
|
150
|
+
const existing = findConfig(projectRoot);
|
|
151
|
+
if (existing) {
|
|
152
|
+
return { created: false, path: existing };
|
|
130
153
|
}
|
|
131
|
-
const configPath = isESM ? cjsPath : jsPath;
|
|
132
154
|
|
|
155
|
+
const configPath = await newConfigPath(projectRoot);
|
|
133
156
|
const appsObj = {};
|
|
134
157
|
for (const app of apps || []) {
|
|
135
158
|
appsObj[app.appPath] = { linters: app.linters };
|
|
@@ -139,6 +162,7 @@ async function writeAppsConfig(projectRoot, apps) {
|
|
|
139
162
|
// Edit this map to correct any mis-discovered apps or linters.
|
|
140
163
|
module.exports = ${JSON.stringify({ apps: appsObj }, null, 2)};
|
|
141
164
|
`;
|
|
165
|
+
await fs.ensureDir(path.dirname(configPath));
|
|
142
166
|
await fs.writeFile(configPath, content, 'utf8');
|
|
143
167
|
return { created: true, path: configPath, apps: appsObj };
|
|
144
168
|
}
|
|
@@ -146,6 +170,7 @@ module.exports = ${JSON.stringify({ apps: appsObj }, null, 2)};
|
|
|
146
170
|
module.exports = {
|
|
147
171
|
copyTemplate,
|
|
148
172
|
detectProjectType,
|
|
173
|
+
findConfig,
|
|
149
174
|
getConfig,
|
|
150
175
|
initConfig,
|
|
151
176
|
writeAppsConfig,
|
package/lib/installer.js
CHANGED
|
@@ -33,7 +33,11 @@ async function init(projectRoot, options = {}) {
|
|
|
33
33
|
frontendDir: options.frontendDir,
|
|
34
34
|
backendDir: options.backendDir,
|
|
35
35
|
});
|
|
36
|
-
results.steps.push(
|
|
36
|
+
results.steps.push(
|
|
37
|
+
configResult.created
|
|
38
|
+
? `Created ${path.relative(projectRoot, configResult.path)}`
|
|
39
|
+
: `Config already exists (${path.relative(projectRoot, configResult.path)})`
|
|
40
|
+
);
|
|
37
41
|
|
|
38
42
|
// Step 3: Copy ESLint template (frontend)
|
|
39
43
|
if (enableFrontend) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theglitchking/gimme-the-lint",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "Polyglot progressive linting for monorepos — adapter-driven baselines, per-app drift detection, and idempotent skips across JavaScript/TypeScript, Python, Go, Rust, Terraform, and Ansible.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"linting",
|