Files
brain/tools/secretary-protocol.mjs
T
Дмитрий 9c8dbfde35 feat(secretary): раздел «Шаги (Слой 1)» — все ходы человекочитаемо + ссылка на сырьё в конце
- buildStepLine: кратко «спросил -> ответил» (служебные строки экономия/coverage/вердикт отброшены)
- protocol.steps: хук ведёт по строке на КАЖДЫЙ ход; рендер — список + одна ссылка raw в конце
- reconcile (stampProvenance) сохраняет steps (модель их не трогает)
- stop-хук добавляет шаг текущего хода

41 тест green, exit=0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:34:25 +03:00

60 lines
3.1 KiB
JavaScript

// Структура и сверка короткого протокола (§D5/§D7). Отменённое зачёркивается, не удаляется.
export function EMPTY_PROTOCOL() {
return {
subject: '', status: 'открыто',
decisions: [], alternatives: [], consequences: [],
will: [], open: [], doneNext: [], history: [], steps: [],
};
}
function prov(turns) {
return Array.isArray(turns) && turns.length ? ` [${turns.map((t) => `${t}`).join(', ')}]` : '';
}
// Навигация в Слой 1: метка сессии рядом с [→N] → искать raw/<session>.log, "=== ХОД turn=N ===".
function src(entry) {
return entry && entry.session ? ` @${String(entry.session).slice(0, 8)}` : '';
}
const line = (e) => `${e.struck ? `~~${e.text}~~` : e.text}${prov(e.turns)}${src(e)}`;
// Шаги (Слой 1): человекочитаемая строка на КАЖДЫЙ ход («спросил → ответил»), в конце —
// ссылка(и) на сырьё для подробностей. Шаги ведёт хук (по ходу), не модель.
function stepsSection(p) {
const steps = (p.steps || []).slice().sort((a, b) => (a.turn || 0) - (b.turn || 0));
const L = steps.map((s) => `- ${s.text}`);
const sessions = [...new Set(steps.map((s) => s.session).filter(Boolean))];
if (sessions.length) L.push('', ...sessions.map((s) => `Подробно (дословно): raw/${s}.log`));
return L;
}
// Полная форма протокола (§D7): шапка «Дело» + 8 корзин (2–9) + навигация Шаги→Слой 1.
export function renderProtocol(protocol, opts = {}) {
const L = [];
if (opts.work) {
L.push(`**Дело:** ${opts.work} · **Статус:** ${protocol.status || 'открыто'} · `
+ `**Дата:** ${opts.date || ''} · **Хозяин:** владелец · **Цель:** ${protocol.subject || ''}`, '');
}
L.push('## Решения');
for (const d of protocol.decisions || []) {
const body = d.struck ? `~~${d.text}~~` : d.text;
const why = d.why ? `${d.why}` : '';
L.push(`- ${body}${why}${prov(d.turns)}${src(d)}`);
}
L.push('', '## Альтернативы');
for (const a of protocol.alternatives || []) L.push(`- ${line(a)}`);
L.push('', '## Последствия / цена');
for (const c of protocol.consequences || []) L.push(`- ${line(c)}`);
L.push('', '## Твоя воля / запреты');
for (const w of protocol.will || []) L.push(`- ${line(w)}`);
L.push('', '## Открытые вопросы');
for (const o of protocol.open || []) L.push(`- ${line(o)}`);
L.push('', '## Сделано / дальше');
for (const s of protocol.doneNext || []) L.push(`- [${s.done ? 'x' : ' '}] ${s.struck ? `~~${s.text}~~` : s.text}${prov(s.turns)}${src(s)}`);
L.push('', '## История (заменено, не стёрто)');
for (const h of protocol.history || []) L.push(`- ~~${h.oldText}~~ → ${h.newText}${prov(h.turns)}`);
L.push('', '## Шаги (Слой 1)');
for (const s of stepsSection(protocol)) L.push(s);
return L.join('\n');
}