diff --git a/TODO.md b/TODO.md index 2d90f27..2962f87 100644 --- a/TODO.md +++ b/TODO.md @@ -89,13 +89,173 @@ ## Фазы реализации -_Пункты чеклиста добавляет владелец репозитория. Агент не заполняет фазы без запроса._ +| Фаза | Название | Зависимости | Критерии SPEC | +|------|----------|-------------|---------------| +| 0 | Каркас репозитория | — | §9, §10 | +| 1 | Состояние и персистенция | 0 | §6.1 | +| 2 | Настройки | 0 | §7.3 | +| 3 | Детекция skills | 1 | §6.2, §12.1 | +| 4 | Expand skill-блоков | 0 | §5.3, §12.1 | +| 5 | Kept window | 3 | §6.4, §12.1 | +| 6 | pi-auto-compact | 2 | §16 | +| 7 | Re-inject оркестрация | 1, 4, 5, 6 | §5.2, §6.5 | +| 8 | Источник compaction | 1 | §8 | +| 9 | Хуки отслеживания | 1, 2, 3 | §6.2 | +| 10 | Восстановление сессии | 1, 3, 9 | §6.3 | +| 11 | Команды и UI | 1, 2, 6, 7 | §7 | +| 12 | Edge cases и полировка | 7–11 | §11 | +| 13 | Приёмка и документация | 0–12 | §12–13 | - +- [ ] **package.json** — manifest с `pi.extensions`, devDependencies (`@earendil-works/pi-coding-agent`, `typescript`); зачем: загрузка extension через `pi -e` (SPEC §9.1, §10) +- [ ] **tsconfig.json** — strict TS, module resolution под Pi extension runtime; зачем: `tsc --noEmit` в цикле AGENTS +- [ ] **npm scripts** — `typecheck`, `test`, `build` (минимально); зачем: единая проверка в каждом пункте +- [ ] **src/index.ts shell** — `export default function(pi: ExtensionAPI)`, пустой `session_start`; зачем: smoke `pi -e ./src/index.ts` без логики + +--- + +### Фаза 1 — Состояние и персистенция + +- [ ] **state.ts types** — `TrackedSkill`, `ExtensionState` (version 1), `RuntimeFlags`; зачем: единый контракт §6.1 +- [ ] **state.ts initial** — `createInitialState()`, `createRuntimeFlags()`; зачем: предсказуемый старт сессии +- [ ] **state.ts persist** — `saveState(pi, state)` через `appendEntry("skill-reinject:state", …)`; зачем: пережить `/resume` (§6.1) +- [ ] **state.ts load** — `loadStateFromBranch(branch)` из последнего custom entry; зачем: восстановление без полного rescan +- [ ] **state.ts trackSkill** — upsert по `name`, merge `sources`, preserve insertion order; зачем: дедуп §6.1 + +--- + +### Фаза 2 — Настройки + +- [ ] **settings.ts types** — `SkillReinjectSettings` + defaults из §7.3 (`enabled`, `trackReadPaths`, `triggerTurn`, `reinjectOnManualCompaction`, `autoCompactIntegration`, `suffix`) +- [ ] **settings.ts read** — merge global + project из `ctx` / Pi settings API; зачем: не читать файл вручную, если API даёт merged view +- [ ] **settings.ts writeGlobal** — merge в `~/.pi/agent/settings.json` без затирания чужих ключей; зачем: `/skill-reinject global on` +- [ ] **settings.ts effective** — `effectiveEnabled(sessionOverride, global)`, `effectiveIntegration(...)`; зачем: три слоя §5.1 +- [ ] **test/settings.test.ts** — defaults, merge write (mock/temp file); зачем: §12.1 + +--- + +### Фаза 3 — Детекция skills + +- [ ] **detect.ts slash** — `detectSlashSkill(text)` → `/^\/skill:([a-z0-9-]+)/`; зачем: источник `slash` §6.2 +- [ ] **detect.ts skill-block** — `parseSkillBlocksFromText(text)` (regex как `parseSkillBlock`); зачем: источник `skill-block` §6.2 +- [ ] **detect.ts read-path** — `matchReadPathToSkill(path, skills)` по `filePath` из resourceLoader; зачем: источник `read` §6.2 +- [ ] **detect.ts trackReadPaths gate** — пропуск read-детекции при `trackReadPaths: false`; зачем: §6.2, §3 +- [ ] **test/detect.test.ts** — slash, blocks, read match, trackReadPaths off; зачем: §12.1 + +--- + +### Фаза 4 — Expand skill-блоков + +- [ ] **expand.ts readBody** — `readSkillBody(filePath)` + strip YAML frontmatter; комментарий «mirror agent-session»; зачем: §5.3, §10 +- [ ] **expand.ts formatBlock** — XML `` с `baseDir`; зачем: повтор `_expandSkillCommand` §5.3 +- [ ] **expand.ts suffix** — опциональный суффикс из `settings.suffix`; зачем: §5.3 +- [ ] **expand.ts expandSkill** — публичная функция: skill meta → готовый user text; зачем: reinject + `/skill-reinject now` +- [ ] **test/expand.test.ts** — frontmatter strip, paths, suffix; зачем: §12.1 + +--- + +### Фаза 5 — Kept window + +- [ ] **kept.ts slice** — `getKeptEntries(branch, firstKeptEntryId)` от compaction entry до хвоста; зачем: §6.4 +- [ ] **kept.ts present** — `skillsPresentInKeptWindow(keptEntries, skillNames)` по `3 (если `maxSkills` не задан — unlimited); зачем: §15 +- [ ] **commands.ts no-ui** — RPC / `hasUI === false`: команды без падения, notify no-op; зачем: §11 +- [ ] **index.ts double compact** — каждый `session_compact` пересчитывает `pendingReinject`; зачем: §16.6 + +--- + +### Фаза 13 — Приёмка и документация + +- [ ] **README.md** — статус «реализовано», установка `pi -e`, ссылка на `/skill-reinject`, coexistence с pi-auto-compact; зачем: §9.1, §16.7 +- [ ] **Manual E2E standalone** — прогон чеклиста §12.2 (записать результат в коммит / BACKLOG при сбоях); зачем: §12.2 +- [ ] **Manual E2E pi-auto-compact** — прогон §12.3 (defer, нет гонки, manual `/compact`); зачем: критерии §13 +- [ ] **Критерии §13** — сверка всех 10 пунктов; расхождения → BACKLOG или правка SPEC + +--- + +## После v1 (не блокирует фазы 0–13) + +Зафиксировано в SPEC §14 — не включать в чеклист v1, только при отдельном запросе: + +- `reinjectOnManualCompaction: true` как осознанный default-path +- custom summary в `session_before_compact` +- `pi.events` протокол с pi-auto-compact +- npm package (`keywords: ["pi-package"]`) +- re-inject только последнего активного skill