Files
brain/tools/plan-skills.mjs
T
Дмитрий bbc053e0a6 feat: D1 — благословлённый ops-runbook (деплой выполняет агент под ревью)
Деплой, помеченный **Kind:** deploy и опечатанный (наставник+судья GO,
judge_mode=live-block), агент выполняет по белому списку шагов под ОДНИМ
согласием владельца `FLOOR-ESCAPE: ops-runbook:<plan-hash>` — без аварийного
выхода на каждую команду. «Ядерный» набор (rm -rf/force-push/migrate:fresh/
db:wipe) остаётся на per-command escape.

- plan-lock: freezePlan принимает kind (в подписанную базу + хеш, как delivery);
  не-'normal' добавляет поле, обычные планы байт-идентичны старым печатям.
- plan-skills: parsePlanKind (**Kind:** deploy|normal, default normal).
- seal-orchestration: sealablePlan/sealPlan прокидывают kind в печать.
- escape-grant: loadOpsRunbookGrants (окно = существование плана, БЕЗ 5-мин
  фильтра) + opsRunbookGrantOpen (точный матч на plan_id).
- floor-decide: floorDecide получает инъектируемый blessedOps(cmd); content-block
  команда из набора пропускается, ЯДЕРНЫЙ набор (bashIsFloor) исключён из послабления.
- blessed-ops (новый модуль-мост): buildBlessedOps + loadBlessedOpsForSession —
  знает план+пол, чтобы СОХРАНИТЬ Δ9 (enforce-floor не зависит от модуля печати плана).
  Предикат пускает команду только дословно из Bash-листов опечатанного deploy-плана.
- enforce-floor: gated — blessed-ops грузит план/гранты ТОЛЬКО при открытом
  ops-runbook-гранте; без согласия владельца пол плана не касается (Δ9 цел).

План: docs/superpowers/plans/2026-06-18-blessed-ops-runbook-plan.md
Спека: docs/superpowers/specs/2026-06-18-blessed-ops-runbook-design.md §3.1-3.7.
+33 теста, свод 4299 passed / 2 skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 13:19:22 +03:00

37 lines
2.1 KiB
JavaScript

#!/usr/bin/env node
/** Парсер объявленных в плане скилов (мерж роутер↔наставник). Зеркало parseVerifiedContext:
* ищет fenced-блок ```skills-json со списком строк. Нет/битый → []. */
export function parsePlanSkills(content) {
const m = String(content ?? '').match(/```skills-json\s*\n([\s\S]*?)\n```/i);
if (!m) return [];
let arr;
try { arr = JSON.parse(m[1]); } catch { return []; }
if (!Array.isArray(arr)) return [];
return arr.filter((s) => typeof s === 'string' && s.trim());
}
/** Цель плана для classify(): секция ## Цель / ## Goal (до след. заголовка) или первый
* непустой не-заголовок абзац. Зеркало extractGoal судьи (enforce-judge-gate.mjs:174). */
export function extractPlanGoal(content) {
const text = String(content ?? '');
const m = text.match(/^##\s*(?:Цель|Goal)[^\n]*\n([\s\S]*?)(?:\n##\s|$)/im);
if (m && m[1].trim()) return m[1].trim();
const para = text.split(/\n\s*\n/).map((s) => s.trim()).find((s) => s && !s.startsWith('#'));
return para || '';
}
/** Пометка поставки плана: `**Delivery:** internal|user-result`. По умолчанию/мусор → 'internal'
* (fail-safe: владельца не дёргаем без явной пометки результата). Зеркало parsePlanSkills. */
export function parsePlanDelivery(content) {
const m = String(content ?? '').match(/(^|\n)\*\*Delivery:\*\*\s*(internal|user-result)\b/i);
return m ? m[2].toLowerCase() : 'internal';
}
/** D1: пометка типа плана: `**Kind:** deploy`. По умолчанию/мусор → 'normal' (fail-safe:
* благословлённый ops-runbook-канал enforce-floor применяется ТОЛЬКО к явному deploy-плану).
* Зеркало parsePlanDelivery. */
export function parsePlanKind(content) {
const m = String(content ?? '').match(/(^|\n)\*\*Kind:\*\*\s*(deploy|normal)\b/i);
return m ? m[2].toLowerCase() : 'normal';
}