@nitra/cursor 1.13.41 → 1.13.43
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 +13 -0
- package/bin/n-cursor.js +1 -2
- package/package.json +1 -1
- package/rules/efes/auto.md +1 -0
- package/rules/efes/efes.mdc +7 -0
- package/rules/k8s/policy/network_policy/network_policy.rego +2 -2
- package/rules/text/lint/lint.mjs +10 -6
- package/schemas/n-cursor.json +1 -1
- package/scripts/auto-rules.mjs +4 -0
- package/scripts/sync-claude-config.mjs +2 -28
- package/skills/efes-create-env/SKILL.md +185 -0
- package/skills/efes-create-env/auto.md +1 -0
- package/.claude-template/npm-CLAUDE.md +0 -40
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
6
6
|
|
|
7
|
+
## [1.13.43] - 2026-05-18
|
|
8
|
+
|
|
9
|
+
### Removed
|
|
10
|
+
|
|
11
|
+
- `npm/CLAUDE.md` як path-scoped нагадування для роботи в `npm/` повністю прибрано — фінальне завершення міграції з `1.13.42` (де вже прибрали `syncNpmClaudeMd` + Rego-first STOP перенесли у `scripts.mdc`): видалено сам `npm/CLAUDE.md`, темплейт `npm/.claude-template/npm-CLAUDE.md`, останні згадки в `bin/n-cursor.js` (повідомлення про `npm/CLAUDE.md` після sync; JSDoc) і опис у `schemas/n-cursor.json` `claude-config`. Реліз-правила (PR-bump + CHANGELOG) і так живуть у `n-changelog.mdc`/`n-npm-module.mdc` (alwaysApply).
|
|
12
|
+
|
|
13
|
+
## [1.13.42] - 2026-05-18
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `efes` rule: новий (поки що порожній) пакет правил для проєктів **github.com/efes-cloud/***. Автодетект у `auto-rules.mjs` через `EFES_REPOSITORY_URL_MARKER` (`https://github.com/efes-cloud/`) — аналогічно до `abie`. Додано `npm/rules/efes/efes.mdc` + `auto.md`, прописано порядок в `AUTO_RULE_ORDER` і покрито тестами в `auto-rules.test.mjs`.
|
|
18
|
+
- `efes-create-env` skill: повʼязано з правилом `efes` через `skills/efes-create-env/auto.md` (`[efes]`) — активується автоматично, коли репозиторій відповідає efes-маркеру. Тести в `auto-skills.test.mjs` фіксують позитивний і негативний випадки.
|
|
19
|
+
|
|
7
20
|
## [1.13.41] - 2026-05-18
|
|
8
21
|
|
|
9
22
|
### Fixed
|
package/bin/n-cursor.js
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Agent інтеграція: під час синку, окрім `.cursor/rules` і `.claude/commands` (з skills), CLI ще раз
|
|
24
24
|
* синхронізує `.claude/settings.json` (hooks + permissions; merge — користувацькі поля зберігаються),
|
|
25
25
|
* `.cursor/hooks.json` (Cursor Agent hooks; merge — користувацькі hooks зберігаються),
|
|
26
|
-
*
|
|
26
|
+
* і slash-команди checks (`/n-check`).
|
|
27
27
|
* Опт-аут — поле `claude-config: false` у `.n-cursor.json`.
|
|
28
28
|
*
|
|
29
29
|
* Якщо у корені репозиторію немає .n-cursor.json, спочатку перейменовується за наявності nitra-cursor.json;
|
|
@@ -1315,7 +1315,6 @@ async function runSync() {
|
|
|
1315
1315
|
const parts = []
|
|
1316
1316
|
if (result.settings) parts.push('.claude/settings.json')
|
|
1317
1317
|
if (result.cursorHooks) parts.push('.cursor/hooks.json')
|
|
1318
|
-
if (result.npmClaudeMd) parts.push('npm/CLAUDE.md')
|
|
1319
1318
|
if (result.commands.length > 0) parts.push(`${result.commands.length} slash-commands`)
|
|
1320
1319
|
if (result.adrHook) parts.push('.claude/hooks/capture-decisions.sh')
|
|
1321
1320
|
if (result.adrNormalizeHook) parts.push('.claude/hooks/normalize-decisions.sh')
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
якщо в кореневому package.json в секції "repository" присутній текст "<https://github.com/efes-cloud/**/>"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Правила для проєктів Efes (репозиторії під github.com/efes-cloud)
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
version: '1.0'
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Правило **efes** для споживачів **@nitra/cursor** у репозиторіях під **`github.com/efes-cloud/*`**. Поки що зміст правила порожній — додавайте сюди вимоги, специфічні для efes-проєктів, у міру їх появи.
|
|
@@ -130,7 +130,7 @@ egress_has_internet_http_https(spec) if {
|
|
|
130
130
|
is_object(peer)
|
|
131
131
|
ipb := object.get(peer, "ipBlock", null)
|
|
132
132
|
is_object(ipb)
|
|
133
|
-
|
|
133
|
+
ipb.cidr == "0.0.0.0/0"
|
|
134
134
|
ports := object.get(rule, "ports", null)
|
|
135
135
|
is_array(ports)
|
|
136
136
|
egress_ports_include(ports, 80)
|
|
@@ -140,7 +140,7 @@ egress_has_internet_http_https(spec) if {
|
|
|
140
140
|
egress_ports_include(ports, want) if {
|
|
141
141
|
some p in ports
|
|
142
142
|
is_object(p)
|
|
143
|
-
|
|
143
|
+
p.port == want
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
egress_has_cluster_namespace_selector(spec) if {
|
package/rules/text/lint/lint.mjs
CHANGED
|
@@ -78,8 +78,9 @@ const DOTENV_LINTER_PREFLIGHT = {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
|
-
*
|
|
82
|
-
* @
|
|
81
|
+
* Шукає шлях до бінарника `dep.bin` у `PATH`; на Windows додатково перебирає `dep.winBins`.
|
|
82
|
+
* @param {PreflightDep} dep опис залежності з canon-списку preflight-перевірок
|
|
83
|
+
* @returns {string | null} абсолютний шлях до знайденого бінарника або `null`, якщо не знайдено
|
|
83
84
|
*/
|
|
84
85
|
function resolvePreflightBin(dep) {
|
|
85
86
|
if (platform === 'win32' && dep.winBins) {
|
|
@@ -92,8 +93,9 @@ function resolvePreflightBin(dep) {
|
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
/**
|
|
95
|
-
*
|
|
96
|
-
* @
|
|
96
|
+
* Друкує stderr-повідомлення про відсутній бінарник з install-hint'ами і посиланням на правило.
|
|
97
|
+
* @param {PreflightDep} dep опис залежності — джерело пояснення й install-команд
|
|
98
|
+
* @returns {void} нічого не повертає; виводить рядки в `console.error`
|
|
97
99
|
*/
|
|
98
100
|
function printPreflightMissingMessage(dep) {
|
|
99
101
|
console.error(`❌ ${dep.bin} не знайдено в PATH.`)
|
|
@@ -106,8 +108,10 @@ function printPreflightMissingMessage(dep) {
|
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
+
* Виконує preflight-перевірку: повертає `true` і друкує `successMsg`, якщо бінарник знайдено,
|
|
112
|
+
* інакше друкує install-hint у stderr і повертає `false`.
|
|
113
|
+
* @param {PreflightDep} dep опис залежності для перевірки наявності в `PATH`
|
|
114
|
+
* @returns {boolean} `true` — бінарник знайдено, `false` — відсутній
|
|
111
115
|
*/
|
|
112
116
|
function preflight(dep) {
|
|
113
117
|
if (resolvePreflightBin(dep)) {
|
package/schemas/n-cursor.json
CHANGED
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
},
|
|
58
58
|
"claude-config": {
|
|
59
59
|
"type": "boolean",
|
|
60
|
-
"description": "Чи синхронізувати `.claude/settings.json` (hooks + permissions, merge зі збереженням користувацьких полів)
|
|
60
|
+
"description": "Чи синхронізувати `.claude/settings.json` (hooks + permissions, merge зі збереженням користувацьких полів) і slash-команди checks. За замовчуванням true.",
|
|
61
61
|
"default": true
|
|
62
62
|
}
|
|
63
63
|
},
|
package/scripts/auto-rules.mjs
CHANGED
|
@@ -32,6 +32,7 @@ export const AUTO_RULE_ORDER = Object.freeze([
|
|
|
32
32
|
'capacitor',
|
|
33
33
|
'changelog',
|
|
34
34
|
'docker',
|
|
35
|
+
'efes',
|
|
35
36
|
'ga',
|
|
36
37
|
'graphql',
|
|
37
38
|
'hasura',
|
|
@@ -106,6 +107,7 @@ export const AUTO_RULE_DEPENDENCIES = Object.freeze(
|
|
|
106
107
|
)
|
|
107
108
|
|
|
108
109
|
const ABIE_REPOSITORY_URL_MARKER = 'https://github.com/abinbevefes/'
|
|
110
|
+
const EFES_REPOSITORY_URL_MARKER = 'https://github.com/efes-cloud/'
|
|
109
111
|
const HASURA_CONFIG_MARKER = 'metadata_directory: metadata'
|
|
110
112
|
const JS_LIKE_RE = /\.(?:mjs|cjs|js|jsx|ts|tsx)$/iu
|
|
111
113
|
const REGO_RE = /\.rego$/iu
|
|
@@ -605,6 +607,7 @@ export async function detectAutoRules({
|
|
|
605
607
|
: null
|
|
606
608
|
)
|
|
607
609
|
const isAbie = typeof repositoryUrl === 'string' && repositoryUrl.toLowerCase().includes(ABIE_REPOSITORY_URL_MARKER)
|
|
610
|
+
const isEfes = typeof repositoryUrl === 'string' && repositoryUrl.toLowerCase().includes(EFES_REPOSITORY_URL_MARKER)
|
|
608
611
|
const depHits = await collectDependencyKeysPresentInPackageJsonTree(root, [
|
|
609
612
|
'mssql',
|
|
610
613
|
'pg',
|
|
@@ -639,6 +642,7 @@ export async function detectAutoRules({
|
|
|
639
642
|
{ enabled: packageJsonExists, id: 'bun' },
|
|
640
643
|
{ enabled: facts.hasCapacitorConfig, id: 'capacitor' },
|
|
641
644
|
{ enabled: facts.hasDockerfile, id: 'docker' },
|
|
645
|
+
{ enabled: isEfes, id: 'efes' },
|
|
642
646
|
{ enabled: facts.hasGaWorkflowsDir, id: 'ga' },
|
|
643
647
|
{ enabled: facts.hasGqlTaggedTemplates, id: 'graphql' },
|
|
644
648
|
{ enabled: facts.hasHasuraConfig, id: 'hasura' },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Синхронізує конфігурацію Claude Code (`.claude/settings.json`,
|
|
2
|
+
* Синхронізує конфігурацію Claude Code (`.claude/settings.json`,
|
|
3
3
|
* slash-команди для checks, ADR Stop-hook) і Cursor hooks (`.cursor/hooks.json`)
|
|
4
4
|
* у поточний проєкт із темплейтів пакету
|
|
5
5
|
* `npm/.claude-template/`.
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
* - `settings.json` — **merge**: користувацькі поля зберігаються; наші hooks
|
|
9
9
|
* ідентифікуються командою-маркером (`MANAGED_HOOK_COMMAND_MARKERS`) і
|
|
10
10
|
* перезаписуються; permissions.allow зливається через union (із дедублікацією).
|
|
11
|
-
* - `npm/CLAUDE.md` — **fully owned**: завжди перезаписується; пропускається,
|
|
12
|
-
* якщо в проєкті немає каталогу `npm/`.
|
|
13
11
|
* - `.claude/commands/n-check.md` — fully owned slash-команда.
|
|
14
12
|
* - `.claude/hooks/capture-decisions.sh` — fully owned bash-скрипт ADR capture Stop-hook;
|
|
15
13
|
* копіюється з `.claude-template/hooks/`, лише коли в `.n-cursor.json` `rules`
|
|
@@ -52,7 +50,6 @@ const CURSOR_DIR = '.cursor'
|
|
|
52
50
|
const CURSOR_HOOKS_FILE = `${CURSOR_DIR}/hooks.json`
|
|
53
51
|
const ADR_HOOK_SCRIPT_NAME = 'capture-decisions.sh'
|
|
54
52
|
const ADR_NORMALIZE_HOOK_SCRIPT_NAME = 'normalize-decisions.sh'
|
|
55
|
-
const NPM_CLAUDE_MD_FILE = 'npm/CLAUDE.md'
|
|
56
53
|
const TEMPLATE_DIR_NAME = '.claude-template'
|
|
57
54
|
|
|
58
55
|
/** Канонічна група hooks для ADR capture Stop-hook'а — додається в settings, коли `adr` у `rules`. */
|
|
@@ -390,25 +387,6 @@ export function syncAdrNormalizeHookScript(projectRoot, templateDir) {
|
|
|
390
387
|
return syncHookScript(projectRoot, templateDir, ADR_NORMALIZE_HOOK_SCRIPT_NAME)
|
|
391
388
|
}
|
|
392
389
|
|
|
393
|
-
/**
|
|
394
|
-
* Копіює `npm/CLAUDE.md` з темплейту, якщо в проєкті є каталог `npm/`.
|
|
395
|
-
* @param {string} projectRoot корінь проєкту, куди писати
|
|
396
|
-
* @param {string} templateDir каталог `.claude-template/` усередині пакету `@nitra/cursor`
|
|
397
|
-
* @returns {Promise<{ written: boolean, path: string }>} результат: чи писали файл, та його відносний шлях
|
|
398
|
-
*/
|
|
399
|
-
export async function syncNpmClaudeMd(projectRoot, templateDir) {
|
|
400
|
-
if (!existsSync(join(projectRoot, 'npm'))) {
|
|
401
|
-
return { written: false, path: '' }
|
|
402
|
-
}
|
|
403
|
-
const templatePath = join(templateDir, 'npm-CLAUDE.md')
|
|
404
|
-
if (!existsSync(templatePath)) {
|
|
405
|
-
return { written: false, path: '' }
|
|
406
|
-
}
|
|
407
|
-
const content = await readFile(templatePath, 'utf8')
|
|
408
|
-
await writeFile(join(projectRoot, NPM_CLAUDE_MD_FILE), content, 'utf8')
|
|
409
|
-
return { written: true, path: NPM_CLAUDE_MD_FILE }
|
|
410
|
-
}
|
|
411
|
-
|
|
412
390
|
/**
|
|
413
391
|
* Копіює всі slash-команди з `templateDir/commands/` у `.claude/commands/`.
|
|
414
392
|
* Команди ідентифікуються тим, що вони лежать у темплейті — не перетинаються
|
|
@@ -444,14 +422,13 @@ export async function syncClaudeCommands(projectRoot, templateDir) {
|
|
|
444
422
|
* @param {string} options.bundledPackageRoot корінь установленого `@nitra/cursor`
|
|
445
423
|
* @param {boolean} options.enabled чи увімкнено sync (з `.n-cursor.json` `claude-config`)
|
|
446
424
|
* @param {string[]} [options.rules] список увімкнених правил із `.n-cursor.json` — впливає на ADR Stop-hook (`adr`)
|
|
447
|
-
* @returns {Promise<{ settings: boolean, cursorHooks: boolean,
|
|
425
|
+
* @returns {Promise<{ settings: boolean, cursorHooks: boolean, commands: string[], adrHook: boolean, adrNormalizeHook: boolean }>} прапорці записів settings/Cursor hooks/ADR-hook(s) та список записаних slash-команд
|
|
448
426
|
*/
|
|
449
427
|
export async function syncClaudeConfig({ projectRoot, bundledPackageRoot, enabled, rules = [] }) {
|
|
450
428
|
if (!enabled) {
|
|
451
429
|
return {
|
|
452
430
|
settings: false,
|
|
453
431
|
cursorHooks: false,
|
|
454
|
-
npmClaudeMd: false,
|
|
455
432
|
commands: [],
|
|
456
433
|
adrHook: false,
|
|
457
434
|
adrNormalizeHook: false
|
|
@@ -462,7 +439,6 @@ export async function syncClaudeConfig({ projectRoot, bundledPackageRoot, enable
|
|
|
462
439
|
return {
|
|
463
440
|
settings: false,
|
|
464
441
|
cursorHooks: false,
|
|
465
|
-
npmClaudeMd: false,
|
|
466
442
|
commands: [],
|
|
467
443
|
adrHook: false,
|
|
468
444
|
adrNormalizeHook: false
|
|
@@ -475,12 +451,10 @@ export async function syncClaudeConfig({ projectRoot, bundledPackageRoot, enable
|
|
|
475
451
|
: { written: false, path: '' }
|
|
476
452
|
const settings = await syncClaudeSettings(projectRoot, templateDir, { includeAdrHook })
|
|
477
453
|
const cursorHooks = await syncCursorHooksConfig(projectRoot, { includeAdrHook })
|
|
478
|
-
const npmClaudeMd = await syncNpmClaudeMd(projectRoot, templateDir)
|
|
479
454
|
const commands = await syncClaudeCommands(projectRoot, templateDir)
|
|
480
455
|
return {
|
|
481
456
|
settings: settings.written,
|
|
482
457
|
cursorHooks: cursorHooks.written,
|
|
483
|
-
npmClaudeMd: npmClaudeMd.written,
|
|
484
458
|
commands,
|
|
485
459
|
adrHook: adrHook.written,
|
|
486
460
|
adrNormalizeHook: adrNormalizeHook.written
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: n-efes-create-env
|
|
3
|
+
description: >-
|
|
4
|
+
Створення нового середовища (env) в репозиторії efes/manager — приймає назву
|
|
5
|
+
середовища як аргумент (наприклад `kz`, `kz-qa`, `tr-stage`, `ua-dev`).
|
|
6
|
+
Генерує .env.prod-<env>, .env.remote-<env>, оверлей site/k8s/<env>/,
|
|
7
|
+
додає скрипт start-remote-<env> у site/package.json і реєструє <env> у
|
|
8
|
+
списках branches GitHub Actions та Azure Pipelines. Якщо назва закінчується
|
|
9
|
+
на dev або -qa — non-production (база: md-qa); інакше — production (база: md).
|
|
10
|
+
Тригери: «створи середовище», «новий env», «add environment», «n-efes-create-env».
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# n-efes-create-env — створення нового середовища
|
|
14
|
+
|
|
15
|
+
Скіл генерує всі конфіги для нового середовища `manager`, спираючись на існуюче як шаблон. Запуск: `/n-efes-create-env <env>` або «створи середовище `<env>`».
|
|
16
|
+
|
|
17
|
+
## Існуючі середовища (станом на створення скіла)
|
|
18
|
+
|
|
19
|
+
`dev` · `md` · `md-qa` · `tr` · `tr-qa`
|
|
20
|
+
|
|
21
|
+
## Аргумент
|
|
22
|
+
|
|
23
|
+
Назва середовища — `$ARGUMENTS` (kebab-case, без пробілів). Якщо аргументу немає — спитай користувача.
|
|
24
|
+
|
|
25
|
+
## Класифікація та джерело
|
|
26
|
+
|
|
27
|
+
| Закінчення | Тип | Базове середовище | Базовий домен |
|
|
28
|
+
| --------------- | -------------- | ----------------- | --------------------------- |
|
|
29
|
+
| `dev` або `-qa` | non-production | `md-qa` | `mayamd-qa.anadoluefes.com` |
|
|
30
|
+
| інше | production | `md` | `mayamd.anadoluefes.com` |
|
|
31
|
+
|
|
32
|
+
Перед роботою зафіксуй у себе:
|
|
33
|
+
|
|
34
|
+
- `ENV` — `$ARGUMENTS`
|
|
35
|
+
- `BASE` — `md-qa` або `md` згідно з таблицею вище
|
|
36
|
+
- `BASE_DOMAIN` — домен бази
|
|
37
|
+
- `DOMAIN` — `maya${ENV}.anadoluefes.com` (шаблон: префікс `maya` + env). Якщо ENV вже містить країну з дефісом (наприклад `kz-qa`) — домен буде `mayakz-qa.anadoluefes.com`. Якщо користувач хоче інший домен — підтверди.
|
|
38
|
+
- `COUNTRY` — країна без суфіксу `-qa`/`-dev`/`-stage` (наприклад `kz-qa` → `kz`). Потрібно для ACR-шляхів.
|
|
39
|
+
|
|
40
|
+
## Кроки
|
|
41
|
+
|
|
42
|
+
### 0. Перевірити, що середовище ще не існує
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
test ! -f site/.env.prod-$ENV \
|
|
46
|
+
&& test ! -f site/.env.remote-$ENV \
|
|
47
|
+
&& test ! -d site/k8s/$ENV \
|
|
48
|
+
|| { echo "Середовище $ENV вже існує — припини"; exit 1; }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 1. Інтерактивне опитування — зібрати country-specific дані
|
|
52
|
+
|
|
53
|
+
**ОБОВ'ЯЗКОВО** перед будь-якими `cp`/`sed` запитай користувача через `AskUserQuestion` (у Cursor — звичайним повідомленням з варіантами). Не виконуй кроки 2–5, поки не отримав усі відповіді.
|
|
54
|
+
|
|
55
|
+
Запитай **одним викликом** `AskUserQuestion` із кількома запитаннями:
|
|
56
|
+
|
|
57
|
+
1. **Тип середовища** — заголовок «Тип env»:
|
|
58
|
+
- «Нова країна» — env вводить нову країну (новий VITE_COUNTRY, своя SAP-tenant, свій бакет)
|
|
59
|
+
- «Новий етап існуючої країни» — env є додатковим етапом md/tr (інший суфікс, але та сама країна та tenant)
|
|
60
|
+
|
|
61
|
+
2. **Домен** — заголовок «Domain»:
|
|
62
|
+
- `maya${ENV}.anadoluefes.com` (default, рекомендований)
|
|
63
|
+
- «Інший» — користувач введе власний
|
|
64
|
+
|
|
65
|
+
3. **SAP-credentials** — заголовок «SAP auth»:
|
|
66
|
+
- «Залишити як у бази (`$BASE`)» — для нових етапів існуючої країни
|
|
67
|
+
- «Заглушки `TODO_SAP_*`» — для нової країни, реальні значення додасть devops/security окремим commit
|
|
68
|
+
- «Введу зараз» — користувач передасть значення в `Other` (формат: `ENDPOINT=…; CLIENT_ID=…; CLIENT_SECRET=…`)
|
|
69
|
+
|
|
70
|
+
4. **Storage account (`VITE_BUCKET`)** — заголовок «Bucket»:
|
|
71
|
+
- «Залишити як у бази» — той самий storage account (`stmdmayasfaprod001`/`stmdmayasfadev001`)
|
|
72
|
+
- «Власний для нової країни» — користувач введе ім'я storage account в `Other` (наприклад `stkzmayasfaprod001`)
|
|
73
|
+
|
|
74
|
+
Якщо «Нова країна» — окремо (у тому ж або наступному виклику) запитай:
|
|
75
|
+
|
|
76
|
+
5. **VITE_COUNTRY** — заголовок «Country»: `md`, `tr`, інше (через `Other`)
|
|
77
|
+
6. **VITE_TFM_DEFAULT** — заголовок «TFM default»: `ru`, `en`, `tr`, `ro`, інше
|
|
78
|
+
7. **VITE_TFM_LIST** — заголовок «TFM list»: набір популярних варіантів (`ru,en,ro,tr`, `en,tr`, `ru,en`) + `Other`
|
|
79
|
+
|
|
80
|
+
Збережи відповіді у змінні `DOMAIN`, `COUNTRY`, `TFM_DEFAULT`, `TFM_LIST`, `BUCKET_ACCOUNT`, `SAP_MODE` (`keep`/`stub`/`custom`), `SAP_VALUES` (якщо `custom`).
|
|
81
|
+
|
|
82
|
+
### 2. Створити `.env.prod-$ENV` та `.env.remote-$ENV`
|
|
83
|
+
|
|
84
|
+
Скопіюй файли бази:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
cp site/.env.prod-$BASE site/.env.prod-$ENV
|
|
88
|
+
cp site/.env.remote-$BASE site/.env.remote-$ENV
|
|
89
|
+
|
|
90
|
+
# домен
|
|
91
|
+
sed -i '' "s|$BASE_DOMAIN|$DOMAIN|g" site/.env.prod-$ENV site/.env.remote-$ENV
|
|
92
|
+
|
|
93
|
+
# bucket path (maya-files-<base> → maya-files-$ENV)
|
|
94
|
+
sed -i '' "s|maya-files-$BASE|maya-files-$ENV|g" site/.env.prod-$ENV site/.env.remote-$ENV
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Далі **застосуй відповіді з кроку 1** (через `Edit`):
|
|
98
|
+
|
|
99
|
+
- Якщо `BUCKET_ACCOUNT` != base — заміни storage account host у `VITE_BUCKET`.
|
|
100
|
+
- Якщо тип = «Нова країна»:
|
|
101
|
+
- `VITE_COUNTRY=$COUNTRY`
|
|
102
|
+
- `VITE_TFM_DEFAULT=$TFM_DEFAULT`
|
|
103
|
+
- `VITE_TFM_LIST=$TFM_LIST`
|
|
104
|
+
- Якщо `SAP_MODE=stub` — заміни значення на:
|
|
105
|
+
- `VITE_SAP_AUTH_ENDPOINT=TODO_SAP_ENDPOINT`
|
|
106
|
+
- `VITE_SAP_AUTH_CLIENT_ID='TODO_SAP_CLIENT_ID'`
|
|
107
|
+
- `VITE_SAP_AUTH_CLIENT_SECRET=TODO_SAP_CLIENT_SECRET`
|
|
108
|
+
- Якщо `SAP_MODE=custom` — підстав `SAP_VALUES`.
|
|
109
|
+
|
|
110
|
+
Інваріанти, які мають лишитися після всіх правок:
|
|
111
|
+
|
|
112
|
+
- У `.env.remote-$ENV` — `VITE_DOMAIN=localhost`, `VITE_UPLOADER=/file-link/`, `VITE_EXPORT_EXCEL=/export-table/`.
|
|
113
|
+
- У `.env.prod-$ENV` — `VITE_DOMAIN=$DOMAIN`, `VITE_UPLOADER=https://$DOMAIN/file-link/`, `VITE_EXPORT_EXCEL=https://$DOMAIN/export-table/`.
|
|
114
|
+
|
|
115
|
+
### 2. Створити `site/k8s/$ENV/kustomization.yaml`
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
mkdir -p site/k8s/$ENV
|
|
119
|
+
cp site/k8s/$BASE/kustomization.yaml site/k8s/$ENV/kustomization.yaml
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Відредагуй новий файл:
|
|
123
|
+
|
|
124
|
+
- `namespace: $ENV`
|
|
125
|
+
- `images[].newName`:
|
|
126
|
+
- **production** → `aefes.azurecr.io/mayasfa-$ENV/$ENV/manager-site`
|
|
127
|
+
- **non-production** → `aefes.azurecr.io/mayasfa-$COUNTRY-dev/$ENV/manager-site`
|
|
128
|
+
- `HTTPRoute` патч → `hostnames: ["$DOMAIN"]`
|
|
129
|
+
- Для **production** залиш блок `components: [../components]` (HPA/PDB).
|
|
130
|
+
- Для **non-production** видали `components` блок і HPA/PDB-патчі (як у `md-qa`).
|
|
131
|
+
|
|
132
|
+
Перевір: запусти `kubectl kustomize site/k8s/$ENV --output /dev/null` (якщо `kubectl` доступний) — має пройти без помилок.
|
|
133
|
+
|
|
134
|
+
### 3. Додати `start-remote-$ENV` у `site/package.json`
|
|
135
|
+
|
|
136
|
+
У секцію `"scripts"` додай рядок (зберігай порядок поряд із сусідніми `start-remote-*`):
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{ "scripts": { "start-remote-$ENV": "vite dev --mode remote-$ENV" } }
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 4. Зареєструвати `$ENV` у CI/CD branch-списках
|
|
143
|
+
|
|
144
|
+
Додай `$ENV` у такі місця (зберігай існуючий порядок: dev → md-qa → md → tr → tr-qa → нові):
|
|
145
|
+
|
|
146
|
+
| Файл | Поле |
|
|
147
|
+
| ------------------------------------------- | ------------------------------ |
|
|
148
|
+
| `.github/workflows/sync-to-azure.yml` | `on.push.branches` |
|
|
149
|
+
| `.github/workflows/clean-merged-branch.yml` | `ignore_branches` (через кому) |
|
|
150
|
+
| `.azurepipelines/apply-k8s.yml` | `trigger.branches.include` |
|
|
151
|
+
| `.azurepipelines/site.yml` | `trigger.branches.include` |
|
|
152
|
+
|
|
153
|
+
Якщо існують інші `**/k8s/`-проекти у репозиторії — переконайся, що `$ENV` потрібен і там (на момент створення скіла є тільки `site/k8s/`).
|
|
154
|
+
|
|
155
|
+
### 5. Попередження користувачу про зовнішні залежності
|
|
156
|
+
|
|
157
|
+
Скіл **не** створює ці артефакти — повідом про них користувача:
|
|
158
|
+
|
|
159
|
+
- У repo `MayaSFA/k8s` має існувати шаблон `.azurepipelines/azure-pipeline-templates/$ENV.yml` (його використовує `apply-k8s.yml` і `site.yml`).
|
|
160
|
+
- Гілка `$ENV` має бути створена в обох remote (GitHub + Azure DevOps).
|
|
161
|
+
- DNS-запис для `$DOMAIN` та health-check у gateway мають бути налаштовані відповідною командою.
|
|
162
|
+
- Якщо ENV — нова країна: ACR-репозиторій `mayasfa-$ENV` (для prod) або `mayasfa-$COUNTRY-dev` (для non-prod) має бути створений.
|
|
163
|
+
|
|
164
|
+
### 6. Перевірка результату
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
ls site/.env.prod-$ENV site/.env.remote-$ENV site/k8s/$ENV/kustomization.yaml
|
|
168
|
+
grep -n "$ENV" \
|
|
169
|
+
.github/workflows/sync-to-azure.yml \
|
|
170
|
+
.github/workflows/clean-merged-branch.yml \
|
|
171
|
+
.azurepipelines/apply-k8s.yml \
|
|
172
|
+
.azurepipelines/site.yml \
|
|
173
|
+
site/package.json
|
|
174
|
+
git status
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Виведи користувачу короткий звіт: що створено, що змінено, які зовнішні дії потрібні (з кроку 5). **Не комітити автоматично** — користувач сам перегляне через `git diff` і закомітить.
|
|
178
|
+
|
|
179
|
+
## Нюанси та пастки
|
|
180
|
+
|
|
181
|
+
- **Доменний шаблон `maya${ENV}.anadoluefes.com`** працює для існуючих країн (md/tr). Якщо нова країна має інший публічний URL — підтверди в користувача _до_ запуску `sed`.
|
|
182
|
+
- **ACR-шлях суворо за шаблоном**: prod → `mayasfa-$ENV/$ENV/manager-site`, non-prod → `mayasfa-$COUNTRY-dev/$ENV/manager-site`. Жодних додаткових сегментів між ACR-namespace та `$ENV` бути не повинно.
|
|
183
|
+
- **`ENV=dev`**: гілка `dev` — спеціальний випадок (вживає `base/`, без оверлею). Скіл не призначений для перестворення `dev`.
|
|
184
|
+
- **`.env.development`** — лише для локального запуску без бекенду; скіл його не чіпає.
|
|
185
|
+
- **Не запускай `bun run lint` / `lint-ga`** в один потік з іншими — дивись CLAUDE.md «Лінт і ESLint». Перевір лише потрібний файл (`bunx eslint <path>` або точково).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[efes]
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<!-- Файл генерується автоматично через `npx @nitra/cursor`. Не редагуй вручну. -->
|
|
2
|
-
|
|
3
|
-
# Робота в `npm/`
|
|
4
|
-
|
|
5
|
-
Path-scoped нагадування для агента: підвантажується автоматично, коли редагуємо файли під `npm/`.
|
|
6
|
-
|
|
7
|
-
## Перед PR з коміт-релевантними змінами в `npm/`
|
|
8
|
-
|
|
9
|
-
1. Підвищ `version` у `npm/package.json` (build-bump, не більше одного кроку відносно `HEAD`).
|
|
10
|
-
2. Додай запис у `npm/CHANGELOG.md` форматом Keep a Changelog: `## [версія] - YYYY-MM-DD` + секції `### Added/Changed/Fixed/Removed`.
|
|
11
|
-
3. Переконайся, що `"CHANGELOG.md"` є в масиві `files` у `npm/package.json` (правило `changelog`).
|
|
12
|
-
|
|
13
|
-
Логіка PR-scoped: bump і запис достатньо зробити **один раз — як суму по всьому PR** (порівняння йде з гілкою `dev`), а не на кожен коміт.
|
|
14
|
-
|
|
15
|
-
Без оновленого CHANGELOG `npx @nitra/cursor check changelog` падає, а `Stop` hook блокує завершення ходу.
|
|
16
|
-
|
|
17
|
-
## Перевірка локально
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npx @nitra/cursor check changelog
|
|
21
|
-
npx @nitra/cursor check npm-module
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Перш ніж писати / розширювати `check-*.mjs`
|
|
25
|
-
|
|
26
|
-
**STOP — спершу пройди алгоритм Rego-first** (`.cursor/rules/conftest.mdc`, alwaysApply). Це стосується **і нової** перевірки, **і додавання нового deny у вже існуючий** `check-<rule>.mjs`: подивись `npm/policy/<rule>/`, чи задача не лягає у вже існуючий rego-пакет як ще одне `deny contains`.
|
|
27
|
-
|
|
28
|
-
Швидкий self-check для нової перевірки (порядок важливий):
|
|
29
|
-
|
|
30
|
-
1. **Це пер-документна перевірка одного JSON/YAML?** (наявність / форма поля, regex по значенню, перелік дозволених літералів). → **Rego, без JS-коду.** Пиши у `npm/policy/<rule>/<name>/<name>.rego` + `<name>_test.rego`.
|
|
31
|
-
2. Потрібен `readdir`, `stat`, парність файлів, AST-парсинг JS/TS, autofix, modeline до YAML-body? → **JS** у `check-<rule>.mjs`. Per-document частина (якщо є) усе одно лишається у rego — JS викликає її через `runConftestBatch`.
|
|
32
|
-
3. Не впевнений? Подивись референс **`npm/policy/k8s/*`** ↔ **`npm/scripts/check-k8s.mjs`** (Plan B: Rego-authoritative + JS-orchestrator) і список «що Rego об'єктивно не вміє» у `conftest.mdc`.
|
|
33
|
-
|
|
34
|
-
**Червоний прапор:** дописуєш `if (pkg.<field>) fail(…)` у JS — майже завжди це варто було робити як `deny contains msg if { … }` у відповідному rego-пакеті. Перевір `npm/policy/<rule>/` **перед** редагуванням `check-<rule>.mjs`.
|
|
35
|
-
|
|
36
|
-
## Джерело правил
|
|
37
|
-
|
|
38
|
-
- `.cursor/rules/n-changelog.mdc` — правило про CHANGELOG (PR-scoped, для всіх воркспейсів)
|
|
39
|
-
- `.cursor/rules/n-npm-module.mdc` — правило публікації пакета (типи, hk, npm-publish workflow)
|
|
40
|
-
- `npm/scripts/check-changelog.mjs`, `npm/scripts/check-npm-module.mjs` — алгоритми перевірки
|