story-kit: merge 117_story_show_startup_reconciliation_progress_in_ui

This commit is contained in:
Dave
2026-02-23 22:50:57 +00:00
parent e3d9813707
commit 85fddcb71a
7 changed files with 341 additions and 8 deletions

View File

@@ -64,6 +64,11 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
const [isNarrowScreen, setIsNarrowScreen] = useState(
window.innerWidth < NARROW_BREAKPOINT,
);
const [reconciliationActive, setReconciliationActive] = useState(false);
const [reconciliationEvents, setReconciliationEvents] = useState<
{ id: string; storyId: string; status: string; message: string }[]
>([]);
const reconciliationEventIdRef = useRef(0);
const wsRef = useRef<ChatWebSocket | null>(null);
const messagesEndRef = useRef<HTMLDivElement>(null);
@@ -197,6 +202,19 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
onActivity: (toolName) => {
setActivityStatus(formatToolActivity(toolName));
},
onReconciliationProgress: (storyId, status, message) => {
if (status === "done") {
setReconciliationActive(false);
} else {
setReconciliationActive(true);
setReconciliationEvents((prev) => {
const id = String(reconciliationEventIdRef.current++);
const next = [...prev, { id, storyId, status, message }];
// Keep only the last 8 events to avoid the banner growing too tall.
return next.slice(-8);
});
}
},
});
return () => {
@@ -679,6 +697,52 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
</div>
</div>
{/* Startup reconciliation progress banner */}
{reconciliationActive && (
<div
data-testid="reconciliation-banner"
style={{
padding: "6px 24px",
background: "#1c2a1c",
borderTop: "1px solid #2d4a2d",
fontSize: "0.8em",
color: "#7ec87e",
maxHeight: "100px",
overflowY: "auto",
flexShrink: 0,
}}
>
<div
style={{
fontWeight: 600,
marginBottom: "2px",
color: "#a0d4a0",
}}
>
Reconciling startup state...
</div>
{reconciliationEvents.map((evt) => (
<div
key={evt.id}
style={{
color:
evt.status === "failed"
? "#d07070"
: evt.status === "advanced"
? "#80c880"
: "#666",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{evt.storyId ? `[${evt.storyId}] ` : ""}
{evt.message}
</div>
))}
</div>
)}
{/* Chat input pinned at bottom of left column */}
<div
style={{