cc-haha/src/buddy/observer.ts
DevinZeng 9233518b11 Enable and fix /buddy command
The /buddy command was completely disabled by bun:bundle feature('BUDDY')
flag which evaluates to false at runtime. Removed all feature('BUDDY')
checks across the codebase to register the command, and added keyboard
event handling (q/Enter to dismiss) which was missing from the UI.
2026-04-03 00:30:56 +08:00

68 lines
2.0 KiB
TypeScript

import type { Message } from '../types/message.js'
import { getCompanion } from './companion.js'
import { getGlobalConfig } from '../utils/config.js'
// Simple companion observer: picks a reaction based on the last assistant message.
// This is a lightweight placeholder that generates fun reactions without an LLM call.
const DEBUGGING_QUIPS = [
'Found it!',
'Interesting...',
'Have you tried rubber duck debugging?',
'Stack trace time!',
'I see what happened.',
]
const GENERAL_QUIPS = [
'Looking good!',
'Keep it up!',
'Nice work!',
'I believe in you!',
'You got this!',
]
const CODE_QUIPS = [
'Fancy!',
'Clean code!',
'Elegant solution!',
'Ship it!',
]
function pickQuip(messages: Message[]): string | undefined {
const lastAssistant = [...messages].reverse().find(m => m.role === 'assistant')
if (!lastAssistant) return undefined
const content = Array.isArray(lastAssistant.content)
? lastAssistant.content.map(c => (typeof c === 'string' ? c : c.type === 'text' ? c.text : '')).join('')
: typeof lastAssistant.content === 'string'
? lastAssistant.content
: ''
if (!content) return undefined
// Only react occasionally (1 in 5 turns)
if (Math.random() > 0.2) return undefined
const lower = content.toLowerCase()
if (lower.includes('error') || lower.includes('bug') || lower.includes('fix') || lower.includes('debug')) {
return DEBUGGING_QUIPS[Math.floor(Math.random() * DEBUGGING_QUIPS.length)]
}
if (lower.includes('function') || lower.includes('class') || lower.includes('const') || lower.includes('```')) {
return CODE_QUIPS[Math.floor(Math.random() * CODE_QUIPS.length)]
}
return GENERAL_QUIPS[Math.floor(Math.random() * GENERAL_QUIPS.length)]
}
export async function fireCompanionObserver(
messages: Message[],
onReaction: (reaction: string) => void,
): Promise<void> {
const companion = getCompanion()
if (!companion || getGlobalConfig().companionMuted) return
const quip = pickQuip(messages)
if (quip) {
onReaction(quip)
}
}