Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions components/ChatWindow.notices.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ test("renders temporary notices once at the top center of the chat column", () =
/position: "absolute",\s*top: 12,\s*left: 0,\s*right: isMobile \? 0 : CHAT_MINIMAP_WIDTH,[\s\S]*?justifyContent: "center",[\s\S]*?<NoticeShelf notices=\{notices\} floating \/>/,
);
});

test("renders multi-line notices (e.g. /acp status panel) with pre-wrap monospace instead of truncating to one line", () => {
assert.match(source, /const isMultiLine = notice\.message\.includes\("\\n"\);/);
assert.match(source, /whiteSpace: "pre-wrap", fontFamily: "var\(--font-mono\)"/);
});
19 changes: 13 additions & 6 deletions components/ChatWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -961,17 +961,17 @@ function NoticeShelf({ notices, floating = false }: { notices: NoticeItem[]; flo
: notice.type === "success"
? "#10b981"
: "var(--accent)";
const isMultiLine = notice.message.includes("\n");
return (
<div
key={notice.id}
className="notice-shelf-item"
style={{
display: "flex",
alignItems: "center",
alignItems: isMultiLine ? "flex-start" : "center",
gap: 10,
minHeight: 60,
height: 60,
maxHeight: 60,
...(isMultiLine ? { maxHeight: 420 } : { height: 60, maxHeight: 60 }),
marginBottom: index === notices.length - 1 ? 0 : 6,
overflow: "hidden",
borderRadius: 14,
Expand All @@ -983,13 +983,13 @@ function NoticeShelf({ notices, floating = false }: { notices: NoticeItem[]; flo
boxShadow: floating
? "0 1px 2px rgba(15,23,42,0.05), 0 10px 28px -14px rgba(15,23,42,0.24)"
: "0 1px 2px rgba(15,23,42,0.04), 0 8px 24px -12px rgba(15,23,42,0.10)",
fontSize: 18,
fontSize: isMultiLine ? 12 : 18,
lineHeight: 1.45,
transformOrigin: "top center",
animation: notice.exiting
? "notice-shelf-out 0.18s ease-in forwards"
: "notice-shelf-in 0.18s ease-out both",
padding: "0 12px",
padding: isMultiLine ? "12px 14px" : "0 12px",
}}
>
<span
Expand All @@ -999,9 +999,16 @@ function NoticeShelf({ notices, floating = false }: { notices: NoticeItem[]; flo
borderRadius: "50%",
background: color,
flexShrink: 0,
marginTop: isMultiLine ? 7 : 0,
}}
/>
<span style={{ padding: "14px 0", minWidth: 0, maxWidth: "100%", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
<span
style={
isMultiLine
? { padding: 0, minWidth: 0, maxWidth: "100%", whiteSpace: "pre-wrap", fontFamily: "var(--font-mono)", overflowY: "auto" }
: { padding: "14px 0", minWidth: 0, maxWidth: "100%", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }
}
>
{notice.message}
</span>
</div>
Expand Down
5 changes: 4 additions & 1 deletion hooks/useAgentSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export type NoticeItem = {
message: string;
type: NoticeType;
exiting?: boolean;
visibleMs?: number;
};

type NoticeState = {
Expand Down Expand Up @@ -163,6 +164,7 @@ const EVENT_STREAM_READY_TIMEOUT_MS = 60_000;
const EVENT_STREAM_RECONNECT_DELAY_MS = 1_000;
const MAX_NOTICES = 5;
const NOTICE_VISIBLE_MS = 5000;
const MULTI_LINE_NOTICE_VISIBLE_MS = 30000;
const NOTICE_EXIT_ANIMATION_MS = 180;
function createNoticeId(): string {
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
Expand Down Expand Up @@ -743,6 +745,7 @@ export function useAgentSession(opts: UseAgentSessionOptions) {
id: notice.id ?? createNoticeId(),
message,
type: notice.type ?? "info",
visibleMs: message.includes("\n") ? MULTI_LINE_NOTICE_VISIBLE_MS : undefined,
},
});
}, []);
Expand Down Expand Up @@ -1911,7 +1914,7 @@ export function useAgentSession(opts: UseAgentSessionOptions) {
if (!oldest) return;
const t = setTimeout(() => {
dispatchNotice({ type: "mark_oldest_exiting" });
}, NOTICE_VISIBLE_MS);
}, oldest.visibleMs ?? NOTICE_VISIBLE_MS);
return () => clearTimeout(t);
}, [noticeState.visible]);

Expand Down