Files
2026-01-30 11:42:20 -08:00

148 lines
3.6 KiB
TypeScript
Executable File

#!/usr/bin/env bun
/**
* Focus Group CLI
*
* Simulate a political focus group with AI personas.
*
* Usage:
* bun cli.ts "healthcare" # Run focus group on healthcare
* bun cli.ts # Interactive mode
* bun cli.ts --status # Show agent status
* bun cli.ts --reset # Reset all agents
*
* The focus group includes:
* - A candidate who presents positions
* - Voters with distinct personas who react
* - An analyst who provides insights
*
* Agents persist across sessions, so they remember previous discussions.
*/
import { parseArgs } from 'node:util';
import {
FocusGroup,
loadState,
resetFocusGroup,
showStatus,
} from './focus-group.js';
async function main() {
const { values, positionals } = parseArgs({
args: process.argv.slice(2),
options: {
status: { type: 'boolean', default: false },
reset: { type: 'boolean', default: false },
help: { type: 'boolean', short: 'h', default: false },
},
allowPositionals: true,
});
if (values.help) {
printHelp();
return;
}
if (values.reset) {
await resetFocusGroup();
return;
}
if (values.status) {
await showStatus();
return;
}
// Load state and create focus group
const state = await loadState();
const focusGroup = new FocusGroup(state);
try {
await focusGroup.initialize();
if (positionals.length > 0) {
// Run on specified topic
const topic = positionals.join(' ');
await focusGroup.runRound(topic);
} else {
// Interactive mode
await interactiveMode(focusGroup);
}
} finally {
focusGroup.close();
}
}
async function interactiveMode(focusGroup: FocusGroup): Promise<void> {
const readline = await import('node:readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const ask = (prompt: string): Promise<string> => {
return new Promise((resolve) => {
rl.question(prompt, (answer) => resolve(answer));
});
};
console.log('\n📊 Focus Group - Interactive Mode');
console.log('Enter topics to test, or "quit" to exit.\n');
while (true) {
const topic = await ask('\x1b[1mTopic:\x1b[0m ');
if (topic.toLowerCase() === 'quit' || topic.toLowerCase() === 'exit') {
break;
}
if (!topic.trim()) continue;
await focusGroup.runRound(topic);
console.log('\n' + '─'.repeat(60) + '\n');
}
rl.close();
}
function printHelp() {
console.log(`
📊 Focus Group Simulator
Test political messaging against AI voter personas.
USAGE:
bun cli.ts [topic] Run focus group on a topic
bun cli.ts Interactive mode
bun cli.ts --status Show agent status
bun cli.ts --reset Reset all agents
bun cli.ts -h, --help Show this help
EXAMPLES:
bun cli.ts "healthcare reform"
bun cli.ts "immigration policy"
bun cli.ts "tax cuts vs government services"
HOW IT WORKS:
1. Candidate presents a position on the topic
2. Voters (Maria & James) react based on their personas
3. Candidate asks a follow-up question
4. Voters respond to the follow-up
5. Analyst provides insights and recommendations
VOTER PERSONAS:
Maria - 34yo Independent from Phoenix, AZ
Nurse, mom of two. Cares about healthcare, education.
James - 58yo moderate Republican from rural Ohio
Former auto worker, small business owner. Skeptical.
PERSISTENCE:
Agents remember previous sessions. Run multiple topics to see
how insights accumulate over time.
`);
}
main().catch(console.error);