Skip to content

Commit d79f40d

Browse files
committed
feat(plugin): wire feature-flagged Tiny Actor output into terminal surfaces (#1302)
Call render_actor_preview("PLAN") in session-start.py after the buddy greeting. When CODINGBUDDY_TINY_ACTORS=1 the Tiny Actor Grid preview is appended to session-start output; otherwise the block is a silent no-op. Adds test_session_start_actors.py with 9 integration tests covering flag gating, output content, invalid mode handling, and error fallback.
1 parent 2aac5b5 commit d79f40d

2 files changed

Lines changed: 105 additions & 0 deletions

File tree

packages/claude-code-plugin/hooks/session-start.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,16 @@ def main():
888888
if output:
889889
print(output)
890890

891+
# Tiny Actor Grid preview (#1302)
892+
try:
893+
from tiny_actor_preview import render_actor_preview
894+
895+
actor_preview = render_actor_preview("PLAN")
896+
if actor_preview:
897+
print(actor_preview)
898+
except Exception:
899+
pass # Never block session start
900+
891901
# Show update notification if marketplace clone was updated (#1101)
892902
if new_version:
893903
print(
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"""Tests for Tiny Actor Grid preview integration in session-start (#1302)."""
2+
import os
3+
import sys
4+
5+
import pytest
6+
7+
# Ensure hooks/lib is on path
8+
_tests_dir = os.path.dirname(os.path.abspath(__file__))
9+
_lib_dir = os.path.join(os.path.dirname(_tests_dir), "hooks", "lib")
10+
if _lib_dir not in sys.path:
11+
sys.path.insert(0, _lib_dir)
12+
13+
from tiny_actor_preview import is_tiny_actors_enabled, render_actor_preview
14+
15+
16+
# ---------------------------------------------------------------------------
17+
# Integration: session-start calls render_actor_preview
18+
# ---------------------------------------------------------------------------
19+
20+
21+
class TestSessionStartActorPreview:
22+
"""Verify that the session-start integration point behaves correctly."""
23+
24+
def test_preview_off_by_default(self, monkeypatch):
25+
"""When flag is unset, render_actor_preview returns None (no output)."""
26+
monkeypatch.delenv("CODINGBUDDY_TINY_ACTORS", raising=False)
27+
assert render_actor_preview("PLAN") is None
28+
29+
def test_preview_on_when_flag_enabled(self, monkeypatch):
30+
"""When flag is set, render_actor_preview returns non-empty string."""
31+
monkeypatch.setenv("CODINGBUDDY_TINY_ACTORS", "1")
32+
result = render_actor_preview("PLAN")
33+
assert isinstance(result, str)
34+
assert len(result) > 0
35+
36+
def test_plan_mode_is_default_session_start_mode(self, monkeypatch):
37+
"""Session start uses PLAN as the default mode for preview."""
38+
monkeypatch.setenv("CODINGBUDDY_TINY_ACTORS", "1")
39+
result = render_actor_preview("PLAN")
40+
assert result is not None
41+
# Buddy moderator face should appear
42+
assert "\u25d5\u203f\u25d5" in result # ◕‿◕
43+
44+
def test_preview_contains_buddy_and_agents(self, monkeypatch):
45+
"""Preview output includes buddy moderator and specialist labels."""
46+
monkeypatch.setenv("CODINGBUDDY_TINY_ACTORS", "1")
47+
result = render_actor_preview("PLAN")
48+
assert result is not None
49+
# Buddy face
50+
assert "\u25d5" in result
51+
# At least one agent label
52+
assert "Technical" in result or "Security" in result
53+
54+
def test_no_exception_when_flag_off_and_render_called(self, monkeypatch):
55+
"""Calling render_actor_preview with flag off never raises."""
56+
monkeypatch.delenv("CODINGBUDDY_TINY_ACTORS", raising=False)
57+
# Should return None cleanly, matching the try/except pattern in session-start
58+
assert render_actor_preview("PLAN") is None
59+
60+
def test_no_exception_with_invalid_mode(self, monkeypatch):
61+
"""Invalid mode returns None without raising (matches session-start guard)."""
62+
monkeypatch.setenv("CODINGBUDDY_TINY_ACTORS", "1")
63+
result = render_actor_preview("NONEXISTENT_MODE")
64+
assert result is None
65+
66+
67+
class TestSessionStartActorFlagGating:
68+
"""Verify feature flag gating matches session-start try/except pattern."""
69+
70+
def test_flag_disabled_matches_session_start_noop(self, monkeypatch):
71+
"""When disabled, the entire actor preview block is a no-op."""
72+
monkeypatch.delenv("CODINGBUDDY_TINY_ACTORS", raising=False)
73+
assert not is_tiny_actors_enabled()
74+
assert render_actor_preview("PLAN") is None
75+
76+
def test_flag_enabled_produces_output(self, monkeypatch):
77+
"""When enabled, preview produces printable output."""
78+
monkeypatch.setenv("CODINGBUDDY_TINY_ACTORS", "1")
79+
assert is_tiny_actors_enabled()
80+
result = render_actor_preview("PLAN")
81+
assert result is not None
82+
# Output should be printable (no None/errors)
83+
assert isinstance(result, str)
84+
85+
def test_exception_fallback_returns_none(self, monkeypatch):
86+
"""If rendering raises, session-start try/except catches it."""
87+
monkeypatch.setenv("CODINGBUDDY_TINY_ACTORS", "1")
88+
import tiny_actor_preview
89+
90+
def _boom(mode):
91+
raise RuntimeError("simulated failure")
92+
93+
monkeypatch.setattr(tiny_actor_preview, "get_cast_preset", _boom)
94+
# render_actor_preview catches internally, returns None
95+
assert render_actor_preview("PLAN") is None

0 commit comments

Comments
 (0)