151 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Spec Delta: dsh-install
## Purpose
Слой установки DSH-обвязки: откуда берутся superpowers-скиллы и роли, что
делает `dsh/install.sh --skills/--roles`, какие пути попадают в установленные
инструкции. В Claude Code источником служит кэш плагина в `~/.claude`; в DSH
источник задаётся установщиком явно (аргумент, переменная или пиннинг в
`~/.dsh`), а `~/.claude` остаётся только legacy-fallback'ом с предупреждением.
Контракт нужен, чтобы свежая установка на машине без Claude Code проходила
полный цикл #48 и чтобы путь `~/.claude` не возвращался в runtime незаметно.
## ADDED Requirements
### Requirement: Источник superpowers задаётся при установке
`dsh/install.sh --skills` SHALL разрешать источник superpowers-скиллов в
порядке приоритета и MUST NOT исполнять `git clone` и любые сетевые операции.
- Порядок: `--superpowers-from <dir>` → `$DSH_SUPERPOWERS_SOURCE` →
`$DSH_HOME/superpowers/skills` (пиннинг; допускается и корень
`$DSH_HOME/superpowers` с подкаталогом `skills/`) → legacy-кэш Claude Code →
legacy `~/.claude/skills`.
- Для явного источника (`--superpowers-from`, `$DSH_SUPERPOWERS_SOURCE`)
допускаются обе формы: корень superpowers (есть `skills/using-superpowers/SKILL.md`)
или сам каталог `skills`.
- Явно заданный, но невалидный источник MUST приводить к `FAIL` и коду
возврата 1: тихий откат на legacy запрещён.
- Копирование MUST быть заменой каталога назначения (`rm -rf` + `cp -R`), а не
симлинком: `~/.dsh/skills` не должен зависеть от каталога-источника.
#### Scenario: Явный источник без ~/.claude
- **WHEN** `HOME` — пустой temp-каталог без `~/.claude`, а `--superpowers-from`
указывает на каталог superpowers
- **THEN** `--skills` копирует скиллы в `$DSH_HOME/skills`, печатает источник и
завершается кодом 0
#### Scenario: Переменная окружения вместо флага
- **WHEN** задан `DSH_SUPERPOWERS_SOURCE=<dir>` и флаг `--superpowers-from` не передан
- **THEN** источник берётся из переменной; поведение совпадает с флагом
#### Scenario: Флаг важнее переменной
- **WHEN** заданы и `--superpowers-from`, и `DSH_SUPERPOWERS_SOURCE`
- **THEN** используется каталог из флага
#### Scenario: Невалидный явный источник
- **WHEN** `--superpowers-from` указывает на каталог без
`using-superpowers/SKILL.md`
- **THEN** `--skills` печатает `FAIL` с ожидаемой структурой и завершается
кодом 1, ничего не копируя из legacy-источников
#### Scenario: Пиннинг в ~/.dsh
- **WHEN** существует `$DSH_HOME/superpowers/skills/using-superpowers/SKILL.md`
и флаг/переменная не заданы
- **THEN** источником служит этот каталог, `--check` печатает
`ok: superpowers source (<path>)`
### Requirement: Отсутствие источника не бывает тихим
Если источник superpowers не найден, `--skills` MUST различать первичную и
повторную установку и MUST NOT завершаться успехом молча.
- Если `$DSH_HOME/skills/using-superpowers/SKILL.md` уже существует —
`WARN` «источник не найден, копии сохранены» и код 0 (идемпотентный повтор).
- Если копий нет — `FAIL` с готовой командой получения источника
(`git clone --depth 1 https://github.com/obra/superpowers ~/.dsh/superpowers`)
и код возврата 1.
- Локальные скиллы обвязки (`dsh/skills/*`: `role`, `sdd`) MUST ставиться в
обоих случаях: они не зависят от superpowers.
#### Scenario: Первая установка без источника
- **WHEN** `HOME` пуст, `$DSH_HOME/skills` не существует, источника нет
- **THEN** `--skills` печатает `FAIL`, код 1, но `$DSH_HOME/skills/role/SKILL.md`
и `$DSH_HOME/skills/sdd/SKILL.md` на месте
#### Scenario: Повторная установка без источника
- **WHEN** `$DSH_HOME/skills/using-superpowers/SKILL.md` уже есть, источника нет
- **THEN** `--skills` печатает `WARN`, код 0, установленные скиллы не удалены
### Requirement: ~/.claude — только legacy-fallback с предупреждением
superpowers-скиллы и роли MUST иметь рабочий путь `~/.dsh`; пути `~/.claude`
SHALL оставаться fallback'ом для машин, где `--skills --roles` ещё не
перезапускали, и MUST сопровождаться предупреждением.
- Установка: legacy-кэш Claude Code и `~/.claude/skills` допустимы как
источник, но `--skills` печатает `WARN: legacy superpowers source` с
подсказкой перейти на пиннинг/флаг.
- `--check`: legacy-источник — `WARN`, явный/пиннинг — `ok`, отсутствие —
`WARN` с подсказкой, невалидный явный источник — `FAIL` и код 1
(пользователь задал его сам, подсказка «нет источника» здесь неверна).
- Runtime: bootstrap и резолвер ролей сохраняют порядок `~/.dsh` → `~/.claude`,
но при выборе legacy-пути один раз за процесс пишут в лог предупреждение.
- Удаление fallback'ов — отдельное изменение; в этом change они не удаляются.
#### Scenario: Legacy-кэш как источник установки
- **WHEN** в `HOME` есть только кэш Claude Code с superpowers, `$DSH_HOME` пуст
- **THEN** `--skills` копирует скиллы и печатает `WARN: legacy superpowers source`
#### Scenario: Runtime-предупреждение
- **WHEN** bootstrap резолвит `using-superpowers` из `~/.claude/...`
- **THEN** в лог один раз за процесс попадает предупреждение с предложением
выполнить `dsh/install.sh --skills`
#### Scenario: ~/.dsh приоритетнее
- **WHEN** существуют и `~/.dsh/skills/using-superpowers/SKILL.md`, и legacy-копия
- **THEN** используется `~/.dsh`, предупреждения нет
### Requirement: Установленные инструкции DSH не ссылаются на ~/.claude
`dsh/install.sh --global` MUST писать `$DSH_HOME/AGENTS.md` так, чтобы пути
ролей указывали на DSH-слой, а формат инструкций не выдавался за runtime
Claude Code.
- Строки `~/.claude/roles` в установленной копии MUST заменяться на
`~/.dsh/roles`, а adapter-шапка MUST NOT называть пути `~/.claude`: в
установленном файле не остаётся ни одного такого пути. `global/CLAUDE.md` в
репозитории MUST NOT меняться (его читает Claude Code).
- Шапка установленного файла MUST говорить, что проектный `CLAUDE.md` /
`AGENTS.md` — это формат файлов инструкций DSH, а не запущенный Claude Code,
и что роли лежат в `~/.dsh/roles` (`--roles`), а superpowers-скиллы — в
`~/.dsh/skills` (`--skills`).
- Повторный `--global` обязан делать бэкап прежнего `AGENTS.md` (как сейчас).
#### Scenario: Пути ролей после установки
- **WHEN** выполнен `--global` во временный `DSH_HOME`
- **THEN** в `AGENTS.md` есть `~/.dsh/roles/dev.md` и нет ни одного пути
`~/.claude`
#### Scenario: global/CLAUDE.md не тронут
- **WHEN** выполнен `--global`
- **THEN** `global/CLAUDE.md` в репозитории побайтно не изменился
### Requirement: Чистый HOME без ~/.claude проходит установку
Установка, bootstrap и skill `role` MUST работать на машине, где Claude Code
никогда не устанавливался.
- `--global --skills --roles` с явным источником superpowers в пустом `HOME`
MUST создавать `$DSH_HOME/{AGENTS.md,skills/using-superpowers/SKILL.md,skills/role/SKILL.md,skills/sdd/SKILL.md,roles/dev.md}`.
- bootstrap MUST резолвить скилл из `$DSH_HOME/skills` при `home` этого HOME и
MUST NOT обращаться к `~/.claude`.
- Резолвер ролей MUST находить `$DSH_HOME/roles` при `home` этого HOME.
#### Scenario: Установка в чистый HOME
- **WHEN** `HOME` — пустой temp-каталог, `DSH_HOME=$HOME/.dsh`,
`--superpowers-from` указывает на каталог superpowers
- **THEN** `--global --skills --roles` завершается кодом 0, все перечисленные
файлы на месте, `--check` зелёный по skills и roles
#### Scenario: Bootstrap в чистом HOME
- **WHEN** `prepareBootstrap({ home: <temp HOME> })` вызывается после установки
- **THEN** выбранный путь — `$HOME/.dsh/skills/using-superpowers/SKILL.md`,
текст содержит маркер `<!-- DSH-HARNESS-BOOTSTRAP:... -->`, предупреждений о
legacy нет