@nitra/cursor 1.8.73 → 1.8.74

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/mdc/abie.mdc CHANGED
@@ -1,14 +1,18 @@
1
1
  ---
2
2
  description: Правила для проєктів AbInBev Efes
3
3
  alwaysApply: true
4
- version: '1.4'
4
+ version: '1.7'
5
5
  ---
6
6
 
7
- Правило **abie** для споживачів **@nitra/cursor**: **k8s** (**Deployment** + **HealthCheckPolicy**), overlay **ua** / **ru** (**nodeSelector**, видалення **HealthCheckPolicy** у **ru**) і гілки в **clean-merged-branch**. **`npx @nitra/cursor check abie`** виконується лише якщо в **`.n-cursor.json`** у **`rules`** є **`abie`** — інакше вихід **0** без зауважень.
7
+ Правило **abie** для споживачів **@nitra/cursor**: **k8s** (Deployment + **HealthCheckPolicy** у **`hc.yaml`**, overlay **ua** / **ru** **nodeSelector**, **HTTPRoute** (будь-який непорожній **`target.name`**), видалення **HealthCheckPolicy** у **ru**), а також гілки **dev**, **ua**, **ru** у **clean-merged-branch**.
8
+
9
+ **`npx @nitra/cursor check abie`** виконується лише якщо в **`.n-cursor.json`** у **`rules`** є **`abie`** — інакше вихід **0** без зауважень.
10
+
11
+ **Канон перевірки** — **`npm/scripts/check-abie.mjs`**: верхній JSDoc і реалізація задають точні умови, допустимі домени для hostnames, тексти помилок. Нижче — зміст правила й орієнтовні фрагменти YAML; не дублюй тут покроковий алгоритм зі скрипта.
8
12
 
9
13
  ## k8s: `hc.yaml` поруч із Deployment
10
14
 
11
- Якщо під **`k8s`** є **`kind: Deployment`**, у **тій самій директорії** має бути **`hc.yaml`** з **HealthCheckPolicy** (**`networking.gke.io/v1`**): коректний modeline **`$schema`**, **`/healthz`**, порт **8080**, **`targetRef.name`** = **`metadata.name`**. Деталі — **`validateAbieHcYaml`** у **`npm/scripts/check-abie.mjs`**.
15
+ Якщо під **`k8s`** є **Deployment**, у **тій самій директорії** має бути **`hc.yaml`** з **HealthCheckPolicy** (**`networking.gke.io/v1`**): коректний modeline **`$schema`**, **`/healthz`**, порт **8080**, **`targetRef.name`** = **`metadata.name`**.
12
16
 
13
17
  ```yaml title="hc.yaml"
14
18
  # yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/networking.gke.io/healthcheckpolicy_v1.json
@@ -30,19 +34,19 @@ spec:
30
34
  name: СЕРВІС
31
35
  ```
32
36
 
33
- ## k8s: overlay **HTTPRoute** `nginx-run` (**ua** / **ru**)
37
+ ## k8s: overlay **HTTPRoute** (**ua** / **ru**)
34
38
 
35
- Якщо під **`k8s`** є **Deployment**, у **кожному** **`ua/kustomization.yaml`** та **`ru/kustomization.yaml`** має бути inline **JSON6902** у **`patches[].patch`** на **`target.kind: HTTPRoute`**, **`name: nginx-run`**: **replace** **`/spec/hostnames`** (допустимі домени — як у прикладах нижче) і **replace** **`/spec/parentRefs/0/namespace`** (**`ua`** або **`ru`**). Для **ru** додатково потрібна анотація **`gwin.yandex.cloud/rules.http.upgradeTypes: websocket`** (зазвичай **op: add**, **`/metadata/annotations`**). Критерії**`validateAbieNginxRunHttpRoutePatches`** / **`getCombinedNginxRunPatchTextFromKustomization`** у **`npm/scripts/check-abie.mjs`**.
39
+ За наявності **Deployment** під **k8s** у **кожному** **`ua/kustomization.yaml`** та **`ru/kustomization.yaml`** потрібні **inline JSON6902** у **`patches`**: **target** **`kind: HTTPRoute`**, **непорожній `name`** (як у маніфесті маршруту). Мають бути зміни **`/spec/hostnames`** (домени abie — у скрипті) та **`/spec/parentRefs/0/namespace`** (**`ua`** / **`ru`**). Для **ru** анотація **`gwin.yandex.cloud/rules.http.upgradeTypes: websocket`**. Як обирати **`op`** (**add** / **replace** тощо) у patch **k8s.mdc** (розділ про JSON patch у kustomization).
36
40
 
37
41
  ```yaml title="…/ua/kustomization.yaml (фрагмент)"
38
42
  - target:
39
43
  kind: HTTPRoute
40
- name: nginx-run
44
+ name: my-httproute
41
45
  patch: |-
42
46
  - op: replace
43
47
  path: /spec/hostnames
44
48
  value:
45
- - "abie.app" # також допускається vybeerai.com.ua, *.vybeerai.com.ua, *.abie.app
49
+ - "abie.app" # зокрема vybeerai.com.ua, *.vybeerai.com.ua, *.abie.app
46
50
  - op: replace
47
51
  path: /spec/parentRefs/0/namespace
48
52
  value: ua
@@ -51,12 +55,12 @@ spec:
51
55
  ```yaml title="…/ru/kustomization.yaml (фрагмент)"
52
56
  - target:
53
57
  kind: HTTPRoute
54
- name: nginx-run
58
+ name: my-httproute
55
59
  patch: |-
56
60
  - op: replace
57
61
  path: /spec/hostnames
58
62
  value:
59
- - "napitkivmeste.tech" # також допускається выбирайонлайн.рф, *.napitkivmeste.tech, *.выбирайонлайн.рф
63
+ - "napitkivmeste.tech" # зокрема выбирайонлайн.рф, *.napitkivmeste.tech, *.выбирайонлайн.рф
60
64
  - op: replace
61
65
  path: /spec/parentRefs/0/namespace
62
66
  value: ru
@@ -65,7 +69,7 @@ spec:
65
69
  ```yaml title="…/ru/kustomization.yaml (фрагмент)"
66
70
  - target:
67
71
  kind: HTTPRoute
68
- name: nginx-run
72
+ name: my-httproute
69
73
  patch: |-
70
74
  - op: add
71
75
  path: /metadata/annotations
@@ -73,9 +77,9 @@ spec:
73
77
  gwin.yandex.cloud/rules.http.upgradeTypes: "websocket"
74
78
  ```
75
79
 
76
- ## k8s: overlay **`ru`** і HealthCheckPolicy
80
+ ## k8s: overlay **ru** і HealthCheckPolicy
77
81
 
78
- Якщо в дереві **k8s** є **HealthCheckPolicy**, **check abie** вимагає **`ru/kustomization.yaml`** з patch **`$patch: delete`** для політики (узгоджено з **k8s.mdc** / **check-k8s**, **`ruKustomizationHasHealthCheckDeletePatch`** у **`npm/scripts/check-k8s.mjs`**). Підстав реальне ім’я замість **`СЕРВІС`**:
82
+ Якщо в дереві **k8s** є **HealthCheckPolicy**, у **`ru/kustomization.yaml`** має бути patch **`$patch: delete`** для політики (узгоджено з **k8s.mdc**; перевірка в **`check-k8s.mjs`**, **`ruKustomizationHasHealthCheckDeletePatch`**). Підстав реальне ім’я замість **`СЕРВІС`**:
79
83
 
80
84
  ```yaml title="…/ru/kustomization.yaml (фрагмент)"
81
85
  patches:
@@ -89,9 +93,9 @@ patches:
89
93
  $patch: delete
90
94
  ```
91
95
 
92
- ## k8s: overlay **`ua`** / **`ru`** і nodeSelector
96
+ ## k8s: overlay **ua** / **ru** і nodeSelector
93
97
 
94
- Якщо під **`k8s`** є **Deployment**, у **кожному** **`…/ua/kustomization.yaml`** та **`…/ru/kustomization.yaml`** має бути inline **JSON6902** у **`patches[].patch`** на **`target.kind: Deployment`** з **nodeSelector** за політикою abie (**ua** — **add** + **preem** false; **ru** — **replace** + **yandex.cloud/preemptible** false). Критерії збігу **`kustomizationHasAbieDeploymentNodeSelectorPatch`** у **`npm/scripts/check-abie.mjs`**.
98
+ За наявності **Deployment** під **k8s** у **кожному** **`…/ua/kustomization.yaml`** та **`…/ru/kustomization.yaml`** patch на **`kind: Deployment`**: **ua** — **`spec.template.spec.nodeSelector`** з **`preem: false`**; **ru** — **`spec.template.spec.nodeSelector`** з **`yandex.cloud/preemptible: false`**. Форму **JSON6902** (шлях **`/spec/template/spec/nodeSelector`**, **`op`**) див. **k8s.mdc**.
95
99
 
96
100
  ```yaml title="…/ua/kustomization.yaml (фрагмент)"
97
101
  patches:
@@ -119,7 +123,7 @@ patches:
119
123
 
120
124
  ### Базовий Deployment (`…/base/`)
121
125
 
122
- Якщо **Deployment** у YAML під **`k8s`** лежить у шляху з сегментом **`base`** (наприклад **`…/k8s/base/deploy.yaml`**), у **`spec.template.spec.nodeSelector`** має бути **`preem`** зі значенням **істинно** (**`true`** або рядок **`'true'`**) overlay **ua** / **ru** підміняє селектор через kustomize. Деталі — **`deploymentDocumentHasAbieBasePreemNodeSelector`** / **`isAbieK8sBaseYamlPath`** у **`npm/scripts/check-abie.mjs`**.
126
+ Якщо **Deployment** у YAML під **`k8s`** лежить у шляху з сегментом **`base`**, у **`spec.template.spec.nodeSelector`** має бути **`preem`** зі значенням **істинно** (**`true`** або рядок **`'true'`**); overlay **ua** / **ru** підміняє селектор.
123
127
 
124
128
  ```yaml title="…/base/deploy.yaml (фрагмент)"
125
129
  spec:
@@ -131,7 +135,7 @@ spec:
131
135
 
132
136
  ## Git branches
133
137
 
134
- У **`.github/workflows/clean-merged-branch.yml`** у кроці **`phpdocker-io/github-actions-delete-abandoned-branches`** значення **`with.ignore_branches`** має містити **dev**, **ua** та **ru** (разом з іншими гілками, якщо потрібно), наприклад:
138
+ У **`.github/workflows/clean-merged-branch.yml`** у кроці **`phpdocker-io/github-actions-delete-abandoned-branches`** значення **`with.ignore_branches`** має містити **dev**, **ua** та **ru** (разом з іншими гілками, якщо потрібно):
135
139
 
136
140
  ```yaml title=".github/workflows/clean-merged-branch.yml (фрагмент)"
137
141
  with:
package/mdc/k8s.mdc CHANGED
@@ -206,20 +206,10 @@ patches:
206
206
  value: dev
207
207
  ```
208
208
 
209
- 4. Якщо в kustomization.yaml є remove разом з add на однаковий path:
210
-
211
- ```yaml title="overlay/kustomization.yaml (фрагмент)"
212
- - op: remove
213
- path: /spec/template/spec/nodeSelector
214
- - op: add
215
- path: /spec/template/spec/nodeSelector
216
- value:
217
- preem: "false"
218
- ```
219
-
220
- заміняй на replace:
209
+ 4. **JSON patch у kustomization:** де можливо, змінюй ресурс через **`op: replace`** (одна операція на `path`), а не пару **`remove` + `add`** на той самий шлях. **`add`** / **`remove`** лишай лише коли **`replace`** не підходить (наприклад додати новий ключ або прибрати поле без заміни).
221
210
 
222
211
  ```yaml title="overlay/kustomization.yaml (фрагмент)"
212
+ patches:
223
213
  - target:
224
214
  kind: Deployment
225
215
  name: x
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.8.73",
3
+ "version": "1.8.74",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -21,9 +21,10 @@
21
21
  * має бути inline **JSON6902** patch на **`kind: Deployment`**: для **ua** — **`op: add`**, **`path: /spec/template/spec/nodeSelector`**,
22
22
  * **`preem: false`**; для **ru** — **`op: replace`**, той самий **path**, **`yandex.cloud/preemptible: false`** (див. abie.mdc).
23
23
  *
24
- * **HTTPRoute nginx-run:** за тієї ж умови (**Deployment** під **k8s**) у **кожному** **`ua`/`ru` kustomization** має бути
25
- * inline **JSON6902** на **`kind: HTTPRoute`**, **`name: nginx-run`**: **replace** **`/spec/hostnames`** (домени з abie.mdc),
26
- * **replace** **`/spec/parentRefs/0/namespace`** (**ua** / **ru**); для **ru** також **`gwin.yandex.cloud/rules.http.upgradeTypes: websocket`**.
24
+ * **HTTPRoute (overlay):** за тієї ж умови (**Deployment** під **k8s**) у **кожному** **`ua`/`ru` kustomization** має бути
25
+ * inline **JSON6902** на **`kind: HTTPRoute`** з **непорожнім `target.name`** (будь-яке ім’я): **replace** **`/spec/hostnames`**
26
+ * (домени з abie.mdc), **replace** **`/spec/parentRefs/0/namespace`** (**ua** / **ru**); для **ru** також
27
+ * **`gwin.yandex.cloud/rules.http.upgradeTypes: websocket`**.
27
28
  */
28
29
  import { existsSync } from 'node:fs'
29
30
  import { readFile } from 'node:fs/promises'
@@ -484,11 +485,11 @@ const ABIE_RU_HTTPROUTE_HOST_MARKERS = [
484
485
  ]
485
486
 
486
487
  /**
487
- * Збирає тексти inline **patch** для **HTTPRoute/nginx-run** з одного розібраного документа **Kustomization**.
488
+ * Збирає тексти inline **patch** для **HTTPRoute** (будь-який непорожній **target.name**) з одного документа **Kustomization**.
488
489
  * @param {import('yaml').Document} doc документ після **parseAllDocuments**
489
490
  * @returns {string[]} непорожні рядки **patch**
490
491
  */
491
- function collectNginxRunPatchStringsFromKustomizationDoc(doc) {
492
+ function collectAbieHttpRoutePatchStringsFromKustomizationDoc(doc) {
492
493
  if (doc.errors.length > 0) {
493
494
  return []
494
495
  }
@@ -512,7 +513,7 @@ function collectNginxRunPatchStringsFromKustomizationDoc(doc) {
512
513
  const target = pr.target
513
514
  if (target !== null && typeof target === 'object' && !Array.isArray(target)) {
514
515
  const tg = /** @type {Record<string, unknown>} */ (target)
515
- if (tg.kind === 'HTTPRoute' && tg.name === 'nginx-run') {
516
+ if (tg.kind === 'HTTPRoute' && typeof tg.name === 'string' && tg.name.trim() !== '') {
516
517
  const patchStr = pr.patch
517
518
  if (typeof patchStr === 'string' && patchStr.trim() !== '') {
518
519
  out.push(patchStr)
@@ -525,7 +526,7 @@ function collectNginxRunPatchStringsFromKustomizationDoc(doc) {
525
526
  }
526
527
 
527
528
  /**
528
- * Збирає всі inline **JSON6902**-фрагменти для **HTTPRoute/nginx-run** у **kustomization.yaml** (усі документи у файлі).
529
+ * Збирає всі inline **JSON6902**-фрагменти для **HTTPRoute** (непорожній **target.name**) у **kustomization.yaml** (усі документи у файлі).
529
530
  * @param {string} raw повний текст файлу
530
531
  * @returns {string} текст для **`validateAbieNginxRunHttpRoutePatches`** (може бути порожнім)
531
532
  */
@@ -544,44 +545,44 @@ export function getCombinedNginxRunPatchTextFromKustomization(raw) {
544
545
  /** @type {string[]} */
545
546
  const chunks = []
546
547
  for (const doc of docs) {
547
- chunks.push(...collectNginxRunPatchStringsFromKustomizationDoc(doc))
548
+ chunks.push(...collectAbieHttpRoutePatchStringsFromKustomizationDoc(doc))
548
549
  }
549
550
  return chunks.join('\n')
550
551
  }
551
552
 
552
553
  /**
553
- * Перевіряє сукупний текст patch(ів) **HTTPRoute/nginx-run** на відповідність abie.mdc.
554
+ * Перевіряє сукупний текст patch(ів) **HTTPRoute** (будь-яке **target.name**) на відповідність abie.mdc.
554
555
  * @param {string} combined текст одного або кількох inline **patch**, розділених символом нового рядка
555
556
  * @param {'ua' | 'ru'} mode **ua** або **ru**
556
557
  * @returns {string | null} повідомлення про помилку або **null**
557
558
  */
558
559
  export function validateAbieNginxRunHttpRoutePatches(combined, mode) {
559
560
  if (typeof combined !== 'string' || combined.trim() === '') {
560
- return `очікується patch target kind HTTPRoute name nginx-run (replace hostnames, parentRefs namespace ${mode}; для ru — також gwin… upgradeTypes websocket) — abie.mdc`
561
+ return `очікується patch target kind HTTPRoute з непорожнім target.name (replace hostnames, parentRefs namespace ${mode}; для ru — також gwin… upgradeTypes websocket) — abie.mdc`
561
562
  }
562
563
  const hasHostnamesReplace = /-\s*op:\s*replace\b[\s\S]{0,200}?path:\s*\/spec\/hostnames\b/m.test(combined)
563
564
  if (!hasHostnamesReplace) {
564
- return 'HTTPRoute nginx-run: потрібен блок op replace з path /spec/hostnames (abie.mdc)'
565
+ return 'HTTPRoute: потрібен блок op replace з path /spec/hostnames (abie.mdc)'
565
566
  }
566
567
  const markers = mode === 'ua' ? ABIE_UA_HTTPROUTE_HOST_MARKERS : ABIE_RU_HTTPROUTE_HOST_MARKERS
567
568
  if (!markers.some(m => combined.includes(m))) {
568
- return `HTTPRoute nginx-run: у value для /spec/hostnames має бути один із доменів abie (${markers.join(', ')}) — abie.mdc`
569
+ return `HTTPRoute: у value для /spec/hostnames має бути один із доменів abie (${markers.join(', ')}) — abie.mdc`
569
570
  }
570
571
  const namespaceOk =
571
572
  mode === 'ua'
572
573
  ? /path:\s*\/spec\/parentRefs\/0\/namespace\b[\s\S]{0,200}?value:\s*['"]?ua['"]?(?:\s|$)/mu.test(combined)
573
574
  : /path:\s*\/spec\/parentRefs\/0\/namespace\b[\s\S]{0,200}?value:\s*['"]?ru['"]?(?:\s|$)/mu.test(combined)
574
575
  if (!namespaceOk) {
575
- return `HTTPRoute nginx-run: потрібен replace path /spec/parentRefs/0/namespace з value ${mode} (abie.mdc)`
576
+ return `HTTPRoute: потрібен replace path /spec/parentRefs/0/namespace з value ${mode} (abie.mdc)`
576
577
  }
577
578
  if (mode === 'ru' && !/gwin\.yandex\.cloud\/rules\.http\.upgradeTypes:\s*['"]?websocket['"]?/m.test(combined)) {
578
- return 'HTTPRoute nginx-run (ru): потрібна анотація gwin.yandex.cloud/rules.http.upgradeTypes: websocket (abie.mdc)'
579
+ return 'HTTPRoute (ru): потрібна анотація gwin.yandex.cloud/rules.http.upgradeTypes: websocket (abie.mdc)'
579
580
  }
580
581
  return null
581
582
  }
582
583
 
583
584
  /**
584
- * Чи **kustomization** містить валідні для abie записи **patch** для **HTTPRoute/nginx-run** (**ua** або **ru**).
585
+ * Чи **kustomization** містить валідні для abie **patch** для **HTTPRoute** з непорожнім **target.name** (**ua** або **ru**).
585
586
  * @param {string} raw повний текст **kustomization.yaml**
586
587
  * @param {'ua' | 'ru'} mode overlay
587
588
  * @returns {boolean} true, якщо **`validateAbieNginxRunHttpRoutePatches`** повертає **null**
@@ -833,7 +834,7 @@ async function ensureUaRuAbieNodeSelectorPatches(root, yamlFilesAbs, fail, passF
833
834
  }
834
835
 
835
836
  /**
836
- * Якщо є **Deployment** під **k8s**, вимагає в кожному overlay **ua** та **ru** patch **HTTPRoute/nginx-run** (abie.mdc).
837
+ * Якщо є **Deployment** під **k8s**, вимагає в кожному overlay **ua** та **ru** patch **HTTPRoute** (непорожній **target.name**) за abie.mdc.
837
838
  * @param {string} root корінь репозиторію
838
839
  * @param {string[]} yamlFilesAbs yaml під k8s
839
840
  * @param {(msg: string) => void} fail callback
@@ -844,7 +845,7 @@ async function ensureUaRuAbieHttpRoutePatches(root, yamlFilesAbs, fail, passFn)
844
845
  const uaAbsList = yamlFilesAbs.filter(abs => isUaKustomizationPath(relative(root, abs).replaceAll('\\', '/') || abs))
845
846
  if (uaAbsList.length === 0) {
846
847
  fail(
847
- 'Є Deployment у k8s — додай ua/kustomization.yaml з patch HTTPRoute nginx-run (hostnames, parentRefs namespace ua) — abie.mdc'
848
+ 'Є Deployment у k8s — додай ua/kustomization.yaml з patch HTTPRoute (будь-який target.name: hostnames, parentRefs namespace ua) — abie.mdc'
848
849
  )
849
850
  return
850
851
  }
@@ -864,13 +865,13 @@ async function ensureUaRuAbieHttpRoutePatches(root, yamlFilesAbs, fail, passFn)
864
865
  fail(`${rel}: ${v}`)
865
866
  return
866
867
  }
867
- passFn(`${rel}: HTTPRoute nginx-run (ua) відповідає abie.mdc`)
868
+ passFn(`${rel}: HTTPRoute patch (ua) відповідає abie.mdc`)
868
869
  }
869
870
 
870
871
  const ruAbsList = yamlFilesAbs.filter(abs => isRuKustomizationPath(relative(root, abs).replaceAll('\\', '/') || abs))
871
872
  if (ruAbsList.length === 0) {
872
873
  fail(
873
- 'Є Deployment у k8s — додай ru/kustomization.yaml з patch HTTPRoute nginx-run (hostnames, namespace ru, gwin websocket) — abie.mdc'
874
+ 'Є Deployment у k8s — додай ru/kustomization.yaml з patch HTTPRoute (будь-який target.name: hostnames, namespace ru, gwin websocket) — abie.mdc'
874
875
  )
875
876
  return
876
877
  }
@@ -890,7 +891,7 @@ async function ensureUaRuAbieHttpRoutePatches(root, yamlFilesAbs, fail, passFn)
890
891
  fail(`${rel}: ${v}`)
891
892
  return
892
893
  }
893
- passFn(`${rel}: HTTPRoute nginx-run (ru) відповідає abie.mdc`)
894
+ passFn(`${rel}: HTTPRoute patch (ru) відповідає abie.mdc`)
894
895
  }
895
896
  }
896
897
 
@@ -983,7 +984,7 @@ export async function check() {
983
984
  if (deploymentDirs.size > 0) {
984
985
  pass('Є Deployment — перевіряємо nodeSelector у ua/ru kustomization (abie.mdc)')
985
986
  await ensureUaRuAbieNodeSelectorPatches(root, yamlFiles, fail, pass)
986
- pass('Є Deployment — перевіряємо HTTPRoute nginx-run у ua/ru kustomization (abie.mdc)')
987
+ pass('Є Deployment — перевіряємо HTTPRoute у ua/ru kustomization (abie.mdc)')
987
988
  await ensureUaRuAbieHttpRoutePatches(root, yamlFiles, fail, pass)
988
989
  }
989
990
 
@@ -10,7 +10,7 @@ import { pass } from './pass.mjs'
10
10
 
11
11
  /**
12
12
  * Створює пару `pass` / `fail` з накопиченням ненульового коду виходу.
13
- * @returns {{ pass: typeof pass, fail: (msg: string) => void, getExitCode: () => number }}
13
+ * @returns {{ pass: typeof pass, fail: (msg: string) => void, getExitCode: () => number }} об’єкт з `pass`, `fail` і `getExitCode()` (0 або 1 після будь-якого `fail`)
14
14
  */
15
15
  export function createCheckReporter() {
16
16
  let exitCode = 0