feat: monorepo consolidation — forge pipeline, MACP protocol, framework plugin, profiles/guides/skills
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/pr/ci Pipeline failed

Work packages completed:
- WP1: packages/forge — pipeline runner, stage adapter, board tasks, brief classifier,
  persona loader with project-level overrides. 89 tests, 95.62% coverage.
- WP2: packages/macp — credential resolver, gate runner, event emitter, protocol types.
  65 tests, 96.24% coverage. Full Python-to-TS port preserving all behavior.
- WP3: plugins/mosaic-framework — OC rails injection plugin (before_agent_start +
  subagent_spawning hooks for Mosaic contract enforcement).
- WP4: profiles/ (domains, tech-stacks, workflows), guides/ (17 docs),
  skills/ (5 universal skills), forge pipeline assets (48 markdown files).

Board deliberation: docs/reviews/consolidation-board-memo.md
Brief: briefs/monorepo-consolidation.md

Consolidates mosaic/stack (forge, MACP, bootstrap framework) into mosaic/mosaic-stack.
154 new tests total. Zero Python — all TypeScript/ESM.
This commit is contained in:
Mos (Agent)
2026-03-30 19:43:24 +00:00
parent 40c068fcbc
commit 10689a30d2
123 changed files with 18166 additions and 11 deletions

View File

@@ -0,0 +1,196 @@
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import {
slugify,
personaNameFromMarkdown,
loadBoardPersonas,
loadPersonaOverrides,
loadForgeConfig,
getEffectivePersonas,
} from '../src/persona-loader.js';
describe('slugify', () => {
it('converts to lowercase and replaces non-alphanumeric with hyphens', () => {
expect(slugify('Chief Executive Officer')).toBe('chief-executive-officer');
});
it('strips leading and trailing hyphens', () => {
expect(slugify('--hello--')).toBe('hello');
});
it('returns "persona" for empty string', () => {
expect(slugify('')).toBe('persona');
});
it('handles special characters', () => {
expect(slugify('CTO — Technical')).toBe('cto-technical');
});
});
describe('personaNameFromMarkdown', () => {
it('extracts name from heading', () => {
expect(personaNameFromMarkdown('# CEO — Chief Executive Officer', 'FALLBACK')).toBe('CEO');
});
it('strips markdown heading markers', () => {
expect(personaNameFromMarkdown('## CTO - Technical Lead', 'FALLBACK')).toBe('CTO');
});
it('returns fallback for empty content', () => {
expect(personaNameFromMarkdown('', 'FALLBACK')).toBe('FALLBACK');
});
it('returns full heading if no separator', () => {
expect(personaNameFromMarkdown('# SimpleTitle', 'FALLBACK')).toBe('SimpleTitle');
});
});
describe('loadBoardPersonas', () => {
let tmpDir: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'forge-personas-'));
});
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it('returns empty array for non-existent directory', () => {
expect(loadBoardPersonas('/nonexistent')).toEqual([]);
});
it('loads personas from markdown files', () => {
fs.writeFileSync(
path.join(tmpDir, 'ceo.md'),
'# CEO — Visionary Leader\n\nThe CEO sets direction.',
);
fs.writeFileSync(
path.join(tmpDir, 'cto.md'),
'# CTO — Technical Realist\n\nThe CTO evaluates feasibility.',
);
const personas = loadBoardPersonas(tmpDir);
expect(personas).toHaveLength(2);
expect(personas[0]!.name).toBe('CEO');
expect(personas[0]!.slug).toBe('ceo');
expect(personas[1]!.name).toBe('CTO');
});
it('sorts by filename', () => {
fs.writeFileSync(path.join(tmpDir, 'z-last.md'), '# Z Last');
fs.writeFileSync(path.join(tmpDir, 'a-first.md'), '# A First');
const personas = loadBoardPersonas(tmpDir);
expect(personas[0]!.slug).toBe('a-first');
expect(personas[1]!.slug).toBe('z-last');
});
it('ignores non-markdown files', () => {
fs.writeFileSync(path.join(tmpDir, 'notes.txt'), 'not a persona');
fs.writeFileSync(path.join(tmpDir, 'ceo.md'), '# CEO');
const personas = loadBoardPersonas(tmpDir);
expect(personas).toHaveLength(1);
});
});
describe('loadPersonaOverrides', () => {
let tmpDir: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'forge-overrides-'));
});
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it('returns empty object when .forge/personas/ does not exist', () => {
expect(loadPersonaOverrides(tmpDir)).toEqual({});
});
it('loads override files', () => {
const overridesDir = path.join(tmpDir, '.forge', 'personas');
fs.mkdirSync(overridesDir, { recursive: true });
fs.writeFileSync(path.join(overridesDir, 'ceo.md'), 'Additional CEO context');
const overrides = loadPersonaOverrides(tmpDir);
expect(overrides['ceo']).toBe('Additional CEO context');
});
});
describe('loadForgeConfig', () => {
let tmpDir: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'forge-config-'));
});
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it('returns empty config when file does not exist', () => {
expect(loadForgeConfig(tmpDir)).toEqual({});
});
it('parses board skipMembers', () => {
const configDir = path.join(tmpDir, '.forge');
fs.mkdirSync(configDir, { recursive: true });
fs.writeFileSync(
path.join(configDir, 'config.yaml'),
'board:\n skipMembers:\n - cfo\n - coo\n',
);
const config = loadForgeConfig(tmpDir);
expect(config.board?.skipMembers).toEqual(['cfo', 'coo']);
});
});
describe('getEffectivePersonas', () => {
let tmpDir: string;
let boardDir: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'forge-effective-'));
boardDir = path.join(tmpDir, 'board-agents');
fs.mkdirSync(boardDir, { recursive: true });
fs.writeFileSync(path.join(boardDir, 'ceo.md'), '# CEO — Visionary');
fs.writeFileSync(path.join(boardDir, 'cto.md'), '# CTO — Technical');
fs.writeFileSync(path.join(boardDir, 'cfo.md'), '# CFO — Financial');
});
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it('returns all personas with no overrides or config', () => {
const personas = getEffectivePersonas(tmpDir, boardDir);
expect(personas).toHaveLength(3);
});
it('appends project overrides to base description', () => {
const overridesDir = path.join(tmpDir, '.forge', 'personas');
fs.mkdirSync(overridesDir, { recursive: true });
fs.writeFileSync(path.join(overridesDir, 'ceo.md'), 'Focus on AI strategy');
const personas = getEffectivePersonas(tmpDir, boardDir);
const ceo = personas.find((p) => p.slug === 'ceo')!;
expect(ceo.description).toContain('# CEO — Visionary');
expect(ceo.description).toContain('Focus on AI strategy');
});
it('removes skipped members via config', () => {
const configDir = path.join(tmpDir, '.forge');
fs.mkdirSync(configDir, { recursive: true });
fs.writeFileSync(path.join(configDir, 'config.yaml'), 'board:\n skipMembers:\n - cfo\n');
const personas = getEffectivePersonas(tmpDir, boardDir);
expect(personas).toHaveLength(2);
expect(personas.find((p) => p.slug === 'cfo')).toBeUndefined();
});
});