feat(install): profile-based skill gating + public skills
- prompt for profile (frontend/backend/qa/mobile) via /dev/tty (works under curl|bash); PI_KIT_PROFILE env fallback
- gate bundled skills per profile by rewriting the pi-kit entry in settings.json to object-form {source, skills:[...]}; prompts/extensions stay ungated
- install common public skills for everyone (grill-me, grill-with-docs, code-review, diagnosing-bugs from mattpocock/skills) and profile-specific (frontend-design from anthropics/skills) via npx skills add --global
- README: profiles table + gating mechanism for maintainers
Verified: gating logic (string->object, idempotent, other packages preserved), live backend-profile load via RPC (ts excluded, prompts intact), npx skills add --global lands in ~/.agents/skills without cwd pollution, all 4 common skills exist in mattpocock/skills (diagnose is 'diagnosing-bugs').
This commit is contained in:
41
README.md
41
README.md
@@ -16,11 +16,33 @@ guardrails и скиллы со знанием того, где у нас код
|
|||||||
curl -fsSL https://git.codelab.vc/ai/pi-kit/-/raw/main/install.sh | bash
|
curl -fsSL https://git.codelab.vc/ai/pi-kit/-/raw/main/install.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
Скрипт проверит Node.js (>= 20), поставит Pi (если нет), установит этот пакет и подскажет,
|
Скрипт проверит Node.js (>= 20), поставит Pi (если нет), установит этот пакет, **спросит
|
||||||
какие переменные окружения нужны (ключ вашего LLM-провайдера, `TRACKER_URL`, `JIRA_TOKEN`).
|
твой профиль**, поставит нужные скилы и подскажет, какие переменные окружения нужны
|
||||||
|
(ключ вашего LLM-провайдера, `TRACKER_URL`, `JIRA_TOKEN`).
|
||||||
Pi провайдер-агностичен — модель/провайдера пакет не навязывает, каждый выбирает свой
|
Pi провайдер-агностичен — модель/провайдера пакет не навязывает, каждый выбирает свой
|
||||||
(Anthropic, OpenAI, OpenRouter, …).
|
(Anthropic, OpenAI, OpenRouter, …).
|
||||||
|
|
||||||
|
Профиль можно задать заранее (для CI/неинтерактивной установки):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PI_KIT_PROFILE=backend curl -fsSL https://git.codelab.vc/ai/pi-kit/-/raw/main/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Профили и скилы
|
||||||
|
|
||||||
|
Общее для всех: команды `/bugfix /feature /review /rfc /kit-config`, guardrails, скилы
|
||||||
|
`jira-workflow`, `repo-map`, `docs-map`, и публичные `grill-me`, `grill-with-docs`,
|
||||||
|
`code-review`, `diagnosing-bugs`. Дополнительно по профилю:
|
||||||
|
|
||||||
|
| Профиль | Языковые стандарты | Доп. публичные скилы |
|
||||||
|
|---|---|---|
|
||||||
|
| `frontend` | typescript | frontend-design |
|
||||||
|
| `backend` | go, rust, python | — |
|
||||||
|
| `qa` | python, typescript | — |
|
||||||
|
| `mobile` | — (TODO: kotlin/swift) | — |
|
||||||
|
|
||||||
|
Сменить профиль позже: `PI_KIT_PROFILE=frontend ./install.sh` (или перезапусти установку).
|
||||||
|
|
||||||
Либо вручную:
|
Либо вручную:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -125,6 +147,21 @@ pi-kit/
|
|||||||
3. **Никаких секретов и URL в тексте** — только ссылки на корпоративный контекст сессии и
|
3. **Никаких секретов и URL в тексте** — только ссылки на корпоративный контекст сессии и
|
||||||
переменные окружения.
|
переменные окружения.
|
||||||
|
|
||||||
|
### Профили и гейтинг скилов
|
||||||
|
|
||||||
|
`install.sh` спрашивает профиль (или берёт `PI_KIT_PROFILE`) и делает две вещи:
|
||||||
|
|
||||||
|
1. **Гейтит наши скилы** — переписывает запись пакета в `~/.pi/agent/settings.json` в
|
||||||
|
object-форму `{"source": "...", "skills": ["skills/go-standards", ...]}`, чтобы грузились
|
||||||
|
только скилы профиля. Prompts и расширения не гейтятся (их ключи опущены → грузятся все).
|
||||||
|
2. **Ставит публичные скилы** через `npx skills add <repo> --skill <name> --global` в
|
||||||
|
`~/.agents/skills/` (Pi читает эту папку). Чужой код в наш репо не вендорится.
|
||||||
|
|
||||||
|
Чтобы поменять маппинг профиль→скилы — правь блок `case "$PROFILE"` и `COMMON_PUBLIC_SKILLS`
|
||||||
|
в `install.sh`. Языковой скилл добавляется как обычный (см. ниже) и подключается к нужному
|
||||||
|
профилю в этом `case`. Профили: `frontend`, `backend`, `qa`, `mobile` (последний пока без
|
||||||
|
языковых стандартов — TODO kotlin/swift).
|
||||||
|
|
||||||
### Как добавить шаблон-команду
|
### Как добавить шаблон-команду
|
||||||
|
|
||||||
1. Создай `prompts/<name>.md` — имя файла станет командой `/<name>`.
|
1. Создай `prompts/<name>.md` — имя файла станет командой `/<name>`.
|
||||||
|
|||||||
144
install.sh
144
install.sh
@@ -7,6 +7,10 @@
|
|||||||
# # or, from a checkout:
|
# # or, from a checkout:
|
||||||
# ./install.sh
|
# ./install.sh
|
||||||
#
|
#
|
||||||
|
# Profile selection:
|
||||||
|
# Interactive by default (prompts via /dev/tty, so it works under curl | bash).
|
||||||
|
# Non-interactive: set PI_KIT_PROFILE=frontend|backend|qa|mobile before running.
|
||||||
|
#
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -17,10 +21,19 @@ PI_KIT_REPO="git:git.codelab.vc/ai/pi-kit"
|
|||||||
|
|
||||||
MIN_NODE_MAJOR=20
|
MIN_NODE_MAJOR=20
|
||||||
INTERNAL_COURSE_URL="TODO: ссылка на внутренний курс по Pi"
|
INTERNAL_COURSE_URL="TODO: ссылка на внутренний курс по Pi"
|
||||||
|
SETTINGS="$HOME/.pi/agent/settings.json"
|
||||||
|
|
||||||
info() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
|
# Public skills installed for EVERYONE (repo:skill), via `npx skills add`.
|
||||||
warn() { printf '\033[1;33m[!]\033[0m %s\n' "$*"; }
|
COMMON_PUBLIC_SKILLS=(
|
||||||
err() { printf '\033[1;31m[x]\033[0m %s\n' "$*" >&2; }
|
"mattpocock/skills:grill-me"
|
||||||
|
"mattpocock/skills:grill-with-docs"
|
||||||
|
"mattpocock/skills:code-review"
|
||||||
|
"mattpocock/skills:diagnosing-bugs" # диагностика багов (в mattpocock/skills скилл называется так)
|
||||||
|
)
|
||||||
|
|
||||||
|
info() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
|
||||||
|
warn() { printf '\033[1;33m[!]\033[0m %s\n' "$*"; }
|
||||||
|
err() { printf '\033[1;31m[x]\033[0m %s\n' "$*" >&2; }
|
||||||
|
|
||||||
# --- 1. Node.js -------------------------------------------------------------
|
# --- 1. Node.js -------------------------------------------------------------
|
||||||
if ! command -v node >/dev/null 2>&1; then
|
if ! command -v node >/dev/null 2>&1; then
|
||||||
@@ -56,7 +69,125 @@ info "Устанавливаю корпоративный пакет: ${PI_KIT_R
|
|||||||
pi install "$PI_KIT_REPO"
|
pi install "$PI_KIT_REPO"
|
||||||
info "Пакет установлен. Обновляться потом: pi update --extensions"
|
info "Пакет установлен. Обновляться потом: pi update --extensions"
|
||||||
|
|
||||||
# --- 4. Provider API keys ---------------------------------------------------
|
# --- 4. Resolve profile -----------------------------------------------------
|
||||||
|
# Precedence: PI_KIT_PROFILE env > interactive prompt > "all" (no gating).
|
||||||
|
PROFILE="${PI_KIT_PROFILE:-}"
|
||||||
|
case "$PROFILE" in
|
||||||
|
frontend | backend | qa | mobile) ;; # valid, keep
|
||||||
|
"") # ask if we have a terminal, even under `curl | bash` (read from /dev/tty)
|
||||||
|
if [ -r /dev/tty ]; then
|
||||||
|
{
|
||||||
|
printf 'Выбери профиль:\n'
|
||||||
|
printf ' 1) frontend — TS/UI\n'
|
||||||
|
printf ' 2) backend — Go/Rust/Python\n'
|
||||||
|
printf ' 3) qa — тестирование\n'
|
||||||
|
printf ' 4) mobile — Android/iOS\n'
|
||||||
|
printf 'Номер или имя [1-4]: '
|
||||||
|
} >/dev/tty
|
||||||
|
read -r ans </dev/tty || ans=""
|
||||||
|
case "$ans" in
|
||||||
|
1 | frontend) PROFILE=frontend ;;
|
||||||
|
2 | backend) PROFILE=backend ;;
|
||||||
|
3 | qa) PROFILE=qa ;;
|
||||||
|
4 | mobile) PROFILE=mobile ;;
|
||||||
|
*) PROFILE=all ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
PROFILE=all
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
warn "Неизвестный PI_KIT_PROFILE='${PROFILE}', использую 'all' (без гейтинга скилов)."
|
||||||
|
PROFILE=all
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
info "Профиль: ${PROFILE}"
|
||||||
|
|
||||||
|
# Bundled language skills per profile. Common skills (jira-workflow/repo-map/
|
||||||
|
# docs-map) are always enabled. Prompts and guardrail extensions are never gated.
|
||||||
|
COMMON_BUNDLED="jira-workflow repo-map docs-map"
|
||||||
|
PROFILE_PUBLIC=()
|
||||||
|
case "$PROFILE" in
|
||||||
|
frontend)
|
||||||
|
LANG_BUNDLED="typescript-standards"
|
||||||
|
PROFILE_PUBLIC=("anthropics/skills:frontend-design")
|
||||||
|
;;
|
||||||
|
backend)
|
||||||
|
LANG_BUNDLED="go-standards rust-standards python-standards"
|
||||||
|
;;
|
||||||
|
qa) # TODO: уточнить стек тестировщиков; по умолчанию — Python и TS (автотесты)
|
||||||
|
LANG_BUNDLED="python-standards typescript-standards"
|
||||||
|
;;
|
||||||
|
mobile) # TODO: добавить kotlin-standards/swift-standards и мобильные скилы
|
||||||
|
LANG_BUNDLED=""
|
||||||
|
;;
|
||||||
|
*) # all: не гейтим, включаем все языковые скилы
|
||||||
|
LANG_BUNDLED="go-standards rust-standards python-standards typescript-standards"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- 5. Gate bundled skills via settings object-form filter -----------------
|
||||||
|
# Rewrites the pi-kit package entry in settings.json to {source, skills:[...]}
|
||||||
|
# so only the profile-relevant skills load. Extensions/prompts stay untouched
|
||||||
|
# (their keys are omitted => all load).
|
||||||
|
gate_bundled_skills() {
|
||||||
|
local allowed="$1"
|
||||||
|
if [ ! -f "$SETTINGS" ]; then
|
||||||
|
warn "settings.json не найден ($SETTINGS) — пропускаю гейтинг скилов."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
SETTINGS_FILE="$SETTINGS" ALLOWED="$allowed" SRC_MATCH="pi-kit" node <<'NODE'
|
||||||
|
const fs = require("fs");
|
||||||
|
const file = process.env.SETTINGS_FILE;
|
||||||
|
const allowed = process.env.ALLOWED.trim().split(/\s+/).filter(Boolean).map((s) => "skills/" + s);
|
||||||
|
const s = JSON.parse(fs.readFileSync(file, "utf8"));
|
||||||
|
if (!Array.isArray(s.packages)) process.exit(0);
|
||||||
|
let patched = false;
|
||||||
|
s.packages = s.packages.map((p) => {
|
||||||
|
const src = typeof p === "string" ? p : (p && p.source);
|
||||||
|
if (typeof src === "string" && src.includes(process.env.SRC_MATCH)) {
|
||||||
|
patched = true;
|
||||||
|
const base = (p && typeof p === "object") ? p : {};
|
||||||
|
return Object.assign({}, base, { source: src, skills: allowed });
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
});
|
||||||
|
fs.writeFileSync(file, JSON.stringify(s, null, 2) + "\n");
|
||||||
|
console.log(patched ? "gated bundled skills -> " + allowed.join(", ") : "pi-kit entry not found; skipped gating");
|
||||||
|
NODE
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$PROFILE" = "all" ]; then
|
||||||
|
info "Профиль 'all' — оставляю все скилы пакета без гейтинга."
|
||||||
|
else
|
||||||
|
info "Гейчу скилы пакета под профиль '${PROFILE}'..."
|
||||||
|
gate_bundled_skills "${COMMON_BUNDLED} ${LANG_BUNDLED}" || warn "не удалось отфильтровать скилы (см. выше)."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 6. Install public skills ----------------------------------------------
|
||||||
|
# Uses the skills.sh CLI (`npx skills add`). Failures are non-fatal.
|
||||||
|
add_public_skill() { # <owner/repo> <skill-name>
|
||||||
|
local repo="$1" name="$2"
|
||||||
|
info "Публичный скилл: ${name} (${repo})"
|
||||||
|
# --global installs into ~/.agents/skills (the universal dir Pi reads),
|
||||||
|
# not the current project. --yes skips the interactive scope prompt.
|
||||||
|
if ! npx --yes skills add "https://github.com/${repo}" --skill "${name}" --global --yes >/dev/null 2>&1; then
|
||||||
|
warn "не удалось поставить '${name}'. Вручную: npx skills add https://github.com/${repo} --skill ${name} -g -y"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
info "Ставлю общие публичные скилы..."
|
||||||
|
for entry in "${COMMON_PUBLIC_SKILLS[@]}"; do
|
||||||
|
add_public_skill "${entry%%:*}" "${entry##*:}"
|
||||||
|
done
|
||||||
|
if [ "${#PROFILE_PUBLIC[@]}" -gt 0 ]; then
|
||||||
|
info "Ставлю публичные скилы профиля '${PROFILE}'..."
|
||||||
|
for entry in "${PROFILE_PUBLIC[@]}"; do
|
||||||
|
add_public_skill "${entry%%:*}" "${entry##*:}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 7. Provider API keys ---------------------------------------------------
|
||||||
# Pi is provider-agnostic: engineers use different LLM providers (Anthropic,
|
# Pi is provider-agnostic: engineers use different LLM providers (Anthropic,
|
||||||
# OpenAI, OpenRouter, Google, ...). The package does NOT pin a provider/model.
|
# OpenAI, OpenRouter, Google, ...). The package does NOT pin a provider/model.
|
||||||
# We only check that *some* provider key is present and hint if none is.
|
# We only check that *some* provider key is present and hint if none is.
|
||||||
@@ -86,14 +217,15 @@ else
|
|||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- 5. Cheat sheet ---------------------------------------------------------
|
# --- 8. Cheat sheet ---------------------------------------------------------
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────
|
||||||
Готово! Памятка:
|
Готово! Профиль: ${PROFILE}
|
||||||
|
|
||||||
Запуск: pi
|
Запуск: pi
|
||||||
Обновление: pi update --extensions
|
Обновление: pi update --extensions
|
||||||
|
Сменить профиль: PI_KIT_PROFILE=backend ./install.sh (или перезапусти и выбери)
|
||||||
Команды: /bugfix <тикет> /feature <тикет>
|
Команды: /bugfix <тикет> /feature <тикет>
|
||||||
/review [фокус] /rfc <тема> /kit-config
|
/review [фокус] /rfc <тема> /kit-config
|
||||||
Проверка: /kit-config — покажет действующие корпоративные значения
|
Проверка: /kit-config — покажет действующие корпоративные значения
|
||||||
|
|||||||
Reference in New Issue
Block a user