story-kit: start 59_story_current_work_panel

This commit is contained in:
Dave
2026-02-23 13:23:35 +00:00
parent 765b537dc0
commit 9417ada89d
7 changed files with 440 additions and 23 deletions

View File

@@ -73,7 +73,16 @@ function StatusBadge({ status }: { status: AgentStatusValue }) {
);
}
function RosterBadge({ agent }: { agent: AgentConfigInfo }) {
function RosterBadge({
agent,
activeStoryId,
}: {
agent: AgentConfigInfo;
activeStoryId: string | null;
}) {
const isActive = activeStoryId !== null;
const storyNumber = activeStoryId?.match(/^(\d+)/)?.[1];
return (
<span
style={{
@@ -83,14 +92,56 @@ function RosterBadge({ agent }: { agent: AgentConfigInfo }) {
padding: "2px 8px",
borderRadius: "6px",
fontSize: "0.7em",
background: "#ffffff08",
color: "#888",
border: "1px solid #333",
background: isActive ? "#58a6ff18" : "#ffffff08",
color: isActive ? "#58a6ff" : "#888",
border: isActive ? "1px solid #58a6ff44" : "1px solid #333",
transition: "background 0.3s, color 0.3s, border-color 0.3s",
}}
title={agent.role || agent.name}
title={
isActive
? `Working on #${storyNumber ?? activeStoryId}`
: `${agent.role || agent.name} — idle`
}
>
<span style={{ fontWeight: 600, color: "#aaa" }}>{agent.name}</span>
{agent.model && <span style={{ color: "#666" }}>{agent.model}</span>}
{isActive && (
<span
style={{
width: "5px",
height: "5px",
borderRadius: "50%",
background: "#58a6ff",
animation: "pulse 1.5s infinite",
flexShrink: 0,
}}
/>
)}
{!isActive && (
<span
style={{
width: "5px",
height: "5px",
borderRadius: "50%",
background: "#555",
flexShrink: 0,
}}
/>
)}
<span style={{ fontWeight: 600, color: isActive ? "#58a6ff" : "#aaa" }}>
{agent.name}
</span>
{agent.model && (
<span style={{ color: isActive ? "#7ab8ff" : "#666" }}>
{agent.model}
</span>
)}
{isActive && storyNumber && (
<span style={{ color: "#7ab8ff", marginLeft: "2px" }}>
#{storyNumber}
</span>
)}
{!isActive && (
<span style={{ color: "#444", fontStyle: "italic" }}>idle</span>
)}
</span>
);
}
@@ -519,7 +570,7 @@ export function AgentPanel() {
)}
</div>
{/* Roster badges */}
{/* Roster badges — show all configured agents with idle/active state */}
{roster.length > 0 && (
<div
style={{
@@ -528,9 +579,24 @@ export function AgentPanel() {
gap: "4px",
}}
>
{roster.map((a) => (
<RosterBadge key={`roster-${a.name}`} agent={a} />
))}
{roster.map((a) => {
// Find the story this roster agent is currently working on (if any)
const activeEntry = Object.entries(agents).find(
([, state]) =>
state.agentName === a.name &&
(state.status === "running" || state.status === "pending"),
);
const activeStoryId = activeEntry
? activeEntry[0].split(":")[0]
: null;
return (
<RosterBadge
key={`roster-${a.name}`}
agent={a}
activeStoryId={activeStoryId}
/>
);
})}
</div>
)}