huskies: merge 1137 story First-run project init flow — walk through config instead of leaving defaults silently

This commit is contained in:
dave
2026-05-18 12:59:11 +00:00
parent f2c13c7d29
commit a7bad217eb
4 changed files with 644 additions and 7 deletions
@@ -217,8 +217,15 @@ pub(in crate::chat::transport::matrix::bot) async fn on_room_message(
// endpoint. Only a small set of gateway-local commands are handled here.
if ctx.is_gateway() {
// Commands that are meaningful on the gateway itself (no project state needed).
const GATEWAY_LOCAL_COMMANDS: &[&str] =
&["help", "ambient", "reset", "switch", "all_status", "new"];
const GATEWAY_LOCAL_COMMANDS: &[&str] = &[
"help",
"ambient",
"reset",
"switch",
"all_status",
"new",
"config",
];
let stripped = crate::chat::util::strip_bot_mention(
&user_message,
@@ -293,6 +300,63 @@ pub(in crate::chat::transport::matrix::bot) async fn on_room_message(
return;
}
// `config <project> <key>=<value>` — override an agent or project setting.
if cmd == "config" {
let response = if let Some(ref store) = ctx.gateway_projects_store {
// Parse: "<project> <key>=<value>"
let mut parts = args.splitn(2, char::is_whitespace);
let project = parts.next().unwrap_or("").trim();
let setting = parts.next().unwrap_or("").trim();
if project.is_empty() || setting.is_empty() {
"Usage: `config <project> <key>=<value>`\n\
Examples:\n\
- `config myapp coder.model=opus`\n\
- `config myapp default_qa=human`"
.to_string()
} else {
match setting.split_once('=') {
None => {
"Usage: setting must be in `key=value` form, e.g. `coder.model=opus`"
.to_string()
}
Some((key, value)) => {
let host_path_opt = {
let projects = store.read().await;
projects.get(project).and_then(|e| e.host_path.clone())
};
match host_path_opt {
None => format!(
"Project `{project}` not found or has no host path configured."
),
Some(path) => {
match super::super::super::new_project::apply_project_config(
std::path::Path::new(&path),
key.trim(),
value.trim(),
) {
Ok(msg) => msg,
Err(e) => format!("Config error: {e}"),
}
}
}
}
}
}
} else {
"Gateway projects store unavailable.".to_string()
};
let html = markdown_to_html(&response);
if let Ok(msg_id) = ctx
.transport
.send_message(&room_id_str, &response, &html)
.await
&& let Ok(event_id) = msg_id.parse()
{
ctx.bot_sent_event_ids.lock().await.insert(event_id);
}
return;
}
// Gateway-local commands and freeform text fall through to normal handling below.
}
@@ -320,6 +384,7 @@ pub(in crate::chat::transport::matrix::bot) async fn on_room_message(
cmd.git_token.as_deref(),
cmd.host_path.as_deref(),
cmd.adopt_path.as_deref(),
cmd.skip_config,
store,
&ctx.services.project_root,
)