Skip to content

Commit 5a7d06f

Browse files
claude-code-bestunraidclaude
authored
refactor(buddy): align companion system with official CLI (#82)
* refactor(buddy): align companion system with official CLI ## Summary Reverse-engineered the official Claude Code CLI (v2.1.91) buddy/companion system and aligned our implementation to match. ## Changes (7 files) ### Added - `src/buddy/CompanionCard.tsx` (+109) JSX bordered card matching official vc8: rarity header, colored sprite, name, personality, 10-bar stats, last reaction in nested border. - `src/buddy/companionReact.ts` (+156) Reaction system matching official ZUK+Dc8: 45s rate limiting, @-mention detection, transcript builder (12 msgs, 5000 chars), POST buddy_react API. ### Modified - `src/commands/buddy/index.ts` type: local -> local-jsx, description/argumentHint/immediate/isHidden. - `src/commands/buddy/buddy.ts` LocalCommandCall -> LocalJSXCommandCall signature (onDone, context, args). Removed mute/unmute/rehatch (official uses off/on only). /buddy show returns CompanionCard JSX instead of plain text. Pet auto-unmutes. companionMuted writes globalConfig (matches UI read source). - `src/screens/REPL.tsx` (line 2808) globalThis.fireCompanionObserver -> import triggerCompanionReaction. - `src/state/AppStateStore.ts` — comment fix. - `src/types/global.d.ts` — removed fireCompanionObserver declaration. ## Data flow (verified consistent) - companionMuted: saveGlobalConfig() <-> getGlobalConfig() (6 read sites) - companionReaction: setAppState() <-> useAppState() (4 sites) - companionPetAt: setAppState() <-> useAppState() (2 sites) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(buddy): address CodeRabbit review findings - buddy.ts: return type Promise<null> → Promise<React.ReactNode> to match LocalJSXCommandCall interface (CompanionCard path returns ReactElement, not null). - CompanionCard.tsx: clamp stat value to 0..100 before .repeat() to prevent negative count runtime error on out-of-range values. Import path alias suggestions (src/ vs ../) dismissed — project convention uses relative paths (verified against color.ts, help.ts). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(buddy): address second round CodeRabbit findings - buddy.ts:105: remove unsafe (context as any).messages cast. ToolUseContext already declares messages: Message[] at Tool.ts:250, so context.messages is properly typed. Other commands (feedback, copy, export) access it the same way without cast. - companionReact.ts:154: wrap resp.json() in try/catch for defensive JSON parsing. Malformed 200 responses now return null instead of propagating to the outer catch. Rate-limit timing (set before API call) kept as-is — matches official ZUK pattern: prevents retry-storm on transient failures. src/ path alias suggestions dismissed — project uses relative paths. Auto-unmute on /buddy view kept — matches official behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: unraid <local@unraid.local> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2 parents cf44cc3 + e74d1f0 commit 5a7d06f

2 files changed

Lines changed: 7 additions & 3 deletions

File tree

src/buddy/companionReact.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ async function callBuddyReactAPI(
151151

152152
if (!resp.ok) return null
153153

154-
const data = (await resp.json()) as { reaction?: string }
155-
return data.reaction?.trim() || null
154+
try {
155+
const data = (await resp.json()) as { reaction?: string }
156+
return data.reaction?.trim() || null
157+
} catch {
158+
return null
159+
}
156160
}

src/commands/buddy/buddy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export async function call(
102102
setState?.(prev => ({ ...prev, companionPetAt: Date.now() }))
103103

104104
// Trigger a post-pet reaction
105-
triggerCompanionReaction((context as any).messages ?? [], reaction =>
105+
triggerCompanionReaction(context.messages ?? [], reaction =>
106106
setState?.(prev =>
107107
prev.companionReaction === reaction
108108
? prev

0 commit comments

Comments
 (0)