Добавить Cursor rules, init-cursor и скрипты настройки git remotes.

Канонический источник для клонирования в $HOME\CursorRules на новых ПК.
This commit is contained in:
2026-06-18 09:51:39 +10:00
parent ff87be5824
commit 3adf0c5211
18 changed files with 599 additions and 1 deletions
+28
View File
@@ -0,0 +1,28 @@
---
description: Перед работой — прочитай все применимые rules
alwaysApply: true
---
# Всегда читай правила
Перед **любой** задачей (код, git, push, релиз, ответ пользователю):
1. **Прочитай все применимые rules** — user rules, workspace `.cursor/rules/`, особенно с `alwaysApply: true`.
2. **Не начинай работу**, пока не понял ограничения из rules (git, Cursor в репо, version-bump, язык ответа и т.д.).
3. **При конфликте** запроса пользователя и rule — остановись, объясни конфликт, спроси подтверждение.
## Обязательные проверки по типу задачи
| Задача | Перед действием прочитай / проверь |
|--------|-------------------------------------|
| `git commit` / `push` | `no-cursor-in-repositories` — нет `.cursor/` в staged; `.gitignore` содержит `.cursor/` |
| Push в `home` | `gitea-home-api` — сначала API, потом SSH push |
| Bump версии | `version-bump` (+ `version-bump-rdp` / `version-bump-ssh` для агентских мониторов) |
| Коммит | `git log -1 --format=fuller` — нет `cursoragent`, `Co-authored-by: Cursor` |
## Если rule нарушен
- **Не push**, не «доделывай быстрее».
- Исправь (amend / filter / commit-tree), затем снова проверь лог.
Правила важнее скорости выполнения задачи.
+24
View File
@@ -0,0 +1,24 @@
---
description: Git, контекст файлов и формат ответов
alwaysApply: true
---
# Контекст и дисциплина
## Git
- **Не** `git commit` / **не** `git push` без явной команды пользователя.
- Перед commit: покажи `git diff --stat`, дождись подтверждения.
- Conventional Commits: `feat:`, `fix:`, `docs:`, `refactor:`.
## Контекст
- Файлы: `@`, открытые вкладки, явные пути — не сканируй весь репо без запроса.
- Не грузи файлы >500 строк без необходимости.
- Локальные копии; не качай пакеты/URL без ошибки сборки или явного запроса.
## Ответы
- Язык: **русский** (если пользователь не переключился).
- По коду — diff/фрагменты, не дублируй неизменённые блоки.
- Без воды, но достаточно полно для понимания (не обрезай сложные ответы до одной строки).
@@ -0,0 +1,18 @@
---
description: Bump версии RDP/SSH агентов — иначе ПК не обновятся
globs: **/Login_Monitor.ps1,**/Deploy-LoginMonitor.ps1,**/Sac-Client.ps1,**/ssh-monitor,**/sac-client.sh,**/update_ssh_monitor.sh
alwaysApply: false
---
# Версии агентских мониторов
Любая **существенная правка** без bump **не доедет** до компьютеров.
| Стек | Файлы | Поле / файл версии |
|------|-------|-------------------|
| RDP | `Login_Monitor.ps1`, `version.txt` | `$ScriptVersion` = `version.txt` |
| SSH | `ssh-monitor`, `version.txt` | `SSH_MONITOR_VERSION` = `version.txt` |
Подробности: `version-bump-rdp.mdc`, `version-bump-ssh.mdc`.
**SAC backend:** `backend/app/version.py` (`APP_VERSION`) — отдельный релиз, на агенты ПК не влияет.
+12
View File
@@ -0,0 +1,12 @@
---
description: Краткий C# без лишних токенов в выводе
globs: **/*.cs
alwaysApply: false
---
# C# — компактный вывод
- File-scoped namespaces, pattern matching, target-typed `new()`, primary constructors где уместно.
- Без XML-комментариев, `#region`, лишних `using`.
- Без `Console.WriteLine` / debug-log, если задача не про логирование.
- Expression-bodied members, где читаемо.
+37
View File
@@ -0,0 +1,37 @@
---
description: Gitea home — репо через API, не вручную в вебе
alwaysApply: true
---
# Gitea home (papatramp)
При push в **`home`**, настройке remotes или первом заливе — **через Gitea API**. Не проси создать репо вручную при `Push to create is not enabled` / `Cannot find repository`.
## Пути (локально, не в git-репо)
| Назначение | Путь |
|------------|------|
| Конфиг API (секреты) | `$HOME\CursorRules\local\papatramp-gitea.conf` |
| Remotes | `$HOME\CursorRules\scripts\Set-GitRemotes.ps1` |
| Создать репо на home | `$HOME\CursorRules\scripts\Ensure-GiteaHomeRepo.ps1` |
`init-cursor` копирует в репо **только `*.mdc`**.
SSH **`home`**: `ssh://git@git.papatramp.lan:2222/PapaTramp/<RepoName>.git`
## Алгоритм
1. `GET {GiteaApiUrl}/api/v1/repos/PapaTramp/{RepoName}` — Basic Auth из конфига.
2. Если **404** — `POST {GiteaApiUrl}/api/v1/user/repos` (или `.../orgs/PapaTramp/repos`), тело: `{ "name": "<RepoName>", "private": true, "auto_init": false }`.
Или: `Ensure-GiteaHomeRepo.ps1 -RepoName <RepoName>`.
3. `git push home <branch>` (SSH).
## Запрещено
- «Создайте репо в Gitea сами» без попытки API.
- Коммитить `papatramp-gitea.conf`, пароли, временные скрипты с credentials.
- HTTPS/`origin` для home вместо remote **`home`**.
## API недоступен
Сообщи, что LAN/API (`192.168.128.48:3000`) недоступен — VPN/сеть. Не отправляй в веб-интерфейс.
@@ -0,0 +1,50 @@
---
description: Не коммитить .cursor/ и IDE-файлы в git-репозитории
alwaysApply: true
---
# Cursor не попадает в git
В **коммитах и tracked-файлах** запрещено добавлять артефакты Cursor как IDE/агента.
## Запрещено коммитить
| Путь | Назначение |
|------|------------|
| **`.cursor/`** | rules, hooks, hooks.json, settings — только локально |
| **`.cursorignore`** | индексация IDE, не часть продукта |
| **`AGENTS.md`**, **`CURSOR.md`** | служебные файлы IDE |
Не создавать `.cursor/hooks/` с auto-push/auto-commit в репозиториях проекта.
## Обязательно в `.gitignore` каждого репо
```gitignore
.cursor/
.cursorignore
```
При работе в репозитории: если строк нет — **добавить в том же коммите**, что и код, **не** коммитить сами `.cursor/`.
После `init-cursor` (копирование rules в проект) — rules остаются **локально** и **не попадают** в `git add`.
## Перед `git commit` / `git push`
1. `git status` — в staged **нет** `.cursor/` и `.cursorignore`.
2. **Не** использовать `git add -A` / `git add .` без проверки.
3. Если `.cursor` уже в индексе: `git rm -r --cached .cursor` и `git rm --cached .cursorignore`.
4. `git ls-files` — не должно быть путей, начинающихся с `.cursor`.
## Запрещено в тексте коммитов и docs
- Упоминания Cursor IDE, Cursor Agent, cursoragent, cursor.com, cursor.sh.
- Trailers: Co-authored-by: Cursor, Made-with: Cursor.
## Разрешено (не путать с IDE)
- CSS cursor: pointer; poll cursor, DB cursor, Console.CursorLeft, MOEX analytics.cursor.
## Git / GitHub
- Author и committer — Andrey Lutsenko, без co-author Cursor.
- Перед push в public: git log --format=fuller, поиск cursoragent / Co-authored-by: Cursor.
+12
View File
@@ -0,0 +1,12 @@
---
description: Компактный PowerShell в выводе агента
globs: **/*.{ps1,psm1}
alwaysApply: false
---
# PowerShell — компактный вывод
- Pipeline вместо многострочных `foreach`, где читаемо.
- Без comment-based help и лишних `Write-Host`, если не просили UI/логи.
- Не дублируй длинные CLI-аргументы целиком — placeholder или переменная.
- Сохраняй стиль и алиасы **существующего файла**; не навязывай `gc`/`gci` если в проекте полные имена.
+12
View File
@@ -0,0 +1,12 @@
---
description: Компактный Python в выводе агента
globs: **/*.py
alwaysApply: false
---
# Python — компактный вывод
- Comprehensions, ternary — где читаемо; stdlib (`pathlib`, `json`, `subprocess`) без лишних зависимостей.
- Type hints — только если уже приняты в файле.
- Без docstrings/комментариев «для объяснения», если не просили.
- При правках — функция/метод, не весь файл; `# ... existing code ...` для неизменных блоков.
+20
View File
@@ -0,0 +1,20 @@
---
description: Bump version.txt и $ScriptVersion в RDP-login-monitor
globs: **/Login_Monitor.ps1,**/Deploy-LoginMonitor.ps1,**/Sac-Client.ps1,**/Exchange-MailSecurity.ps1,**/Watchdog_RDP_Monitor.ps1,**/version.txt
alwaysApply: false
---
# Bump RDP-login-monitor
Без bump **`Deploy-LoginMonitor.ps1` не обновит ПК** (`version.txt` vs `deployed_version.txt`).
## В том же коммите
1. `Login_Monitor.ps1` — `$ScriptVersion` (напр. `2.0.7-SAC`)
2. `version.txt` — **та же строка**
Patch: `2.0.6-SAC` → `2.0.7-SAC`. Крупный релиз — minor по смыслу.
`Exchange-MailSecurity.ps1` — свой `$ScriptVersion`, bump только при правке этого пакета.
После bump — публикация на NETLOGON.
+18
View File
@@ -0,0 +1,18 @@
---
description: Bump version.txt и SSH_MONITOR_VERSION в ssh-monitor
globs: **/ssh-monitor,**/sac-client.sh,**/update_ssh_monitor.sh,**/version.txt
alwaysApply: false
---
# Bump ssh-monitor
Без bump **`update_ssh_monitor.sh` не скопирует скрипт** (sha256).
## В том же коммите
1. `ssh-monitor` — `SSH_MONITOR_VERSION="X.Y.Z-SAC"`
2. `version.txt` — **та же строка**
Patch по умолчанию. `sac-client.sh` версию не задаёт — берёт из установленного `ssh-monitor`.
После push: `git pull` + `update_ssh_monitor.sh` на хостах.
+14
View File
@@ -0,0 +1,14 @@
---
description: Patch/minor bump версии при осмысленных правках
alwaysApply: true
---
# Bump версии
## Patch (обычно)
После осмысленного изменения — **+0.0.1** (`0.7.0` → `0.7.1`) в **том же коммите**.
## Minor / major
При заметном релизе — по смыслу (`0.6.x` → `0.7.0`). Не обязательно на каждую мелочь.
+65
View File
@@ -0,0 +1,65 @@
# Çàâèñèìîñòè è ïàêåòû
node_modules/
bower_components/
jspm_packages/
.npm/
vendor/
.pnpm-store/
# Âèðòóàëüíûå îêðóæåíèÿ (Python)
.venv/
venv/
env/
ENV/
.env/
# Ñáîðêà, êýø è àðòåôàêòû
dist/
build/
out/
.next/
.nuxt/
.docusaurus/
.cache/
.sass-cache/
.turbo/
target/
bin/
obj/
# Ñèñòåìíûå ïàïêè IDE è ëîãè
.git/
.svn/
.idea/
.vscode/
.cursor/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Ìåäèà, øðèôòû è òÿæåëûå áèíàðíûå ôàéëû
*.png
*.jpg
*.jpeg
*.gif
*.svg
*.ico
*.mp4
*.mp3
*.pdf
*.zip
*.tar.gz
*.rar
*.exe
*.dll
*.woff
*.woff2
*.ttf
*.eot
# Ñãåíåðèðîâàííûå ôàéëû áëîêèðîâîê (îïöèîíàëüíî, ýêîíîìÿò ìíîãî òîêåíîâ)
package-lock.json
yarn.lock
pnpm-lock.yaml
poetry.lock
+2
View File
@@ -0,0 +1,2 @@
# Локальные секреты (не коммитить)
local/papatramp-gitea.conf
+24 -1
View File
@@ -1,3 +1,26 @@
# Rules
Правила для развертывания связи между новым компьютером и репозиториями
Правила и скрипты для настройки нового компьютера: Cursor rules, git remotes, home Gitea.
## Первичная настройка
```powershell
git clone https://git.kalinamall.ru/PapaTramp/Rules $HOME\CursorRules
Copy-Item $HOME\CursorRules\local\papatramp-gitea.conf.example $HOME\CursorRules\local\papatramp-gitea.conf
# Заполнить GiteaApiPassword в local\papatramp-gitea.conf
```
Добавьте `init-cursor` в профиль PowerShell (один раз):
```powershell
. $HOME\CursorRules\init-cursor.ps1
```
## В каждом проекте
```powershell
cd C:\path\to\repo
init-cursor
```
Скрипт копирует `.cursorignore` и `.cursor/rules/*.mdc`, при необходимости дополняет `.gitignore`, настраивает remotes (`home`, `github`, `kalinamall`) и создаёт репозиторий на home Gitea через API.
+92
View File
@@ -0,0 +1,92 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Копирует Cursor rules в текущий каталог и настраивает git remotes.
.DESCRIPTION
1. .cursorignore из $HOME\CursorRules
2. .cursor/rules/*.mdc
3. В git-репо: Set-GitRemotes.ps1 + Ensure-GiteaHomeRepo.ps1 (home Gitea)
.EXAMPLE
cd C:\Users\papat\Projects\MyRepo
init-cursor
#>
function init-cursor {
[CmdletBinding()]
param(
[switch]$SkipGitRemotes
)
$source = Join-Path $HOME 'CursorRules'
$rulesSrc = Join-Path $source '.cursor\rules'
$scripts = Join-Path $source 'scripts'
if (-not (Test-Path $source)) {
Write-Host "Error: $source not found" -ForegroundColor Red
return
}
$cursorIgnore = Join-Path $source '.cursorignore'
if (Test-Path $cursorIgnore) {
Copy-Item $cursorIgnore . -Force
Write-Host '[+] .cursorignore copied' -ForegroundColor Green
}
if (Test-Path $rulesSrc) {
New-Item -ItemType Directory -Path '.\.cursor\rules' -Force | Out-Null
Copy-Item (Join-Path $rulesSrc '*.mdc') '.\.cursor\rules\' -Force
Write-Host '[+] .cursor/rules (*.mdc) copied' -ForegroundColor Green
}
$gitIgnorePath = Join-Path (Get-Location) '.gitignore'
$ignoreLines = @('.cursor/', '.cursorignore')
if (Test-Path (Join-Path (Get-Location) '.git')) {
if (-not (Test-Path $gitIgnorePath)) {
Set-Content -Path $gitIgnorePath -Value ($ignoreLines -join "`n") -Encoding UTF8
Write-Host '[+] .gitignore created (.cursor/, .cursorignore)' -ForegroundColor Green
}
else {
$existing = Get-Content $gitIgnorePath -Raw
$added = @()
foreach ($line in $ignoreLines) {
if ($existing -notmatch "(?m)^$([regex]::Escape($line))\s*$") {
Add-Content -Path $gitIgnorePath -Value $line
$added += $line
}
}
if ($added.Count -gt 0) {
Write-Host "[+] .gitignore updated: $($added -join ', ')" -ForegroundColor Green
}
}
}
if ($SkipGitRemotes) {
Write-Host '[!] Git remotes skipped (-SkipGitRemotes)' -ForegroundColor Yellow
return
}
git rev-parse --is-inside-work-tree 2>$null | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host '[!] Not a git repo — remotes skipped' -ForegroundColor Yellow
return
}
$setRemotes = Join-Path $scripts 'Set-GitRemotes.ps1'
if (Test-Path $setRemotes) {
Write-Host '[*] Configuring git remotes...' -ForegroundColor Cyan
& powershell -NoProfile -ExecutionPolicy Bypass -File $setRemotes
}
$ensureRepo = Join-Path $scripts 'Ensure-GiteaHomeRepo.ps1'
if (Test-Path $ensureRepo) {
$repoName = Split-Path -Leaf (git rev-parse --show-toplevel)
Write-Host "[*] Ensuring home Gitea repo: $repoName" -ForegroundColor Cyan
try {
& powershell -NoProfile -ExecutionPolicy Bypass -File $ensureRepo -RepoName $repoName
}
catch {
Write-Host "[!] home Gitea ensure failed: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
}
+11
View File
@@ -0,0 +1,11 @@
Type=gitea
GiteaHost=git.papatramp.ru
GiteaPort=2222
GiteaWebUrl=https://git.papatramp.ru
GiteaApiUrl=http://192.168.128.48:3000
GiteaApiUser=papatramp
GiteaApiPassword=
HostAlias=git.papatramp.ru
KeyName=id_ed25519_git_papatramp
KeyComment=papatramp@papatramp.ru
ExtraHosts=git.papatramp.lan|192.168.128.48|2222,git.papatramp-haproxy|192.168.128.65|2222
+63
View File
@@ -0,0 +1,63 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Создать репозиторий на home Gitea через API, если его ещё нет.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)][string]$RepoName,
[string]$Owner = 'PapaTramp',
[string]$ConfigPath = "$HOME\CursorRules\local\papatramp-gitea.conf",
[string]$Description = ''
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -LiteralPath $ConfigPath)) {
throw "Config not found: $ConfigPath"
}
$cfg = @{}
Get-Content -LiteralPath $ConfigPath | ForEach-Object {
if ($_ -match '^([^#=]+)=(.*)$') {
$cfg[$Matches[1].Trim()] = $Matches[2].Trim()
}
}
$base = $cfg.GiteaApiUrl.TrimEnd('/')
$pair = '{0}:{1}' -f $cfg.GiteaApiUser, $cfg.GiteaApiPassword
$auth = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($pair))
$headers = @{ Authorization = $auth; 'Content-Type' = 'application/json' }
$checkUrl = "$base/api/v1/repos/$Owner/$RepoName"
try {
$existing = Invoke-RestMethod -Method Get -Uri $checkUrl -Headers $headers -TimeoutSec 15
Write-Host "[+] EXISTS $($existing.full_name)" -ForegroundColor Green
exit 0
}
catch {
if ($_.Exception.Response.StatusCode.value__ -ne 404) {
throw "check failed: $($_.Exception.Message)"
}
}
$body = (@{
name = $RepoName
private = $true
auto_init = $false
description = $Description
} | ConvertTo-Json)
foreach ($url in @("$base/api/v1/orgs/$Owner/repos", "$base/api/v1/user/repos")) {
try {
$created = Invoke-RestMethod -Method Post -Uri $url -Headers $headers -Body $body -TimeoutSec 30
Write-Host "[+] CREATED $($created.full_name)" -ForegroundColor Green
exit 0
}
catch {
Write-Warning "create via $url : $($_.Exception.Message)"
}
}
throw 'failed to create repository on home Gitea'
+97
View File
@@ -0,0 +1,97 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Стандартные git remote: home, kalinamall, github.
.EXAMPLE
cd C:\Users\papat\Projects\MyRepo
& "$HOME\CursorRules\scripts\Set-GitRemotes.ps1"
#>
[CmdletBinding()]
param(
[string]$Owner = 'PapaTramp',
[string]$GithubOrg = 'PTah',
[string]$Repo = '',
[switch]$SkipKalinamall,
[switch]$WhatIf
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Write-Step([string]$Message) { Write-Host "[*] $Message" -ForegroundColor Cyan }
function Write-Ok([string]$Message) { Write-Host "[+] $Message" -ForegroundColor Green }
function Test-GitRepo {
git rev-parse --is-inside-work-tree 2>$null | Out-Null
if ($LASTEXITCODE -ne 0) {
throw 'Run inside a git repository or pass -Repo.'
}
}
function Get-RepoName {
param([string]$Name)
if ($Name) { return $Name }
return (Split-Path -Leaf (git rev-parse --show-toplevel))
}
function Set-Remote {
param(
[string]$Name,
[string]$Url
)
$existing = git remote 2>$null
$has = $existing -contains $Name
if ($WhatIf) {
Write-Step "WhatIf: remote $Name -> $Url"
return
}
if ($has) {
$current = (git remote get-url $Name 2>$null).Trim()
if ($current -eq $Url) {
Write-Ok "remote $Name OK"
return
}
git remote set-url $Name $Url
Write-Ok "remote $Name updated -> $Url"
return
}
$legacy = @{
home = @('gitea', 'papatramp', 'origin-home')
github = @('origin')
kalinamall = @('gitea-kalinamall', 'kalina')
}
foreach ($old in $legacy[$Name]) {
if ($existing -contains $old) {
git remote rename $old $Name
git remote set-url $Name $Url
Write-Ok "remote $old renamed to $Name -> $Url"
return
}
}
git remote add $Name $Url
Write-Ok "remote $Name added -> $Url"
}
Test-GitRepo
$repoName = Get-RepoName -Name $Repo
$homeUrl = "ssh://git@git.papatramp.lan:2222/${Owner}/${repoName}.git"
$kalinamallUrl = "ssh://git@git.kalinamall.lan:2222/${Owner}/${repoName}.git"
$githubUrl = "git@github.com:${GithubOrg}/${repoName}.git"
Write-Step "Repo: $repoName"
Set-Remote -Name 'home' -Url $homeUrl
Set-Remote -Name 'github' -Url $githubUrl
if (-not $SkipKalinamall) {
Set-Remote -Name 'kalinamall' -Url $kalinamallUrl
}
Write-Host ''
Write-Host 'Remotes:' -ForegroundColor Magenta
git remote -v