import type { ExtensionAPI, ExtensionContext, } from '@earendil-works/pi-coding-agent'; import { Text } from '@earendil-works/pi-tui'; import { Type } from 'typebox'; import { PERSONA_STATUS_KEY, PERSONA_TOOL_NAME } from './catalog.ts'; import { executePersona, type PersonaToolResult } from './execute.ts'; import { createPersonaGuardState, registerPersonaGuard, resetPersonaRun, } from './guard.ts'; import { personaStatusLabel } from './model.ts'; import { appendPersonaReminder } from './prompt.ts'; export const PERSONA_DESCRIPTION = 'Load the complete Sideroom writing guide before a substantial explanation, findings report, implementation summary, or user-facing documentation; also use when asked for clearer, shorter, or less technical wording. Reuse while in context.'; export const PERSONA_PROMPT_SNIPPET = 'Load the complete writing guide before substantial user-facing prose.'; export default function registerPersona(pi: ExtensionAPI): void { const state = createPersonaGuardState(); const publishStatus = (ctx: ExtensionContext): void => { if (!ctx.hasUI) { return; } ctx.ui.setStatus( PERSONA_STATUS_KEY, personaStatusLabel(state.blocksThisRun, state.steersThisRun), ); }; registerPersonaGuard(pi, state, publishStatus); pi.on('session_start', (_event, ctx) => { resetPersonaRun(state); publishStatus(ctx); }); pi.on('before_agent_start', (event, ctx) => { resetPersonaRun(state); publishStatus(ctx); const systemPrompt = appendPersonaReminder(event.systemPrompt); if (systemPrompt === event.systemPrompt) { return; } return { systemPrompt }; }); pi.registerTool({ name: PERSONA_TOOL_NAME, label: 'Sideroom Persona', description: PERSONA_DESCRIPTION, promptSnippet: PERSONA_PROMPT_SNIPPET, parameters: Type.Object({}), executionMode: 'sequential', execute: async () => executePersona(), renderCall(_args, theme) { return new Text( theme.fg('toolTitle', theme.bold(PERSONA_TOOL_NAME)), 0, 0, ); }, renderResult(result, _options, theme) { const details = result.details as | PersonaToolResult['details'] | undefined; const voices = details?.voiceRules.length ?? 0; const prohibitions = details?.prohibitions.length ?? 0; return new Text( theme.fg( 'success', `${String(voices)} voice rules ยท ${String(prohibitions)} prohibitions`, ), 0, 0, ); }, }); }