← back to Dw Boardroom Governance

src/agents/president.ts

58 lines

/**
 * President Agent — Meeting chair
 * Validates agenda, enforces 5-item cap, opens/closes meetings
 */

import { AgendaItem } from '../types';

const MAX_AGENDA_ITEMS = 5;

export interface AgendaValidation {
  valid: boolean;
  errors: string[];
  summary: string;
}

export function validateAgenda(items: AgendaItem[]): AgendaValidation {
  const errors: string[] = [];

  if (!items || items.length === 0) {
    errors.push('Agenda is empty — at least one item required.');
  }

  if (items && items.length > MAX_AGENDA_ITEMS) {
    errors.push(`Agenda exceeds cap of ${MAX_AGENDA_ITEMS} items (received ${items.length}). Trim or defer lower-priority items.`);
  }

  if (items) {
    items.forEach((item, i) => {
      if (!item.topic || item.topic.trim().length < 3) {
        errors.push(`Item #${i + 1}: Topic too vague or missing.`);
      }
      if (!item.recommendation) {
        errors.push(`Item #${i + 1}: Missing recommendation — every item needs a proposed action.`);
      }
      if (!item.decisionType || !['A', 'B', 'C'].includes(item.decisionType)) {
        errors.push(`Item #${i + 1}: Invalid decision type (must be A, B, or C).`);
      }
    });
  }

  return {
    valid: errors.length === 0,
    errors,
    summary: errors.length === 0
      ? `Agenda approved: ${items.length} item(s), structurally valid.`
      : `Agenda rejected: ${errors.length} issue(s) found.`
  };
}

export function generateOpeningStatement(meetingType: string, itemCount: number): string {
  const time = new Date().toLocaleTimeString('en-US', { timeZone: 'America/Los_Angeles', hour: '2-digit', minute: '2-digit' });
  return `This ${meetingType} meeting is called to order at ${time} PT. We have ${itemCount} agenda item(s) to review.`;
}

export function generateClosingStatement(meetingType: string, decisionsCount: number): string {
  return `The ${meetingType} meeting is adjourned. ${decisionsCount} decision(s) recorded in the governance ledger.`;
}