@theglitchking/gimme-the-lint 2.4.0 → 2.5.1
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 +35 -0
- package/README.md +4 -1
- package/bin/gimme-the-lint.js +13 -5
- package/lib/adapters/adapter.js +32 -0
- package/lib/adapters/tflint.js +24 -8
- package/lib/baseline.js +10 -8
- 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.1"
|
|
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.1",
|
|
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.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TheGlitchKing",
|
|
7
7
|
"email": "theglitchking@users.noreply.github.com"
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,41 @@ 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.1] - 2026-05-17
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **tflint config resolution is now root-aware.** In the standard Terraform
|
|
12
|
+
monorepo — one repo-root `.tflint.hcl`, many nested `modules/*` / `envs/*`
|
|
13
|
+
units — the adapter resolved config only in the unit directory, so every
|
|
14
|
+
unit was linted with tflint defaults: the repo's preset, plugin declarations
|
|
15
|
+
and `rule { enabled = false }` overrides were silently ignored and
|
|
16
|
+
`tflint --init` never ran. Meanwhile `configHashFor()` *did* find the
|
|
17
|
+
repo-root config, so the baseline's `config_hash` reflected a config the
|
|
18
|
+
linter never actually used — a silent correctness bug. A new shared resolver,
|
|
19
|
+
`LinterAdapter.resolveConfigPath()`, walks up from the unit directory to the
|
|
20
|
+
project root; `buildCommand()` and `initCommand()` now pass the resolved
|
|
21
|
+
file as an absolute `--config`, and `configHashFor()` hashes that same file —
|
|
22
|
+
the hashed config and the linted config can no longer disagree. A unit with
|
|
23
|
+
its own `.tflint.hcl` still wins (nearest-first); a repo with no config
|
|
24
|
+
anywhere still runs the zero-config core ruleset. The resolver is generic
|
|
25
|
+
(no provider name in code) and root-aware config-hashing now benefits every
|
|
26
|
+
adapter.
|
|
27
|
+
|
|
28
|
+
## [2.5.0] - 2026-05-17
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **`.gtl/config.js` — consolidated config location.** gimme-the-lint's own
|
|
32
|
+
config file now lives canonically at `.gtl/config.js` (`.gtl/config.cjs` for
|
|
33
|
+
ESM projects), so it travels with the committed `.gtl/` baselines rather than
|
|
34
|
+
sitting loose at the repo root. `install` and `migrate` write new configs
|
|
35
|
+
there; `config-manager.findConfig()` resolves the location. A repo-root
|
|
36
|
+
`gimme-the-lint.config.js` is still read as a fallback — existing projects
|
|
37
|
+
need no change — and `.gtl/` wins when both exist. `uninstall` removes a
|
|
38
|
+
repo-root config but leaves a `.gtl/` one in place (it is part of the
|
|
39
|
+
preserved `.gtl/` directory). Linter configs (`eslint.config.js`,
|
|
40
|
+
`.tflint.hcl`, …) are unaffected: each linter resolves its own config from a
|
|
41
|
+
fixed location gimme-the-lint does not own.
|
|
42
|
+
|
|
8
43
|
## [2.4.0] - 2026-05-17
|
|
9
44
|
|
|
10
45
|
### 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/adapters/adapter.js
CHANGED
|
@@ -65,6 +65,38 @@ class LinterAdapter {
|
|
|
65
65
|
return [];
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Resolve the EFFECTIVE config file for the unit being linted: walk up from
|
|
70
|
+
* `startDir` (default: appRoot) to projectRoot inclusive and return the
|
|
71
|
+
* absolute path of the nearest file named by configFiles(), or null if none
|
|
72
|
+
* exists anywhere on that path.
|
|
73
|
+
*
|
|
74
|
+
* Root-aware — this is what lets a single repo-root config (the standard
|
|
75
|
+
* monorepo layout: one config, many nested units) govern every unit. It is
|
|
76
|
+
* the SINGLE source of truth shared by the config-hash (baseline.js) and the
|
|
77
|
+
* linter invocation, so the hashed config and the linted config can never
|
|
78
|
+
* disagree.
|
|
79
|
+
* @param {string} [startDir]
|
|
80
|
+
* @returns {string|null}
|
|
81
|
+
*/
|
|
82
|
+
resolveConfigPath(startDir) {
|
|
83
|
+
const names = this.configFiles();
|
|
84
|
+
if (!names || names.length === 0) return null;
|
|
85
|
+
const root = path.resolve(this.projectRoot);
|
|
86
|
+
let dir = path.resolve(startDir || this.appRoot);
|
|
87
|
+
while (true) {
|
|
88
|
+
for (const name of names) {
|
|
89
|
+
const candidate = path.join(dir, name);
|
|
90
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
91
|
+
}
|
|
92
|
+
if (dir === root) break; // checked projectRoot — stop
|
|
93
|
+
const parent = path.dirname(dir);
|
|
94
|
+
if (parent === dir) break; // filesystem root reached
|
|
95
|
+
dir = parent;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
68
100
|
/** Return the first candidate path that exists, else the last candidate. */
|
|
69
101
|
resolveBinary(candidates) {
|
|
70
102
|
for (const candidate of candidates) {
|
package/lib/adapters/tflint.js
CHANGED
|
@@ -66,16 +66,22 @@ class TflintAdapter extends LinterAdapter {
|
|
|
66
66
|
|
|
67
67
|
// --- .tflint.hcl introspection (generic — no provider is special-cased) ---
|
|
68
68
|
|
|
69
|
-
/** True when the unit
|
|
69
|
+
/** True when an effective .tflint.hcl exists (the unit dir or up to root). */
|
|
70
70
|
_hasConfig(dir) {
|
|
71
|
-
return
|
|
71
|
+
return this.resolveConfigPath(dir) !== null;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Enumerate every `plugin "<name>"` block in the EFFECTIVE .tflint.hcl —
|
|
76
|
+
* the one resolveConfigPath() resolves, which may live up at the repo root,
|
|
77
|
+
* not in the unit dir.
|
|
78
|
+
*/
|
|
75
79
|
_declaredPlugins(dir) {
|
|
80
|
+
const configPath = this.resolveConfigPath(dir);
|
|
81
|
+
if (!configPath) return [];
|
|
76
82
|
let hcl;
|
|
77
83
|
try {
|
|
78
|
-
hcl = fs.readFileSync(
|
|
84
|
+
hcl = fs.readFileSync(configPath, 'utf8');
|
|
79
85
|
} catch {
|
|
80
86
|
return [];
|
|
81
87
|
}
|
|
@@ -105,10 +111,12 @@ class TflintAdapter extends LinterAdapter {
|
|
|
105
111
|
* base adapter). A repo with no .tflint.hcl gets core linting, no init.
|
|
106
112
|
*/
|
|
107
113
|
initCommand(cwd) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
const configPath = this.resolveConfigPath(cwd);
|
|
115
|
+
if (!configPath) return null;
|
|
116
|
+
// Pass the resolved config explicitly so `--init` reads the right
|
|
117
|
+
// .tflint.hcl for its plugin declarations — even when it lives up at the
|
|
118
|
+
// repo root rather than in the unit dir.
|
|
119
|
+
return { cmd: this.binary, args: ['--init', `--config=${configPath}`] };
|
|
112
120
|
}
|
|
113
121
|
|
|
114
122
|
// --- availability: agree with what lint() will actually see --------------
|
|
@@ -178,6 +186,14 @@ class TflintAdapter extends LinterAdapter {
|
|
|
178
186
|
// Unresolvable target — fall back to the default cwd.
|
|
179
187
|
}
|
|
180
188
|
}
|
|
189
|
+
|
|
190
|
+
// tflint runs IN the unit dir; pass the effective config — which may live
|
|
191
|
+
// up at the repo root — as an absolute --config so the unit is linted with
|
|
192
|
+
// the repo's preset / plugin declarations / rule overrides, not tflint
|
|
193
|
+
// defaults. No config anywhere → plain tflint (zero-config core ruleset).
|
|
194
|
+
const configPath = this.resolveConfigPath(cwd);
|
|
195
|
+
if (configPath) args.push(`--config=${configPath}`);
|
|
196
|
+
|
|
181
197
|
return { cmd: this.binary, args, cwd };
|
|
182
198
|
}
|
|
183
199
|
|
package/lib/baseline.js
CHANGED
|
@@ -18,15 +18,17 @@ const gtlManifest = require('./gtl-manifest');
|
|
|
18
18
|
// the baseline CLI, the hooks installer) can refuse to gate commits against a
|
|
19
19
|
// baseline that never actually captured a linter.
|
|
20
20
|
|
|
21
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Hash the EFFECTIVE config file for an adapter. Resolution walks up from the
|
|
23
|
+
* unit dir to the project root via the adapter's shared resolver, so the
|
|
24
|
+
* hashed config is exactly the one the linter is invoked with — a repo-root
|
|
25
|
+
* config governing nested units is hashed correctly, never missed or faked.
|
|
26
|
+
*/
|
|
27
|
+
// eslint-disable-next-line no-unused-vars
|
|
22
28
|
async function configHashFor(projectRoot, unitRoot, adapter) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (hash !== 'unknown') return hash;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return 'unknown';
|
|
29
|
+
const configPath = adapter.resolveConfigPath(unitRoot);
|
|
30
|
+
if (!configPath) return 'unknown';
|
|
31
|
+
return manifestManager.hashFile(configPath);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
/** Baseline a single unit across all its bound linters. */
|
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.1",
|
|
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",
|