feat: claude-brain — управляющий слой, выделен из Лидерры по ADR-020
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { extractStepsBlock, parsePlanSteps } from './plan-steps-parse.mjs';
|
||||
|
||||
const good = [
|
||||
'# Plan', '```steps-json',
|
||||
'[{"op":"Edit","object":"app/Foo.php","ref":"dec-a"},',
|
||||
' {"op":"Bash","object":"npm run build","ref":"dec-b"}]',
|
||||
'```',
|
||||
].join('\n');
|
||||
|
||||
describe('plan-steps-parse', () => {
|
||||
it('extracts and parses valid steps', () => {
|
||||
const steps = parsePlanSteps(good);
|
||||
expect(steps).toHaveLength(2);
|
||||
expect(steps[0]).toMatchObject({ op: 'Edit', ref: 'dec-a' });
|
||||
});
|
||||
it('extractStepsBlock returns block body or null', () => {
|
||||
expect(extractStepsBlock(good)).toContain('app/Foo.php');
|
||||
expect(extractStepsBlock('# no block')).toBe(null);
|
||||
});
|
||||
it('canonicalizes file object to repo-relative POSIX (SE-5)', () => {
|
||||
const md = '```steps-json\n[{"op":"Write","object":"app\\\\Bar.php","ref":"r"}]\n```';
|
||||
expect(parsePlanSteps(md)[0].object).toBe('app/Bar.php');
|
||||
});
|
||||
it('rejects step without ref (SE-1) → throws', () => {
|
||||
const md = '```steps-json\n[{"op":"Edit","object":"x"}]\n```';
|
||||
expect(() => parsePlanSteps(md)).toThrow(/ref/);
|
||||
});
|
||||
it('rejects op:Task (VA-4, субагенты запрещены) → throws', () => {
|
||||
const md = '```steps-json\n[{"op":"Task","object":"coder","ref":"r"}]\n```';
|
||||
expect(() => parsePlanSteps(md)).toThrow(/Task/);
|
||||
});
|
||||
it('missing block → throws (fail-CLOSE)', () => {
|
||||
expect(() => parsePlanSteps('# Plan no block')).toThrow();
|
||||
});
|
||||
it('non-JSON block → throws', () => {
|
||||
expect(() => parsePlanSteps('```steps-json\nnot json\n```')).toThrow();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user