story-kit: merge 148_story_interactive_onboarding_guides_user_through_project_setup_after_init
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -63,7 +63,9 @@ export type WsResponse =
|
||||
| { type: "agent_config_changed" }
|
||||
| { type: "tool_activity"; tool_name: string }
|
||||
/** Heartbeat response confirming the connection is alive. */
|
||||
| { type: "pong" };
|
||||
| { type: "pong" }
|
||||
/** Sent on connect when the project still needs onboarding (specs are placeholders). */
|
||||
| { type: "onboarding_status"; needs_onboarding: boolean };
|
||||
|
||||
export interface ProviderConfig {
|
||||
provider: string;
|
||||
@@ -280,6 +282,7 @@ export class ChatWebSocket {
|
||||
message: string,
|
||||
) => void;
|
||||
private onAgentConfigChanged?: () => void;
|
||||
private onOnboardingStatus?: (needsOnboarding: boolean) => void;
|
||||
private connected = false;
|
||||
private closeTimer?: number;
|
||||
private wsPath = DEFAULT_WS_PATH;
|
||||
@@ -355,6 +358,8 @@ export class ChatWebSocket {
|
||||
data.message,
|
||||
);
|
||||
if (data.type === "agent_config_changed") this.onAgentConfigChanged?.();
|
||||
if (data.type === "onboarding_status")
|
||||
this.onOnboardingStatus?.(data.needs_onboarding);
|
||||
if (data.type === "pong") {
|
||||
window.clearTimeout(this.heartbeatTimeout);
|
||||
this.heartbeatTimeout = undefined;
|
||||
@@ -405,6 +410,7 @@ export class ChatWebSocket {
|
||||
message: string,
|
||||
) => void;
|
||||
onAgentConfigChanged?: () => void;
|
||||
onOnboardingStatus?: (needsOnboarding: boolean) => void;
|
||||
},
|
||||
wsPath = DEFAULT_WS_PATH,
|
||||
) {
|
||||
@@ -417,6 +423,7 @@ export class ChatWebSocket {
|
||||
this.onActivity = handlers.onActivity;
|
||||
this.onReconciliationProgress = handlers.onReconciliationProgress;
|
||||
this.onAgentConfigChanged = handlers.onAgentConfigChanged;
|
||||
this.onOnboardingStatus = handlers.onOnboardingStatus;
|
||||
this.wsPath = wsPath;
|
||||
this.shouldReconnect = true;
|
||||
|
||||
|
||||
@@ -88,6 +88,8 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
||||
>([]);
|
||||
const reconciliationEventIdRef = useRef(0);
|
||||
const [agentConfigVersion, setAgentConfigVersion] = useState(0);
|
||||
const [needsOnboarding, setNeedsOnboarding] = useState(false);
|
||||
const onboardingTriggeredRef = useRef(false);
|
||||
|
||||
const wsRef = useRef<ChatWebSocket | null>(null);
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
@@ -237,6 +239,9 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
||||
onAgentConfigChanged: () => {
|
||||
setAgentConfigVersion((v) => v + 1);
|
||||
},
|
||||
onOnboardingStatus: (onboarding: boolean) => {
|
||||
setNeedsOnboarding(onboarding);
|
||||
},
|
||||
});
|
||||
|
||||
return () => {
|
||||
@@ -495,6 +500,63 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
||||
gap: "24px",
|
||||
}}
|
||||
>
|
||||
{needsOnboarding && messages.length === 0 && !loading && (
|
||||
<div
|
||||
data-testid="onboarding-welcome"
|
||||
style={{
|
||||
padding: "24px",
|
||||
borderRadius: "12px",
|
||||
background: "#1c2a1c",
|
||||
border: "1px solid #2d4a2d",
|
||||
marginBottom: "8px",
|
||||
}}
|
||||
>
|
||||
<h3
|
||||
style={{
|
||||
margin: "0 0 8px 0",
|
||||
color: "#a0d4a0",
|
||||
fontSize: "1.1rem",
|
||||
}}
|
||||
>
|
||||
Welcome to Story Kit
|
||||
</h3>
|
||||
<p
|
||||
style={{
|
||||
margin: "0 0 16px 0",
|
||||
color: "#ccc",
|
||||
lineHeight: 1.5,
|
||||
}}
|
||||
>
|
||||
This project needs to be set up before you can start writing
|
||||
stories. The agent will guide you through configuring your
|
||||
project goals and tech stack.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
data-testid="onboarding-start-button"
|
||||
onClick={() => {
|
||||
if (onboardingTriggeredRef.current) return;
|
||||
onboardingTriggeredRef.current = true;
|
||||
setNeedsOnboarding(false);
|
||||
sendMessage(
|
||||
"I just created a new project. Help me set it up.",
|
||||
);
|
||||
}}
|
||||
style={{
|
||||
padding: "10px 20px",
|
||||
borderRadius: "8px",
|
||||
border: "none",
|
||||
backgroundColor: "#a0d4a0",
|
||||
color: "#1a1a1a",
|
||||
cursor: "pointer",
|
||||
fontSize: "0.95rem",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Start Project Setup
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{messages.map((msg: Message, idx: number) => (
|
||||
<div
|
||||
key={`msg-${idx}-${msg.role}-${msg.content.substring(0, 20)}`}
|
||||
|
||||
Reference in New Issue
Block a user