- Add docs/PRODUCTION-READINESS.md with journey matrix and defect backlog - Persist onboarding draft in session storage across reload - Localize onboarding discovery main-bot role; German Chief of Staff string - Destroy team sandboxes and home folders when deleting an account - Keep composer/transcript visible during queued runs; extend send watchdog - Add Playwright specs: reload persistence, DE intake, queued progress, console guard Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
import { BotAvatar, GroupAvatar, type GroupAvatarMember } from "@rakazo/ui-web";
|
|
import { useEffect, useMemo, useState } from "react";
|
|
import { isDoingStatus } from "../../lib/agent-activity";
|
|
import { personaWorkingLinesPlain, resolveBotPersona } from "../../lib/bot-persona";
|
|
import { Shimmer } from "./primitives";
|
|
|
|
/** Lightweight peer event shown without exposing the exchanged message body. */
|
|
export function CollaborationMarker({
|
|
ariaLabel,
|
|
color,
|
|
identity,
|
|
label,
|
|
onClick,
|
|
}: {
|
|
ariaLabel: string;
|
|
color: string;
|
|
identity: string;
|
|
label: string;
|
|
onClick: () => void;
|
|
}) {
|
|
return (
|
|
<div className="flex justify-start">
|
|
<button
|
|
type="button"
|
|
data-testid="peer-receipt-chip"
|
|
aria-label={ariaLabel}
|
|
onClick={onClick}
|
|
className="inline-flex max-w-full items-center gap-1.5 rounded-full px-2.5 py-1 text-ui-body-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground/75"
|
|
>
|
|
<BotAvatar color={color} identity={identity} className="size-icon-md" />
|
|
<span dir="auto" className="truncate">
|
|
{label}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function ActiveBotGlyph({
|
|
bots,
|
|
label,
|
|
runStatus,
|
|
}: {
|
|
bots: GroupAvatarMember[];
|
|
label: string;
|
|
runStatus?: string;
|
|
}) {
|
|
const firstBot = bots[0];
|
|
const status = runStatus ?? firstBot?.status;
|
|
const persona = useMemo(
|
|
() =>
|
|
firstBot?.name
|
|
? resolveBotPersona({
|
|
name: firstBot.name,
|
|
title: "",
|
|
description: "",
|
|
})
|
|
: null,
|
|
[firstBot?.name],
|
|
);
|
|
const workingLines = useMemo(() => {
|
|
if (!firstBot?.name || !persona) return [label];
|
|
if (isDoingStatus(status) && status !== "running") return [label];
|
|
return [...personaWorkingLinesPlain(persona.archetype, firstBot.name)];
|
|
}, [firstBot?.name, label, persona, status]);
|
|
const [phraseIndex, setPhraseIndex] = useState(0);
|
|
|
|
useEffect(() => {
|
|
if (workingLines.length <= 1) return;
|
|
const interval = setInterval(() => {
|
|
setPhraseIndex((index) => (index + 1) % workingLines.length);
|
|
}, 3500);
|
|
return () => clearInterval(interval);
|
|
}, [workingLines.length]);
|
|
|
|
const displayLabel = workingLines[phraseIndex] ?? label;
|
|
|
|
return (
|
|
<div className="flex min-h-10 items-center px-1">
|
|
<span role="status" className="flex w-fit items-center gap-3">
|
|
<GroupAvatar members={bots} size={28} />
|
|
<span className="text-ui-body font-medium tracking-tight">
|
|
<Shimmer>{displayLabel}</Shimmer>
|
|
</span>
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|