diff --git a/docs/superpowers/plans/2026-06-02-router-gate-dev-prod-rescope.md b/docs/superpowers/plans/2026-06-02-router-gate-dev-prod-rescope.md new file mode 100644 index 00000000..8d624b99 --- /dev/null +++ b/docs/superpowers/plans/2026-06-02-router-gate-dev-prod-rescope.md @@ -0,0 +1,290 @@ +# Router-gate dev/prod re-scope — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Разрешить локальную разработку (composer/npm/git/worktree) через контроллера, сохранив блок боевого/опасного и дисциплины. + +**Architecture:** Точечно расширить whitelist Bash-гейта (`enforce-router-gate.mjs`) дев-инструментами + разрешить dev-safe git в общем `shell-content-rules.mjs` (`classifyGitCommand`) с «стражем main» для push. Философия default-deny сохраняется; hard-blacklist опасного и дисциплинарные хуки не трогаются. + +**Tech Stack:** Node ESM, vitest (`vitest.config.tools.mjs`, root `app`). + +**Spec:** `docs/superpowers/specs/2026-06-02-router-gate-dev-prod-rescope-design.md` + +**Verify-команда (вся регрессия tools):** +`npx vitest run --root app --config vitest.config.tools.mjs` +Узкий прогон файла: добавить хвост `<имя>.test` (например `enforce-router-gate.test`). + +**Bootstrap-нюанс (важно):** до того как Task 3 (git dev-allow) применится, `git commit` ещё +заблокирован самим гейтом. Поэтому коммиты НЕ делаем по ходу — все правки складываем в рабочее +дерево, гоняем тесты, и **один раз** коммитим в конце (Task 5), когда git уже разрешён. Реализация — +в основной копии (worktree пока недоступен; это и есть bootstrap-исключение из спеки). + +--- + +## Задачи + +### Task 1: Разрешить `composer` (install/update/require/remove/dump-autoload) + +**Files:** + +- Modify: `tools/enforce-router-gate.mjs` (BASH_HARD_BLACKLIST ~line 59; SAFE_EXACT ~line 124) +- Test: `tools/enforce-router-gate.test.mjs` + +- [ ] **Step 1: Write failing tests** — добавить в конец `enforce-router-gate.test.mjs`: + +```js +import { matchBashHardBlacklist as mhb2, classifyBashCommand as cbc2 } from './enforce-router-gate.mjs'; + +describe('composer dev-allow (owner-authorized 2026-06-02)', () => { + it('allows composer install', () => { + expect(mhb2('composer install')).toBe(null); + expect(cbc2('composer install', {}).result).toBe('allow'); + }); + it('allows composer require / update / dump-autoload', () => { + expect(cbc2('composer require monolog/monolog', {}).result).toBe('allow'); + expect(cbc2('composer update', {}).result).toBe('allow'); + expect(cbc2('composer dump-autoload', {}).result).toBe('allow'); + }); + it('still allows composer install with -d working-dir', () => { + expect(cbc2('composer install -d app --no-interaction', {}).result).toBe('allow'); + }); +}); +``` + +- [ ] **Step 2: Run to verify FAIL** + +Run: `npx vitest run --root app --config vitest.config.tools.mjs enforce-router-gate.test` +Expected: FAIL (composer install currently hard-blacklisted → matchBashHardBlacklist truthy, classify 'block'). + +- [ ] **Step 3: Remove composer from hard-blacklist** — в `tools/enforce-router-gate.mjs` удалить строку: + +```js + { re: /\bcomposer\s+(?:install|update|require|remove)\b/, reason: 'composer install/update/require/remove запрещён' }, +``` + +- [ ] **Step 4: Add composer to whitelist** — в массив `SAFE_EXACT`, рядом с существующей `/^composer\s+(?:show|outdated)\b/`, добавить: + +```js + /^composer\s+(?:install|update|require|remove|dump-autoload|dump)\b/, // dev-allow 2026-06-02 +``` + +- [ ] **Step 5: Run to verify PASS** + +Run: `npx vitest run --root app --config vitest.config.tools.mjs enforce-router-gate.test` +Expected: PASS (включая новый describe). + +--- + +### Task 2: Разрешить `npm` (install/ci/run-скрипты) + +**Files:** + +- Modify: `tools/enforce-router-gate.mjs` (BASH_HARD_BLACKLIST ~line 60; SAFE_EXACT ~line 122) +- Test: `tools/enforce-router-gate.test.mjs` + +- [ ] **Step 1: Write failing tests** — добавить describe: + +```js +describe('npm dev-allow (owner-authorized 2026-06-02)', () => { + it('allows npm install / i / ci', () => { + expect(mhb2('npm install')).toBe(null); + expect(cbc2('npm install', {}).result).toBe('allow'); + expect(cbc2('npm ci', {}).result).toBe('allow'); + }); + it('allows npm run