storkit: merge 429_story_interactive_project_setup_wizard_for_new_storkit_projects

This commit is contained in:
dave
2026-03-28 13:26:29 +00:00
parent 9feed0f882
commit 0b50c66caa
10 changed files with 1217 additions and 59 deletions
+47
View File
@@ -2,6 +2,7 @@ use crate::http::context::{AppContext, PermissionDecision};
use crate::http::workflow::{PipelineState, load_pipeline_state};
use crate::io::onboarding;
use crate::io::watcher::WatcherEvent;
use crate::io::wizard;
use crate::llm::chat;
use crate::llm::types::Message;
use crate::log_buffer;
@@ -46,6 +47,16 @@ enum WsRequest {
},
}
/// Serialisable summary of a single wizard step for WebSocket broadcast.
#[derive(Serialize, Clone)]
pub struct WizardStepInfo {
pub step: String,
pub label: String,
pub status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
}
#[derive(Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
/// WebSocket response messages sent by the server.
@@ -125,6 +136,13 @@ enum WsResponse {
OnboardingStatus {
needs_onboarding: bool,
},
/// Sent on connect when a setup wizard is active. Contains the full
/// wizard state so the frontend can render the step-by-step UI.
WizardState {
steps: Vec<WizardStepInfo>,
current_step_index: usize,
completed: bool,
},
/// Streaming token from a `/btw` side question response.
SideQuestionToken {
content: String,
@@ -219,6 +237,35 @@ pub async fn ws_handler(ws: WebSocket, ctx: Data<&Arc<AppContext>>) -> impl poem
});
}
// Push wizard state if an active wizard exists.
{
if let Ok(root) = ctx.state.get_project_root()
&& let Some(ws) = wizard::WizardState::load(&root)
{
let steps: Vec<WizardStepInfo> = ws
.steps
.iter()
.map(|s| WizardStepInfo {
step: serde_json::to_value(s.step)
.ok()
.and_then(|v| v.as_str().map(String::from))
.unwrap_or_default(),
label: s.step.label().to_string(),
status: serde_json::to_value(&s.status)
.ok()
.and_then(|v| v.as_str().map(String::from))
.unwrap_or_default(),
content: s.content.clone(),
})
.collect();
let _ = tx.send(WsResponse::WizardState {
steps,
current_step_index: ws.current_step_index(),
completed: ws.completed,
});
}
}
// Push recent server log entries so the client has history on connect.
{
let entries = log_buffer::global().get_recent_entries(100, None, None);