ai-quality-gate 0.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ ## [0.0.1] - 2026-03-27
6
+
7
+ ### Added
8
+
9
+ - **MCP:** `quality_fix` tool — Phase 1 (TypeScript, embedded ESLint + SonarJS, AST fixers, Prettier, JSON validator with optional i18n locale checks) and optional Phase 2 (SonarQube).
10
+ - **CLI:** `--setup` wizard, `--check`, `--fix`, phase flags; config via `.quality-gate.yaml` / `.quality-gate.json` (discovery + `QUALITY_GATE_CONFIG`).
11
+ - **Config:** `fixers` toggles, optional `customRules` (regex per line), Sonar env / nested `sonar` block; Zod-validated merge with environment variables.
12
+ - **Project root:** when `PROJECT_ROOT` is unset, infer by walking up from `process.cwd()` for `package.json` or `tsconfig.json` (`findProjectRoot`); `PROJECT_ROOT` remains an optional override.
13
+ - **Docs:** README MCP section (npx, global binary, Sonar, env reference); `.cursor/mcp.json.example` with commented env catalog; troubleshooting for missing `quality_fix`.
14
+ - **Tests & tooling:** Vitest coverage, contract/integration tests for ESLint embedding and validators.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mustafa Cagri Guven (https://github.com/mustafacagri)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,517 @@
1
+ # AI Quality Gate
2
+
3
+ MCP Server for AI code quality automation.
4
+
5
+ [![npm version](https://badge.fury.io/js/ai-quality-gate.svg)](https://www.npmjs.com/package/ai-quality-gate)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ---
9
+
10
+ ## What It Does
11
+
12
+ AI writes code → calls `quality_fix` → Server fixes what it can → Reports remaining issues to AI.
13
+
14
+ **Hybrid Approach:**
15
+
16
+ - **Phase 1:** ESLint + 627 rules + Prettier (~2-8s, always runs)
17
+ - **Phase 2:** SonarQube Server (~30-60s, optional)
18
+
19
+ **Important: ESLint vs Prettier**
20
+
21
+ | Tool | Source | Config |
22
+ |------|--------|--------|
23
+ | **ESLint** | Project's config (if exists) or MCP's embedded | `.eslintrc.*` / `eslint.config.*` / MCP embedded |
24
+ | **Prettier** | **Project's own** | Project's `prettier.config.mjs` |
25
+
26
+ > ESLint rules are controlled by MCP for consistent quality gates.
27
+ > Prettier uses project's config so formatting matches project preferences.
28
+
29
+ **Phase 1 Rule Coverage:**
30
+
31
+ | Plugin | Rules | Description |
32
+ |--------|-------|-------------|
33
+ | SonarJS | 201 | Security, bugs, code smells |
34
+ | Unicorn | 127 | Modern JS best practices |
35
+ | ESLint Core | 108 | JavaScript fundamentals |
36
+ | TypeScript-ESLint | 99 | TypeScript-specific rules |
37
+ | RegExp | 60 | Regex best practices |
38
+ | Import | 11 | Import/export rules |
39
+ | Promise | 10 | Async/await best practices |
40
+ | Node.js (n) | 9 | Node.js specific rules |
41
+ | Unused Imports | 2 | Auto-remove unused imports |
42
+ | **Total** | **627** | |
43
+
44
+ ---
45
+
46
+ ## Installation
47
+
48
+ ### Prerequisites
49
+
50
+ - **Node.js 18+** on your PATH (`node -v`).
51
+ - **Cursor** (or another MCP-capable editor) with MCP enabled.
52
+
53
+ Project root is **auto-detected** when `PROJECT_ROOT` is omitted: the server walks up from the MCP process working directory until it finds `package.json` or `tsconfig.json`. Set `PROJECT_ROOT` in `env` only to analyze a different tree than the inferred root.
54
+
55
+ ---
56
+
57
+ ### MCP configuration (Cursor)
58
+
59
+ Open **Settings → Tools & MCP → Edit** (user `mcp.json`). Add **one** server block; the examples below match [`.cursor/mcp.json.example`](.cursor/mcp.json.example) (JSONC with comments — if your editor rejects comments, copy the JSON blocks below only).
60
+
61
+ **Server name vs tool name:** The key under `mcpServers` (e.g. `"ai-quality-gate"`) is only the label for that connection in Cursor. The MCP **tool** your agent calls is always `quality_fix` — that name is fixed by this package and is separate from the server key and from `ai-quality-gate`.
62
+
63
+ #### A) Recommended: `npx` (no global install)
64
+
65
+ Always runs the published package; good for teams and CI-like setups.
66
+
67
+ ```json
68
+ {
69
+ "mcpServers": {
70
+ "ai-quality-gate": {
71
+ "command": "npx",
72
+ "args": ["-y", "ai-quality-gate"]
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ #### B) Optional: global `npm` install
79
+
80
+ After `npm i -g ai-quality-gate`, the `ai-quality-gate` binary is on your PATH:
81
+
82
+ ```json
83
+ {
84
+ "mcpServers": {
85
+ "ai-quality-gate": {
86
+ "command": "ai-quality-gate",
87
+ "args": []
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ #### C) SonarQube (Phase 2)
94
+
95
+ Requires a running SonarQube instance, `sonar-scanner` available (see [SonarQube Setup](#optional-sonarqube-server-phase-2)), and all three variables below. Phase 1 still runs first.
96
+
97
+ ```json
98
+ {
99
+ "mcpServers": {
100
+ "ai-quality-gate": {
101
+ "command": "npx",
102
+ "args": ["-y", "ai-quality-gate"],
103
+ "env": {
104
+ "SONAR_HOST_URL": "http://localhost:9000",
105
+ "SONAR_TOKEN": "your_sonar_token",
106
+ "SONAR_PROJECT_KEY": "your_project_key"
107
+ }
108
+ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ #### D) Optional environment variables (any server)
114
+
115
+ Add an `"env"` object when you need overrides. Merge order for config is **defaults → `.quality-gate.yaml` / `.quality-gate.json` → environment variables**.
116
+
117
+ | Variable | When to set |
118
+ | -------- | ----------- |
119
+ | `QUALITY_GATE_CONFIG` | Absolute path to a specific `.quality-gate.yaml` or `.quality-gate.json` (skips walking directories). |
120
+ | `PROJECT_ROOT` | Force project root if auto-detection is wrong for your layout. |
121
+ | `SONAR_HOST_URL` | SonarQube server URL (with Phase 2). |
122
+ | `SONAR_TOKEN` | SonarQube token (with Phase 2). |
123
+ | `SONAR_PROJECT_KEY` | SonarQube project key (with Phase 2). |
124
+ | `SONAR_SCANNER_PATH` | Full path to `sonar-scanner` if not on `PATH`. |
125
+ | `PHASE1_TIMEOUT` | Phase 1 timeout (ms), default `30000`. |
126
+ | `PHASE2_TIMEOUT` | Phase 2 timeout (ms), default `300000`. |
127
+ | `ENABLE_I18N_RULES` | `true` / `false` — stricter JSX literal checks for i18n projects. |
128
+
129
+ ---
130
+
131
+ ### Local development (this repository)
132
+
133
+ To dogfood or contribute:
134
+
135
+ 1. **`yarn build`** — generates `dist/server.js`.
136
+ 2. Point MCP at the built file (absolute paths):
137
+
138
+ ```json
139
+ {
140
+ "mcpServers": {
141
+ "ai-quality-gate-dev": {
142
+ "command": "node",
143
+ "args": ["/ABSOLUTE/PATH/TO/ai-quality-gate/dist/server.js"]
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ 3. Reload MCP. Use `env.PROJECT_ROOT` only if the repo you analyze differs from the inferred root.
150
+
151
+ ---
152
+
153
+ ### 2. Add AI Rule
154
+
155
+ `Settings` → `Rules and Commands` → `Add Rule`:
156
+
157
+ ```
158
+ After every code change, before telling the user "done",
159
+ AI must call the quality_fix MCP tool. This is mandatory.
160
+ ```
161
+
162
+ ### 3. Use It
163
+
164
+ ```
165
+ AI writes code → calls quality_fix → Fixes errors → "Done ✅"
166
+ ```
167
+
168
+ ---
169
+
170
+ ## CLI: interactive config (`--setup`)
171
+
172
+ The **interactive wizard** creates or updates `.quality-gate.yaml` without hand-editing: it walks you through project root, optional SonarQube (host URL + project key; **token is not saved to disk** — use `SONAR_TOKEN` in your environment), which Phase 1 tools to enable (ESLint, curly-brace / arrow AST fixers, Prettier, JSON validator), timeouts, and i18n rules. The generated file includes a `fixers:` block you can adjust later.
173
+
174
+ After `yarn build` (or install from npm), run from the target project (or any path under it):
175
+
176
+ ```bash
177
+ node dist/server.js --setup
178
+ ```
179
+
180
+ `PROJECT_ROOT` is inferred when unset (see [MCP configuration](#mcp-configuration-cursor)). Use the same entrypoint as the MCP server (`node dist/server.js` or `npx ai-quality-gate`); only the `--setup` flag switches to wizard mode. Answer prompts in the terminal; on success you get a ready-to-use config next to your project root.
181
+
182
+ **Other CLI modes:** `--check` (read-only Phase 1), `--fix` (default behavior when using CLI quality run), `--phase1-only`, `--phase2-only` — see [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md).
183
+
184
+ ---
185
+
186
+ ## Optional: SonarQube Server (Phase 2)
187
+
188
+ Configure Sonar env in MCP as in **[C) SonarQube (Phase 2)](#c-sonarqube-phase-2)** above, or copy from [`.cursor/mcp.json.example`](.cursor/mcp.json.example). You need **`sonar-scanner`** on your machine for analysis (see below).
189
+
190
+ ### SonarQube Setup
191
+
192
+ #### Docker (Recommended)
193
+
194
+ ```bash
195
+ # Start SonarQube
196
+ docker run -d --name sonarqube -p 9000:9000 sonarqube:community
197
+
198
+ # First login: admin/admin → change password
199
+ # http://localhost:9000
200
+ ```
201
+
202
+ #### Docker Compose
203
+
204
+ ```yaml
205
+ # docker-compose.yml
206
+ version: '3'
207
+ services:
208
+ sonarqube:
209
+ image: sonarqube:community
210
+ ports:
211
+ - '9000:9000'
212
+ volumes:
213
+ - sonarqube_data:/opt/sonarqube/data
214
+ - sonarqube_logs:/opt/sonarqube/logs
215
+ - sonarqube_extensions:/opt/sonarqube/extensions
216
+
217
+ volumes:
218
+ sonarqube_data:
219
+ sonarqube_logs:
220
+ sonarqube_extensions:
221
+ ```
222
+
223
+ ```bash
224
+ docker-compose up -d
225
+ ```
226
+
227
+ ### Creating SonarQube Token
228
+
229
+ 1. http://localhost:9000 → Login (admin)
230
+ 2. **My Account** → **Security** → **Generate Tokens**
231
+ 3. Select token type: **Global Analysis Token**
232
+ 4. Copy token → use as `SONAR_TOKEN`
233
+
234
+ ### Installing sonar-scanner
235
+
236
+ | Platform | Method | Command |
237
+ | ----------- | ------------ | ------------------------------------------ |
238
+ | **Windows** | npm (global) | `npm install -g sonarqube-scanner` |
239
+ | **Windows** | Chocolatey | `choco install sonar-scanner` |
240
+ | **macOS** | npm (global) | `npm install -g sonarqube-scanner` |
241
+ | **macOS** | Homebrew | `brew install sonar-scanner` |
242
+ | **Linux** | npm (global) | `npm install -g sonarqube-scanner` |
243
+ | **Docker** | Container | `docker run sonarsource/sonar-scanner-cli` |
244
+
245
+ For custom path: `SONAR_SCANNER_PATH` env var
246
+
247
+ ---
248
+
249
+ ## Configuration
250
+
251
+ Optional files (discovered by walking up from the inferred project root — same algorithm as `package.json` / `tsconfig.json` — or from `PROJECT_ROOT` when set): **`.quality-gate.yaml`** (preferred) or **`.quality-gate.json`**. Same fields as environment variables (camelCase); you may nest Sonar settings under `sonar: { hostUrl, token, projectKey, scannerPath }`.
252
+
253
+ Merge order: **defaults → config file → environment variables** (ENV wins on conflicts).
254
+
255
+ Set **`QUALITY_GATE_CONFIG`** to an explicit path to skip discovery.
256
+
257
+ ### Custom rules (`customRules`)
258
+
259
+ Optional **line-based regex** checks on lintable files (Phase 1). Each match is reported as an issue with `rule` set to `custom:<id>` (and included in `quality_fix` `remaining`). Example:
260
+
261
+ ```yaml
262
+ customRules:
263
+ - id: no-console
264
+ message: 'Console.log is not allowed'
265
+ pattern: 'console\\.log\\('
266
+ severity: error
267
+ - id: no-debugger
268
+ message: 'Debugger statement found'
269
+ pattern: 'debugger'
270
+ severity: warning
271
+ ```
272
+
273
+ Patterns use JavaScript `RegExp` source (escape backslashes as in YAML strings). Invalid patterns are skipped at runtime with a log line.
274
+
275
+ ### JSON validator & i18n locale files
276
+
277
+ When **`fixers.jsonValidator`** is enabled and you pass JSON paths that match locale patterns (for example `locales/en.json` / `locales/tr.json`), the tool compares keys across those files.
278
+
279
+ - **Syntax errors, invalid UTF-8 BOM, etc.** → reported as `issues` and **fail** Phase 1 / `quality_fix` until fixed.
280
+ - **Missing or extra keys between locale files** → collected as **`i18nIssues`** in the validator result and printed as **warnings on stderr** during Phase 1. They do **not** set `passed: false` and do **not** block the gate.
281
+
282
+ Treat `i18nIssues` as advisory unless you add your own CI check on top.
283
+
284
+ ---
285
+
286
+ ## Environment Variables
287
+
288
+ All variables are **optional** unless you use Phase 2, which requires **`SONAR_HOST_URL`**, **`SONAR_TOKEN`**, and **`SONAR_PROJECT_KEY`** together.
289
+
290
+ | Variable | Description | Example |
291
+ | -------- | ----------- | ------- |
292
+ | `QUALITY_GATE_CONFIG` | Absolute path to a `.quality-gate.yaml` or `.quality-gate.json` file. Skips walking parent directories for config discovery. | `/app/ci/quality-gate.yaml` |
293
+ | `PROJECT_ROOT` | Override detected project root. Default: walk up from the process cwd until `package.json` or `tsconfig.json` is found. | `/Users/me/my-repo` |
294
+ | `SONAR_HOST_URL` | SonarQube server base URL (Phase 2). | `http://localhost:9000` |
295
+ | `SONAR_TOKEN` | SonarQube authentication token (Phase 2). Prefer env / secret store; avoid committing. | `sqa_xxx...` |
296
+ | `SONAR_PROJECT_KEY` | SonarQube project key (Phase 2). | `my-project` |
297
+ | `SONAR_SCANNER_PATH` | Full path to the `sonar-scanner` executable if it is not on `PATH`. | `/opt/sonar-scanner/bin/sonar-scanner` |
298
+ | `PHASE1_TIMEOUT` | Phase 1 subprocess timeout in milliseconds. | `30000` (default) |
299
+ | `PHASE2_TIMEOUT` | Phase 2 (Sonar) timeout in milliseconds. | `300000` (default) |
300
+ | `ENABLE_I18N_RULES` | Set to `true` to enable ESLint rules that flag raw string literals in JSX (for i18n-heavy apps). | `false` (default) |
301
+
302
+ ---
303
+
304
+ ## Auto-Fix
305
+
306
+ Phase 1 automatically fixes these issues:
307
+
308
+ ### ESLint Auto-Fix (~100+ rules)
309
+
310
+ ```typescript
311
+ // var → const/let
312
+ var x = 1 → const x = 1
313
+
314
+ // forEach → for...of (unicorn/no-array-for-each)
315
+ arr.forEach(x => f(x)) → for (const x of arr) f(x)
316
+
317
+ // Nested ternary → extracted (unicorn/no-nested-ternary)
318
+ a ? b : c ? d : e → const temp = c ? d : e; a ? b : temp
319
+
320
+ // Unused imports removed
321
+ import { unused } from 'x' → (removed)
322
+
323
+ // Type imports (consistent-type-imports)
324
+ import { Type } from 'x' → import type { Type } from 'x'
325
+
326
+ // Optional chain (prefer-optional-chain)
327
+ a && a.b && a.b.c → a?.b?.c
328
+
329
+ // Regex optimization (regexp/*)
330
+ /[0-9]/ → /\d/
331
+ ```
332
+
333
+ ### AST Auto-Fix
334
+
335
+ ```typescript
336
+ // Remove unnecessary curly braces (single-line if)
337
+ if (x) { return true } → if (x) return true
338
+ ```
339
+
340
+ ### Prettier Formatting
341
+
342
+ After ESLint fixes, Prettier runs to ensure consistent formatting:
343
+
344
+ ```typescript
345
+ // ESLint removes braces but leaves awkward format:
346
+ if (x)
347
+ return true
348
+
349
+ // Prettier fixes to single line:
350
+ if (x) return true
351
+ ```
352
+
353
+ > **Note:** Prettier uses project's config, not MCP's.
354
+
355
+ **Everything else:** Reported to AI, AI fixes it.
356
+
357
+ ---
358
+
359
+ ## API
360
+
361
+ ### Tool: `quality_fix`
362
+
363
+ ```typescript
364
+ // Input
365
+ {
366
+ files: string[] // File paths to check
367
+ }
368
+
369
+ // Output
370
+ {
371
+ phase: "local" | "server" | "complete",
372
+ success: boolean,
373
+ message: string,
374
+ fixed: {
375
+ eslint: number, // ESLint auto-fixes
376
+ curlyBraces: number, // AST: single-statement if braces
377
+ singleLineArrow: number, // AST: arrow body style
378
+ prettier: number, // Prettier formatting
379
+ json: number // JSON validation passes counted
380
+ },
381
+ remaining: Issue[],
382
+ timing: {
383
+ phase1: string,
384
+ phase2?: string,
385
+ total: string
386
+ }
387
+ }
388
+ ```
389
+
390
+ ---
391
+
392
+ ## Feature Flags
393
+
394
+ ### `ENABLE_I18N_RULES`
395
+
396
+ For projects with internationalization (i18n), enable literal string detection:
397
+
398
+ ```json
399
+ {
400
+ "env": {
401
+ "ENABLE_I18N_RULES": "true"
402
+ }
403
+ }
404
+ ```
405
+
406
+ When enabled:
407
+
408
+ ```tsx
409
+ // ⚠️ Warning
410
+ <h1>Hello World</h1>
411
+
412
+ // ✅ OK
413
+ <h1>{t('hello')}</h1>
414
+ ```
415
+
416
+ ---
417
+
418
+ ## Troubleshooting
419
+
420
+ ### MCP: `quality_fix` does not appear
421
+
422
+ 1. **Node.js 18+** — run `node -v` and `npx --version`.
423
+ 2. **Reload** Cursor after editing `mcp.json` (or use the MCP refresh control).
424
+ 3. **JSON** — the file must be valid JSON (no trailing commas). Copy from the [MCP configuration](#mcp-configuration-cursor) section if unsure.
425
+ 4. **Global install** — if you use `"command": "ai-quality-gate"`, run `npm i -g ai-quality-gate` once so the binary exists.
426
+
427
+ ### Windows
428
+
429
+ **"npx not found" error:**
430
+
431
+ ```bash
432
+ # Node.js must be in PATH
433
+ # Check in PowerShell:
434
+ where.exe npx
435
+ ```
436
+
437
+ **Permission denied:**
438
+
439
+ ```bash
440
+ # Run PowerShell as Administrator
441
+ ```
442
+
443
+ ### macOS / Linux
444
+
445
+ **"Permission denied" error:**
446
+
447
+ ```bash
448
+ # Fix npm global directory
449
+ mkdir ~/.npm-global
450
+ npm config set prefix '~/.npm-global'
451
+ echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc
452
+ source ~/.zshrc
453
+ ```
454
+
455
+ **"sonar-scanner not found" error:**
456
+
457
+ ```bash
458
+ # Install via Homebrew
459
+ brew install sonar-scanner
460
+
461
+ # Or via npm
462
+ npm install -g sonarqube-scanner
463
+ ```
464
+
465
+ ### SonarQube
466
+
467
+ **"Insufficient privileges" error:**
468
+
469
+ - SonarQube → **Administration** → **Security** → **Global Permissions**
470
+ - Give **Anyone** group **Browse** and **Execute Analysis** permissions
471
+
472
+ **"Project not found" error:**
473
+
474
+ - Create project manually for first analysis: **Projects** → **Create Project** → **Manually**
475
+
476
+ ---
477
+
478
+ ## Clone & build (contributors)
479
+
480
+ ```bash
481
+ git clone https://github.com/mustafacagri/ai-quality-gate.git
482
+ cd ai-quality-gate
483
+ yarn install
484
+ yarn build
485
+ ```
486
+
487
+ Use [Local development (this repository)](#local-development-this-repository) for MCP pointing at `dist/server.js`.
488
+
489
+ ---
490
+
491
+ ## Docs
492
+
493
+ - [SETUP.md](./SETUP.md) — Local setup (if included in your tree)
494
+ - [AGREEMENTS.md](./docs/AGREEMENTS.md), [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md), etc. — optional; some files may be omitted in minimal clones. **README** + **`.cursor/mcp.json.example`** are enough to run the published package.
495
+
496
+ ---
497
+
498
+ ## Principles
499
+
500
+ - ✅ 627 ESLint rules (SonarJS, Unicorn, TypeScript-ESLint, etc.)
501
+ - ✅ Prettier integration (uses project's config)
502
+ - ✅ AST-based transforms (no regex)
503
+ - ✅ Verify after each fix
504
+ - ✅ Rollback on error
505
+ - ✅ ESLint config discovery (uses project config if available, otherwise embedded)
506
+ - ✅ Zero workaround
507
+ - ✅ Principal level
508
+
509
+ ---
510
+
511
+ ## License
512
+
513
+ MIT © [Mustafa Çağrı Güven](https://github.com/mustafacagri)
514
+
515
+ ---
516
+
517
+ **v0.0.1** — Initial release! MCP `quality_fix`, Phase 1/2 pipeline, CLI, config files, custom rules (see [CHANGELOG](./CHANGELOG.md))